@blockcast/mmt-container 0.1.0-main.149f78a4adae
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 +432 -0
- package/dist/.build-stamp +0 -0
- package/dist/__tests__/test-utils.d.ts +71 -0
- package/dist/__tests__/test-utils.d.ts.map +1 -0
- package/dist/align.d.ts +148 -0
- package/dist/align.d.ts.map +1 -0
- package/dist/align.js +88 -0
- package/dist/align.js.map +7 -0
- package/dist/audio-init-parser.d.ts +66 -0
- package/dist/audio-init-parser.d.ts.map +1 -0
- package/dist/audio-init-parser.js +118 -0
- package/dist/audio-init-parser.js.map +7 -0
- package/dist/audio-ring-buffer.d.ts +50 -0
- package/dist/audio-ring-buffer.d.ts.map +1 -0
- package/dist/audio-ring-buffer.js +93 -0
- package/dist/audio-ring-buffer.js.map +7 -0
- package/dist/authored-timing.d.ts +32 -0
- package/dist/authored-timing.d.ts.map +1 -0
- package/dist/authored-timing.js +32 -0
- package/dist/authored-timing.js.map +7 -0
- package/dist/browser-runtime.js +17109 -0
- package/dist/browser-runtime.js.map +7 -0
- package/dist/carp-catalog.d.ts +318 -0
- package/dist/carp-catalog.d.ts.map +1 -0
- package/dist/carp-catalog.js +549 -0
- package/dist/carp-catalog.js.map +7 -0
- package/dist/catalog-fec-params.d.ts +82 -0
- package/dist/catalog-fec-params.d.ts.map +1 -0
- package/dist/catalog-fec-params.js +66 -0
- package/dist/catalog-fec-params.js.map +7 -0
- package/dist/catalog-network-source.d.ts +19 -0
- package/dist/catalog-network-source.d.ts.map +1 -0
- package/dist/catalog-network-source.js +22 -0
- package/dist/catalog-network-source.js.map +7 -0
- package/dist/catalog-validator.d.ts +18 -0
- package/dist/catalog-validator.d.ts.map +1 -0
- package/dist/catalog-validator.js +7747 -0
- package/dist/catalog-validator.js.map +7 -0
- package/dist/cmaf-block-assembler.d.ts +168 -0
- package/dist/cmaf-block-assembler.d.ts.map +1 -0
- package/dist/cmaf-block-assembler.js +1755 -0
- package/dist/cmaf-block-assembler.js.map +7 -0
- package/dist/cmaf-group-batcher.d.ts +38 -0
- package/dist/cmaf-group-batcher.d.ts.map +1 -0
- package/dist/cmaf-group-batcher.js +195 -0
- package/dist/cmaf-group-batcher.js.map +7 -0
- package/dist/cmcd-producer.d.ts +104 -0
- package/dist/cmcd-producer.d.ts.map +1 -0
- package/dist/cmcd-producer.js +207 -0
- package/dist/cmcd-producer.js.map +7 -0
- package/dist/codec-utils.d.ts +235 -0
- package/dist/codec-utils.d.ts.map +1 -0
- package/dist/codec-utils.js +1225 -0
- package/dist/codec-utils.js.map +7 -0
- package/dist/fec-codec.d.ts +32 -0
- package/dist/fec-codec.d.ts.map +1 -0
- package/dist/fec-codec.js +47 -0
- package/dist/fec-codec.js.map +7 -0
- package/dist/fec-manager.d.ts +266 -0
- package/dist/fec-manager.d.ts.map +1 -0
- package/dist/fec-manager.js +1447 -0
- package/dist/fec-manager.js.map +7 -0
- package/dist/fec-starvation-detector.d.ts +59 -0
- package/dist/fec-starvation-detector.d.ts.map +1 -0
- package/dist/fec-starvation-detector.js +75 -0
- package/dist/fec-starvation-detector.js.map +7 -0
- package/dist/fec-worker-setup.d.ts +76 -0
- package/dist/fec-worker-setup.d.ts.map +1 -0
- package/dist/fec-worker-setup.js +603 -0
- package/dist/fec-worker-setup.js.map +7 -0
- package/dist/fmp4-completion.d.ts +30 -0
- package/dist/fmp4-completion.d.ts.map +1 -0
- package/dist/fmp4-completion.js +21 -0
- package/dist/fmp4-completion.js.map +7 -0
- package/dist/fmp4-reader.d.ts +37 -0
- package/dist/fmp4-reader.d.ts.map +1 -0
- package/dist/fmp4-reader.js +100 -0
- package/dist/fmp4-reader.js.map +7 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +330 -0
- package/dist/index.js.map +7 -0
- package/dist/iso-bmff-timing.d.ts +47 -0
- package/dist/iso-bmff-timing.d.ts.map +1 -0
- package/dist/iso-bmff-timing.js +526 -0
- package/dist/iso-bmff-timing.js.map +7 -0
- package/dist/loc.d.ts +68 -0
- package/dist/loc.d.ts.map +1 -0
- package/dist/loc.js +143 -0
- package/dist/loc.js.map +7 -0
- package/dist/manifest-auth-plan.d.ts +30 -0
- package/dist/manifest-auth-plan.d.ts.map +1 -0
- package/dist/manifest-auth-plan.js +1267 -0
- package/dist/manifest-auth-plan.js.map +7 -0
- package/dist/media-router.d.ts +338 -0
- package/dist/media-router.d.ts.map +1 -0
- package/dist/media-router.js +802 -0
- package/dist/media-router.js.map +7 -0
- package/dist/mfu-reassembler.d.ts +264 -0
- package/dist/mfu-reassembler.d.ts.map +1 -0
- package/dist/mfu-reassembler.js +2668 -0
- package/dist/mfu-reassembler.js.map +7 -0
- package/dist/mfu-reassembly-policy.d.ts +24 -0
- package/dist/mfu-reassembly-policy.d.ts.map +1 -0
- package/dist/mfu-reassembly-policy.js +99 -0
- package/dist/mfu-reassembly-policy.js.map +7 -0
- package/dist/mmtp-container-parser.d.ts +304 -0
- package/dist/mmtp-container-parser.d.ts.map +1 -0
- package/dist/mmtp-container-parser.js +5378 -0
- package/dist/mmtp-container-parser.js.map +7 -0
- package/dist/mmtp-container-parser.no-modules.js +7853 -0
- package/dist/mmtp-container-parser.no-modules.js.map +7 -0
- package/dist/mmtp-decode-pipeline.d.ts +96 -0
- package/dist/mmtp-decode-pipeline.d.ts.map +1 -0
- package/dist/mmtp-decode-pipeline.js +5589 -0
- package/dist/mmtp-decode-pipeline.js.map +7 -0
- package/dist/mmtp-router.d.ts +383 -0
- package/dist/mmtp-router.d.ts.map +1 -0
- package/dist/mmtp-router.js +8384 -0
- package/dist/mmtp-router.js.map +7 -0
- package/dist/mmtp-to-cmaf.d.ts +166 -0
- package/dist/mmtp-to-cmaf.d.ts.map +1 -0
- package/dist/mmtp-to-cmaf.js +781 -0
- package/dist/mmtp-to-cmaf.js.map +7 -0
- package/dist/multicast-auth-catalog.d.ts +115 -0
- package/dist/multicast-auth-catalog.d.ts.map +1 -0
- package/dist/multicast-auth-catalog.js +202 -0
- package/dist/multicast-auth-catalog.js.map +7 -0
- package/dist/multicast-input.d.ts +107 -0
- package/dist/multicast-input.d.ts.map +1 -0
- package/dist/multicast-input.js +256 -0
- package/dist/multicast-input.js.map +7 -0
- package/dist/multicast-manager.d.ts +330 -0
- package/dist/multicast-manager.d.ts.map +1 -0
- package/dist/multicast-manager.js +11032 -0
- package/dist/multicast-manager.js.map +7 -0
- package/dist/multicast-transport.d.ts +62 -0
- package/dist/multicast-transport.d.ts.map +1 -0
- package/dist/multicast-transport.js +338 -0
- package/dist/multicast-transport.js.map +7 -0
- package/dist/multicast-unwrap.d.ts +57 -0
- package/dist/multicast-unwrap.d.ts.map +1 -0
- package/dist/multicast-unwrap.js +384 -0
- package/dist/multicast-unwrap.js.map +7 -0
- package/dist/no-modules.d.ts +9 -0
- package/dist/no-modules.d.ts.map +1 -0
- package/dist/no-modules.js +7819 -0
- package/dist/no-modules.js.map +7 -0
- package/dist/phase14-catalog-override.d.ts +126 -0
- package/dist/phase14-catalog-override.d.ts.map +1 -0
- package/dist/phase14-catalog-override.js +155 -0
- package/dist/phase14-catalog-override.js.map +7 -0
- package/dist/repair-fetch.d.ts +58 -0
- package/dist/repair-fetch.d.ts.map +1 -0
- package/dist/repair-fetch.js +117 -0
- package/dist/repair-fetch.js.map +7 -0
- package/dist/sample-combiner.d.ts +182 -0
- package/dist/sample-combiner.d.ts.map +1 -0
- package/dist/sample-combiner.js +571 -0
- package/dist/sample-combiner.js.map +7 -0
- package/dist/signaling.d.ts +29 -0
- package/dist/signaling.d.ts.map +1 -0
- package/dist/signaling.js +232 -0
- package/dist/signaling.js.map +7 -0
- package/dist/source-auth.d.ts +2 -0
- package/dist/source-auth.d.ts.map +1 -0
- package/dist/source-auth.js +1220 -0
- package/dist/source-auth.js.map +7 -0
- package/dist/switching-set-alignment.d.ts +61 -0
- package/dist/switching-set-alignment.d.ts.map +1 -0
- package/dist/switching-set-alignment.js +85 -0
- package/dist/switching-set-alignment.js.map +7 -0
- package/dist/timestamp-codec.d.ts +34 -0
- package/dist/timestamp-codec.d.ts.map +1 -0
- package/dist/timestamp-codec.js +456 -0
- package/dist/timestamp-codec.js.map +7 -0
- package/dist/track-pipeline-setup.d.ts +72 -0
- package/dist/track-pipeline-setup.d.ts.map +1 -0
- package/dist/track-pipeline-setup.js +306 -0
- package/dist/track-pipeline-setup.js.map +7 -0
- package/dist/track-pipeline.d.ts +121 -0
- package/dist/track-pipeline.d.ts.map +1 -0
- package/dist/track-pipeline.js +229 -0
- package/dist/track-pipeline.js.map +7 -0
- package/dist/track-session.d.ts +269 -0
- package/dist/track-session.d.ts.map +1 -0
- package/dist/track-session.js +597 -0
- package/dist/track-session.js.map +7 -0
- package/dist/transport-pool.d.ts +69 -0
- package/dist/transport-pool.d.ts.map +1 -0
- package/dist/transport-pool.js +88 -0
- package/dist/transport-pool.js.map +7 -0
- package/dist/wasm-mfu-reassembler.d.ts +81 -0
- package/dist/wasm-mfu-reassembler.d.ts.map +1 -0
- package/dist/wasm-mfu-reassembler.js +1915 -0
- package/dist/wasm-mfu-reassembler.js.map +7 -0
- package/dist/wasm-mmtp-container-parser.d.ts +10 -0
- package/dist/wasm-mmtp-container-parser.d.ts.map +1 -0
- package/dist/wasm-mmtp-container-parser.js +5635 -0
- package/dist/wasm-mmtp-container-parser.js.map +7 -0
- package/node_modules/@blockcast/fec-worker/README.md +213 -0
- package/node_modules/@blockcast/fec-worker/dist/.build-stamp +0 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.d.ts +80 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.d.ts.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.js +270 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.js.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts +252 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.js +11 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.js.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker.d.ts +14 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker.d.ts.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker.js +565 -0
- package/node_modules/@blockcast/fec-worker/dist/fec-worker.js.map +7 -0
- package/node_modules/@blockcast/fec-worker/dist/index.d.ts +10 -0
- package/node_modules/@blockcast/fec-worker/dist/index.d.ts.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/index.js +8 -0
- package/node_modules/@blockcast/fec-worker/dist/index.js.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.d.ts +20 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.d.ts.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.js +349 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.js.map +7 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.d.ts +104 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.d.ts.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.js +181 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.js.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.d.ts +179 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.d.ts.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.js +47 -0
- package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.js.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/transfer.d.ts +9 -0
- package/node_modules/@blockcast/fec-worker/dist/transfer.d.ts.map +1 -0
- package/node_modules/@blockcast/fec-worker/dist/transfer.js +13 -0
- package/node_modules/@blockcast/fec-worker/dist/transfer.js.map +1 -0
- package/node_modules/@blockcast/fec-worker/package.json +59 -0
- package/node_modules/@blockcast/fec-worker/src/fec-worker-client.ts +309 -0
- package/node_modules/@blockcast/fec-worker/src/fec-worker-types.ts +268 -0
- package/node_modules/@blockcast/fec-worker/src/fec-worker.ts +1048 -0
- package/node_modules/@blockcast/fec-worker/src/index.ts +32 -0
- package/node_modules/@blockcast/fec-worker/src/shred-fec-worker.ts +558 -0
- package/node_modules/@blockcast/fec-worker/src/shred-worker-client.ts +222 -0
- package/node_modules/@blockcast/fec-worker/src/shred-worker-types.ts +194 -0
- package/node_modules/@blockcast/fec-worker/src/transfer.ts +12 -0
- package/node_modules/@blockcast/mmt-alta-parse/README.md +181 -0
- package/node_modules/@blockcast/mmt-alta-parse/dist/.build-stamp +0 -0
- package/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts +57 -0
- package/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-alta-parse/dist/index.js +115 -0
- package/node_modules/@blockcast/mmt-alta-parse/dist/index.js.map +1 -0
- package/node_modules/@blockcast/mmt-alta-parse/package.json +50 -0
- package/node_modules/@blockcast/mmt-alta-parse/src/index.ts +136 -0
- package/node_modules/@blockcast/mmt-base/README.md +120 -0
- package/node_modules/@blockcast/mmt-base/dist/.build-stamp +0 -0
- package/node_modules/@blockcast/mmt-base/dist/index.d.ts +2 -0
- package/node_modules/@blockcast/mmt-base/dist/index.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-base/dist/index.js +2 -0
- package/node_modules/@blockcast/mmt-base/dist/index.js.map +1 -0
- package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +275 -0
- package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-base/dist/mmtp.js +644 -0
- package/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -0
- package/node_modules/@blockcast/mmt-base/package.json +49 -0
- package/node_modules/@blockcast/mmt-base/src/index.ts +1 -0
- package/node_modules/@blockcast/mmt-base/src/mmtp.ts +898 -0
- package/node_modules/@blockcast/mmt-fec/README.md +270 -0
- package/node_modules/@blockcast/mmt-fec/dist/.build-stamp +0 -0
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts +80 -0
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.js +294 -0
- package/node_modules/@blockcast/mmt-fec/dist/block-manager.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/block-processor.d.ts +72 -0
- package/node_modules/@blockcast/mmt-fec/dist/block-processor.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/block-processor.js +192 -0
- package/node_modules/@blockcast/mmt-fec/dist/block-processor.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.d.ts +46 -0
- package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.js +96 -0
- package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.d.ts +33 -0
- package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.js +57 -0
- package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.d.ts +185 -0
- package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.js +273 -0
- package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/index.d.ts +22 -0
- package/node_modules/@blockcast/mmt-fec/dist/index.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/index.js +22 -0
- package/node_modules/@blockcast/mmt-fec/dist/index.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.d.ts +20 -0
- package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.js +28 -0
- package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts +174 -0
- package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/oti.js +256 -0
- package/node_modules/@blockcast/mmt-fec/dist/oti.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.d.ts +41 -0
- package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.js +81 -0
- package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/README.md +181 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/.build-stamp +0 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts +57 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.js +115 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/package.json +50 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/src/index.ts +136 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/README.md +120 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/.build-stamp +0 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.d.ts +2 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.js +2 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +275 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js +644 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/package.json +49 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/index.ts +1 -0
- package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/mmtp.ts +898 -0
- package/node_modules/@blockcast/mmt-fec/package.json +79 -0
- package/node_modules/@blockcast/mmt-fec/src/block-manager.ts +369 -0
- package/node_modules/@blockcast/mmt-fec/src/block-processor.ts +277 -0
- package/node_modules/@blockcast/mmt-fec/src/cmaf-recovery.ts +127 -0
- package/node_modules/@blockcast/mmt-fec/src/cmaf-symbols.ts +68 -0
- package/node_modules/@blockcast/mmt-fec/src/fec-block-mapper.ts +332 -0
- package/node_modules/@blockcast/mmt-fec/src/index.ts +77 -0
- package/node_modules/@blockcast/mmt-fec/src/loc-symbols.ts +34 -0
- package/node_modules/@blockcast/mmt-fec/src/oti.ts +319 -0
- package/node_modules/@blockcast/mmt-fec/src/reorder-buffer.ts +101 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/.build-stamp +0 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.d.ts +28 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.js +128 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.js.map +1 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/index.d.ts +4 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/index.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/index.js +4 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/index.js.map +1 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.d.ts +37 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.js +179 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.js.map +1 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts +90 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts.map +1 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js +462 -0
- package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js.map +1 -0
- package/node_modules/@blockcast/mmt-manifest-verify/package.json +45 -0
- package/node_modules/@blockcast/mmt-manifest-verify/src/admission.ts +171 -0
- package/node_modules/@blockcast/mmt-manifest-verify/src/index.ts +3 -0
- package/node_modules/@blockcast/mmt-manifest-verify/src/source-auth.ts +230 -0
- package/node_modules/@blockcast/mmt-manifest-verify/src/verifier.ts +636 -0
- package/node_modules/@noble/hashes/LICENSE +21 -0
- package/node_modules/@noble/hashes/README.md +521 -0
- package/node_modules/@noble/hashes/_assert.d.ts +17 -0
- package/node_modules/@noble/hashes/_assert.d.ts.map +1 -0
- package/node_modules/@noble/hashes/_assert.js +18 -0
- package/node_modules/@noble/hashes/_assert.js.map +1 -0
- package/node_modules/@noble/hashes/_blake.d.ts +14 -0
- package/node_modules/@noble/hashes/_blake.d.ts.map +1 -0
- package/node_modules/@noble/hashes/_blake.js +50 -0
- package/node_modules/@noble/hashes/_blake.js.map +1 -0
- package/node_modules/@noble/hashes/_md.d.ts +51 -0
- package/node_modules/@noble/hashes/_md.d.ts.map +1 -0
- package/node_modules/@noble/hashes/_md.js +162 -0
- package/node_modules/@noble/hashes/_md.js.map +1 -0
- package/node_modules/@noble/hashes/_u64.d.ts +55 -0
- package/node_modules/@noble/hashes/_u64.d.ts.map +1 -0
- package/node_modules/@noble/hashes/_u64.js +90 -0
- package/node_modules/@noble/hashes/_u64.js.map +1 -0
- package/node_modules/@noble/hashes/argon2.d.ts +32 -0
- package/node_modules/@noble/hashes/argon2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/argon2.js +401 -0
- package/node_modules/@noble/hashes/argon2.js.map +1 -0
- package/node_modules/@noble/hashes/blake1.d.ts +106 -0
- package/node_modules/@noble/hashes/blake1.d.ts.map +1 -0
- package/node_modules/@noble/hashes/blake1.js +459 -0
- package/node_modules/@noble/hashes/blake1.js.map +1 -0
- package/node_modules/@noble/hashes/blake2.d.ts +116 -0
- package/node_modules/@noble/hashes/blake2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/blake2.js +420 -0
- package/node_modules/@noble/hashes/blake2.js.map +1 -0
- package/node_modules/@noble/hashes/blake2b.d.ts +11 -0
- package/node_modules/@noble/hashes/blake2b.d.ts.map +1 -0
- package/node_modules/@noble/hashes/blake2b.js +14 -0
- package/node_modules/@noble/hashes/blake2b.js.map +1 -0
- package/node_modules/@noble/hashes/blake2s.d.ts +20 -0
- package/node_modules/@noble/hashes/blake2s.d.ts.map +1 -0
- package/node_modules/@noble/hashes/blake2s.js +24 -0
- package/node_modules/@noble/hashes/blake2s.js.map +1 -0
- package/node_modules/@noble/hashes/blake3.d.ts +54 -0
- package/node_modules/@noble/hashes/blake3.d.ts.map +1 -0
- package/node_modules/@noble/hashes/blake3.js +255 -0
- package/node_modules/@noble/hashes/blake3.js.map +1 -0
- package/node_modules/@noble/hashes/crypto.d.ts +2 -0
- package/node_modules/@noble/hashes/crypto.d.ts.map +1 -0
- package/node_modules/@noble/hashes/crypto.js +5 -0
- package/node_modules/@noble/hashes/crypto.js.map +1 -0
- package/node_modules/@noble/hashes/cryptoNode.d.ts +2 -0
- package/node_modules/@noble/hashes/cryptoNode.d.ts.map +1 -0
- package/node_modules/@noble/hashes/cryptoNode.js +18 -0
- package/node_modules/@noble/hashes/cryptoNode.js.map +1 -0
- package/node_modules/@noble/hashes/eskdf.d.ts +47 -0
- package/node_modules/@noble/hashes/eskdf.d.ts.map +1 -0
- package/node_modules/@noble/hashes/eskdf.js +166 -0
- package/node_modules/@noble/hashes/eskdf.js.map +1 -0
- package/node_modules/@noble/hashes/esm/_assert.d.ts +17 -0
- package/node_modules/@noble/hashes/esm/_assert.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/_assert.js +15 -0
- package/node_modules/@noble/hashes/esm/_assert.js.map +1 -0
- package/node_modules/@noble/hashes/esm/_blake.d.ts +14 -0
- package/node_modules/@noble/hashes/esm/_blake.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/_blake.js +45 -0
- package/node_modules/@noble/hashes/esm/_blake.js.map +1 -0
- package/node_modules/@noble/hashes/esm/_md.d.ts +51 -0
- package/node_modules/@noble/hashes/esm/_md.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/_md.js +155 -0
- package/node_modules/@noble/hashes/esm/_md.js.map +1 -0
- package/node_modules/@noble/hashes/esm/_u64.d.ts +55 -0
- package/node_modules/@noble/hashes/esm/_u64.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/_u64.js +67 -0
- package/node_modules/@noble/hashes/esm/_u64.js.map +1 -0
- package/node_modules/@noble/hashes/esm/argon2.d.ts +32 -0
- package/node_modules/@noble/hashes/esm/argon2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/argon2.js +392 -0
- package/node_modules/@noble/hashes/esm/argon2.js.map +1 -0
- package/node_modules/@noble/hashes/esm/blake1.d.ts +106 -0
- package/node_modules/@noble/hashes/esm/blake1.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/blake1.js +452 -0
- package/node_modules/@noble/hashes/esm/blake1.js.map +1 -0
- package/node_modules/@noble/hashes/esm/blake2.d.ts +116 -0
- package/node_modules/@noble/hashes/esm/blake2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/blake2.js +413 -0
- package/node_modules/@noble/hashes/esm/blake2.js.map +1 -0
- package/node_modules/@noble/hashes/esm/blake2b.d.ts +11 -0
- package/node_modules/@noble/hashes/esm/blake2b.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/blake2b.js +11 -0
- package/node_modules/@noble/hashes/esm/blake2b.js.map +1 -0
- package/node_modules/@noble/hashes/esm/blake2s.d.ts +20 -0
- package/node_modules/@noble/hashes/esm/blake2s.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/blake2s.js +21 -0
- package/node_modules/@noble/hashes/esm/blake2s.js.map +1 -0
- package/node_modules/@noble/hashes/esm/blake3.d.ts +54 -0
- package/node_modules/@noble/hashes/esm/blake3.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/blake3.js +251 -0
- package/node_modules/@noble/hashes/esm/blake3.js.map +1 -0
- package/node_modules/@noble/hashes/esm/crypto.d.ts +2 -0
- package/node_modules/@noble/hashes/esm/crypto.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/crypto.js +2 -0
- package/node_modules/@noble/hashes/esm/crypto.js.map +1 -0
- package/node_modules/@noble/hashes/esm/cryptoNode.d.ts +2 -0
- package/node_modules/@noble/hashes/esm/cryptoNode.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/cryptoNode.js +15 -0
- package/node_modules/@noble/hashes/esm/cryptoNode.js.map +1 -0
- package/node_modules/@noble/hashes/esm/eskdf.d.ts +47 -0
- package/node_modules/@noble/hashes/esm/eskdf.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/eskdf.js +160 -0
- package/node_modules/@noble/hashes/esm/eskdf.js.map +1 -0
- package/node_modules/@noble/hashes/esm/hkdf.d.ts +36 -0
- package/node_modules/@noble/hashes/esm/hkdf.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/hkdf.js +82 -0
- package/node_modules/@noble/hashes/esm/hkdf.js.map +1 -0
- package/node_modules/@noble/hashes/esm/hmac.d.ts +35 -0
- package/node_modules/@noble/hashes/esm/hmac.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/hmac.js +86 -0
- package/node_modules/@noble/hashes/esm/hmac.js.map +1 -0
- package/node_modules/@noble/hashes/esm/index.d.ts +2 -0
- package/node_modules/@noble/hashes/esm/index.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/index.js +33 -0
- package/node_modules/@noble/hashes/esm/index.js.map +1 -0
- package/node_modules/@noble/hashes/esm/legacy.d.ts +71 -0
- package/node_modules/@noble/hashes/esm/legacy.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/legacy.js +281 -0
- package/node_modules/@noble/hashes/esm/legacy.js.map +1 -0
- package/node_modules/@noble/hashes/esm/package.json +10 -0
- package/node_modules/@noble/hashes/esm/pbkdf2.d.ts +23 -0
- package/node_modules/@noble/hashes/esm/pbkdf2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/pbkdf2.js +97 -0
- package/node_modules/@noble/hashes/esm/pbkdf2.js.map +1 -0
- package/node_modules/@noble/hashes/esm/ripemd160.d.ts +13 -0
- package/node_modules/@noble/hashes/esm/ripemd160.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/ripemd160.js +13 -0
- package/node_modules/@noble/hashes/esm/ripemd160.js.map +1 -0
- package/node_modules/@noble/hashes/esm/scrypt.d.ts +34 -0
- package/node_modules/@noble/hashes/esm/scrypt.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/scrypt.js +228 -0
- package/node_modules/@noble/hashes/esm/scrypt.js.map +1 -0
- package/node_modules/@noble/hashes/esm/sha1.d.ts +11 -0
- package/node_modules/@noble/hashes/esm/sha1.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/sha1.js +11 -0
- package/node_modules/@noble/hashes/esm/sha1.js.map +1 -0
- package/node_modules/@noble/hashes/esm/sha2.d.ts +159 -0
- package/node_modules/@noble/hashes/esm/sha2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/sha2.js +375 -0
- package/node_modules/@noble/hashes/esm/sha2.js.map +1 -0
- package/node_modules/@noble/hashes/esm/sha256.d.ts +20 -0
- package/node_modules/@noble/hashes/esm/sha256.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/sha256.js +20 -0
- package/node_modules/@noble/hashes/esm/sha256.js.map +1 -0
- package/node_modules/@noble/hashes/esm/sha3-addons.d.ts +142 -0
- package/node_modules/@noble/hashes/esm/sha3-addons.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/sha3-addons.js +393 -0
- package/node_modules/@noble/hashes/esm/sha3-addons.js.map +1 -0
- package/node_modules/@noble/hashes/esm/sha3.d.ts +53 -0
- package/node_modules/@noble/hashes/esm/sha3.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/sha3.js +234 -0
- package/node_modules/@noble/hashes/esm/sha3.js.map +1 -0
- package/node_modules/@noble/hashes/esm/sha512.d.ts +26 -0
- package/node_modules/@noble/hashes/esm/sha512.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/sha512.js +26 -0
- package/node_modules/@noble/hashes/esm/sha512.js.map +1 -0
- package/node_modules/@noble/hashes/esm/utils.d.ts +161 -0
- package/node_modules/@noble/hashes/esm/utils.d.ts.map +1 -0
- package/node_modules/@noble/hashes/esm/utils.js +281 -0
- package/node_modules/@noble/hashes/esm/utils.js.map +1 -0
- package/node_modules/@noble/hashes/hkdf.d.ts +36 -0
- package/node_modules/@noble/hashes/hkdf.d.ts.map +1 -0
- package/node_modules/@noble/hashes/hkdf.js +88 -0
- package/node_modules/@noble/hashes/hkdf.js.map +1 -0
- package/node_modules/@noble/hashes/hmac.d.ts +35 -0
- package/node_modules/@noble/hashes/hmac.d.ts.map +1 -0
- package/node_modules/@noble/hashes/hmac.js +91 -0
- package/node_modules/@noble/hashes/hmac.js.map +1 -0
- package/node_modules/@noble/hashes/index.d.ts +1 -0
- package/node_modules/@noble/hashes/index.d.ts.map +1 -0
- package/node_modules/@noble/hashes/index.js +33 -0
- package/node_modules/@noble/hashes/index.js.map +1 -0
- package/node_modules/@noble/hashes/legacy.d.ts +71 -0
- package/node_modules/@noble/hashes/legacy.d.ts.map +1 -0
- package/node_modules/@noble/hashes/legacy.js +287 -0
- package/node_modules/@noble/hashes/legacy.js.map +1 -0
- package/node_modules/@noble/hashes/package.json +266 -0
- package/node_modules/@noble/hashes/pbkdf2.d.ts +23 -0
- package/node_modules/@noble/hashes/pbkdf2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/pbkdf2.js +101 -0
- package/node_modules/@noble/hashes/pbkdf2.js.map +1 -0
- package/node_modules/@noble/hashes/ripemd160.d.ts +13 -0
- package/node_modules/@noble/hashes/ripemd160.d.ts.map +1 -0
- package/node_modules/@noble/hashes/ripemd160.js +16 -0
- package/node_modules/@noble/hashes/ripemd160.js.map +1 -0
- package/node_modules/@noble/hashes/scrypt.d.ts +34 -0
- package/node_modules/@noble/hashes/scrypt.d.ts.map +1 -0
- package/node_modules/@noble/hashes/scrypt.js +232 -0
- package/node_modules/@noble/hashes/scrypt.js.map +1 -0
- package/node_modules/@noble/hashes/sha1.d.ts +11 -0
- package/node_modules/@noble/hashes/sha1.d.ts.map +1 -0
- package/node_modules/@noble/hashes/sha1.js +14 -0
- package/node_modules/@noble/hashes/sha1.js.map +1 -0
- package/node_modules/@noble/hashes/sha2.d.ts +159 -0
- package/node_modules/@noble/hashes/sha2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/sha2.js +384 -0
- package/node_modules/@noble/hashes/sha2.js.map +1 -0
- package/node_modules/@noble/hashes/sha256.d.ts +20 -0
- package/node_modules/@noble/hashes/sha256.d.ts.map +1 -0
- package/node_modules/@noble/hashes/sha256.js +23 -0
- package/node_modules/@noble/hashes/sha256.js.map +1 -0
- package/node_modules/@noble/hashes/sha3-addons.d.ts +142 -0
- package/node_modules/@noble/hashes/sha3-addons.d.ts.map +1 -0
- package/node_modules/@noble/hashes/sha3-addons.js +402 -0
- package/node_modules/@noble/hashes/sha3-addons.js.map +1 -0
- package/node_modules/@noble/hashes/sha3.d.ts +53 -0
- package/node_modules/@noble/hashes/sha3.d.ts.map +1 -0
- package/node_modules/@noble/hashes/sha3.js +239 -0
- package/node_modules/@noble/hashes/sha3.js.map +1 -0
- package/node_modules/@noble/hashes/sha512.d.ts +26 -0
- package/node_modules/@noble/hashes/sha512.d.ts.map +1 -0
- package/node_modules/@noble/hashes/sha512.js +29 -0
- package/node_modules/@noble/hashes/sha512.js.map +1 -0
- package/node_modules/@noble/hashes/src/_assert.ts +22 -0
- package/node_modules/@noble/hashes/src/_blake.ts +50 -0
- package/node_modules/@noble/hashes/src/_md.ts +176 -0
- package/node_modules/@noble/hashes/src/_u64.ts +91 -0
- package/node_modules/@noble/hashes/src/argon2.ts +497 -0
- package/node_modules/@noble/hashes/src/blake1.ts +534 -0
- package/node_modules/@noble/hashes/src/blake2.ts +486 -0
- package/node_modules/@noble/hashes/src/blake2b.ts +10 -0
- package/node_modules/@noble/hashes/src/blake2s.ts +20 -0
- package/node_modules/@noble/hashes/src/blake3.ts +272 -0
- package/node_modules/@noble/hashes/src/crypto.ts +9 -0
- package/node_modules/@noble/hashes/src/cryptoNode.ts +15 -0
- package/node_modules/@noble/hashes/src/eskdf.ts +187 -0
- package/node_modules/@noble/hashes/src/hkdf.ts +88 -0
- package/node_modules/@noble/hashes/src/hmac.ts +94 -0
- package/node_modules/@noble/hashes/src/index.ts +31 -0
- package/node_modules/@noble/hashes/src/legacy.ts +293 -0
- package/node_modules/@noble/hashes/src/pbkdf2.ts +122 -0
- package/node_modules/@noble/hashes/src/ripemd160.ts +12 -0
- package/node_modules/@noble/hashes/src/scrypt.ts +257 -0
- package/node_modules/@noble/hashes/src/sha1.ts +10 -0
- package/node_modules/@noble/hashes/src/sha2.ts +402 -0
- package/node_modules/@noble/hashes/src/sha256.ts +24 -0
- package/node_modules/@noble/hashes/src/sha3-addons.ts +499 -0
- package/node_modules/@noble/hashes/src/sha3.ts +258 -0
- package/node_modules/@noble/hashes/src/sha512.ts +34 -0
- package/node_modules/@noble/hashes/src/utils.ts +395 -0
- package/node_modules/@noble/hashes/utils.d.ts +161 -0
- package/node_modules/@noble/hashes/utils.d.ts.map +1 -0
- package/node_modules/@noble/hashes/utils.js +313 -0
- package/node_modules/@noble/hashes/utils.js.map +1 -0
- package/package.json +203 -0
- package/schemas/catalog.schema.json +283 -0
- package/src/align.ts +235 -0
- package/src/audio-init-parser.ts +189 -0
- package/src/audio-ring-buffer.ts +120 -0
- package/src/authored-timing.ts +63 -0
- package/src/carp-catalog.ts +776 -0
- package/src/catalog-fec-params.ts +167 -0
- package/src/catalog-network-source.ts +49 -0
- package/src/catalog-validator.ts +34 -0
- package/src/cmaf-block-assembler.ts +1058 -0
- package/src/cmaf-group-batcher.ts +104 -0
- package/src/cmcd-producer.ts +329 -0
- package/src/codec-utils.ts +1539 -0
- package/src/fec-codec.ts +61 -0
- package/src/fec-manager.ts +1939 -0
- package/src/fec-starvation-detector.ts +128 -0
- package/src/fec-worker-setup.ts +177 -0
- package/src/fmp4-completion.ts +47 -0
- package/src/fmp4-reader.ts +112 -0
- package/src/index.ts +443 -0
- package/src/iso-bmff-timing.ts +688 -0
- package/src/loc.ts +181 -0
- package/src/manifest-auth-plan.ts +107 -0
- package/src/media-router.ts +1185 -0
- package/src/mfu-reassembler.ts +2842 -0
- package/src/mfu-reassembly-policy.ts +134 -0
- package/src/mmtp-container-parser.ts +1498 -0
- package/src/mmtp-decode-pipeline.ts +315 -0
- package/src/mmtp-router.ts +3027 -0
- package/src/mmtp-to-cmaf.ts +956 -0
- package/src/multicast-auth-catalog.ts +340 -0
- package/src/multicast-input.ts +439 -0
- package/src/multicast-manager.ts +1503 -0
- package/src/multicast-transport.ts +320 -0
- package/src/multicast-unwrap.ts +132 -0
- package/src/no-modules.ts +20 -0
- package/src/phase14-catalog-override.ts +336 -0
- package/src/repair-fetch.ts +217 -0
- package/src/sample-combiner.ts +846 -0
- package/src/signaling.ts +78 -0
- package/src/source-auth.ts +1 -0
- package/src/switching-set-alignment.ts +109 -0
- package/src/timestamp-codec.ts +265 -0
- package/src/track-pipeline-setup.ts +189 -0
- package/src/track-pipeline.ts +332 -0
- package/src/track-session.ts +778 -0
- package/src/transport-pool.ts +128 -0
- package/src/wasm-mfu-reassembler.ts +372 -0
- package/src/wasm-mmtp-container-parser.ts +23 -0
- package/test-vectors/align.json +199 -0
- package/test-vectors/catalog/README.md +25 -0
- package/test-vectors/catalog/negative/legacy-selection-params.json +15 -0
- package/test-vectors/catalog/negative/missing-mmtp-fields.json +12 -0
- package/test-vectors/catalog/negative/multicast-auth-padded-key.json +37 -0
- package/test-vectors/catalog/negative/multicast-auth-reused-track-format.json +53 -0
- package/test-vectors/catalog/negative/multicast-auth-trailing-pad-bits.json +37 -0
- package/test-vectors/catalog/negative/multicast-endpoint-missing-protocol-and-source.json +24 -0
- package/test-vectors/catalog/negative/network-source-object.json +25 -0
- package/test-vectors/catalog/negative/raptorq-unaligned-symbol.json +26 -0
- package/test-vectors/catalog/negative/repair-track-legacy-shape.json +18 -0
- package/test-vectors/catalog/negative/track-role-empty.json +16 -0
- package/test-vectors/catalog/negative/track-role-non-string.json +16 -0
- package/test-vectors/catalog/positive/fec-multicast.json +51 -0
- package/test-vectors/catalog/positive/flat-av.json +30 -0
- package/test-vectors/catalog/positive/multicast-auth-rotation.json +55 -0
- package/test-vectors/catalog/positive/ticks-and-mixed-timescales.json +39 -0
- package/test-vectors/catalog/positive/track-role.json +49 -0
- package/test-vectors/catalog/releases/moqcast-native-v16-v1/catalog.json +65 -0
- package/test-vectors/catalog/releases/moqcast-native-v16-v1.archive.sha256 +1 -0
- package/test-vectors/catalog-multicast-auth-v1.json +26 -0
- package/test-vectors/catalog-validation.json +148 -0
- package/test-vectors/catalog-validator-public-api.mjs +25 -0
- package/test-vectors/generate-source-auth-fixture.mjs +114 -0
- package/test-vectors/source-auth-v1.json +61 -0
- package/test-vectors/subsample-placement-v1.json +230 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/no-modules.ts", "../../mmt-alta-parse/src/index.ts", "../../mmt-base/src/mmtp.ts", "../src/mfu-reassembler.ts", "../src/sample-combiner.ts", "../src/codec-utils.ts", "../src/mfu-reassembly-policy.ts", "../src/iso-bmff-timing.ts", "../src/mmtp-container-parser.ts", "../src/wasm-mfu-reassembler.ts", "../src/wasm-mmtp-container-parser.ts", "../src/multicast-auth-catalog.ts", "../src/carp-catalog.ts", "../../fec/src/oti.ts", "../src/mmtp-to-cmaf.ts", "../../mmt-manifest-verify/node_modules/@noble/hashes/src/utils.ts", "../../mmt-manifest-verify/node_modules/@noble/hashes/src/_md.ts", "../../mmt-manifest-verify/node_modules/@noble/hashes/src/_u64.ts", "../../mmt-manifest-verify/node_modules/@noble/hashes/src/_blake.ts", "../../mmt-manifest-verify/node_modules/@noble/hashes/src/blake2.ts", "../../mmt-manifest-verify/node_modules/@noble/hashes/src/blake3.ts", "../../mmt-manifest-verify/src/source-auth.ts", "../../mmt-manifest-verify/src/verifier.ts", "../src/manifest-auth-plan.ts"],
|
|
4
|
+
"sourcesContent": ["export { MmtpContainerParser } from './mmtp-container-parser.js'\nexport { createWasmMmtpContainerParser } from './wasm-mmtp-container-parser.js'\nexport {\n datagramMfuReassembly,\n reliableMoqMfuReassembly,\n mmtpFrameReorderWindowFrames,\n} from './mfu-reassembly-policy.js'\nexport {\n validateCmsfMmtpCatalog,\n CmsfCatalogValidationError,\n resolveGroupDurationMs,\n} from './carp-catalog.js'\nexport { catalogFecInterleaveMs, computeFecTimeout } from '@blockcast/mmt-fec'\nexport { MmtpToCmaf } from './mmtp-to-cmaf.js'\nexport { createManifestAuthPlan } from './manifest-auth-plan.js'\nexport {\n ManifestVerifier,\n createWebCryptoEd25519Verifier,\n manifestBindingId,\n} from '@blockcast/mmt-manifest-verify'\n", "/**\n * Zero-dependency helper for extracting the detached ALTA authenticator trailer\n * from an MMTP source packet.\n *\n * Lives in its own leaf package so both `@blockcast/mmt-container` (wire-path\n * parsing) and `@blockcast/fec-worker` (FEC-recovered-source parsing) can share\n * one implementation without creating a package cycle between them.\n *\n * Spec: ISO/IEC 23008-1:2023 + draft-ramadan-moq-mmt \u00A712 (detached trailer, Path 2).\n */\n\n// --- Private MMTP/MPU/MFU constants (ISO/IEC 23008-1 \u00A79.2.2\u20139.2.3) ---\n// Duplicated here as immutable spec values so this package stays a leaf with\n// zero `@blockcast/*` dependencies. Re-deriving from `mmt-container` would\n// reintroduce the package cycle this split exists to avoid.\n\nconst MMTP_HEADER_SIZE = 12\nconst MPU_HEADER_SIZE = 8\nconst MPU_LENGTH_FIELD_SIZE = 2\nconst MPU_HEADER_REMAINDER_SIZE = MPU_HEADER_SIZE - MPU_LENGTH_FIELD_SIZE\nconst TIMED_MFU_DU_HEADER_SIZE = 14\nconst NONTIMED_MFU_DU_HEADER_SIZE = 4\nconst PACKET_TYPE_MPU = 0x00\n\n// --- Public ALTA trailer constants ---\n\n/**\n * MMTP header-extension ext_type assigned to the detached ALTA authenticator\n * trailer (Path 2 / 08-07). Carried in an `[ext_type][ext_length][auth]`\n * block appended after the MPU's declared payload bytes, before the 4-byte\n * Source FEC Payload ID. MMTP X-bit stays 0 \u2014 non-ALTA MMTP receivers treat\n * the trailer as bytes past `payload_length` and skip it (per ISO 23008-1\n * \u00A79.2.2 \"may be discarded without impacting correct processing\").\n */\nexport const MMTP_EXT_TYPE_ALTA_AUTH = 0xf0a1\n\n/** Fixed size of the trailer's `[ext_type][ext_length]` prefix (2 + 2 BE). */\nexport const MMTP_EXT_TRAILER_HEADER_SIZE = 4\n\n/** Result of extracting the detached ALTA authenticator from an MMTP packet. */\nexport interface AltaTrailer {\n /** Authenticator bytes (no ext_type/ext_length prefix, no trailing padding). */\n auth: Uint8Array\n /**\n * Wire-packet byte offset where the signed payload ends, i.e. where the\n * trailer begins. Caller uses this to produce\n * `payload = wirePacket.subarray(0, signedEnd)` for verify_detached.\n */\n signedEnd: number\n}\n\n/**\n * Extract the detached ALTA authenticator trailer from an MMTP source packet.\n *\n * Wire layout:\n * `[MMTP hdr][length(2)][remaining MPU hdr(6)][DU?][media][TRAILER][SS_ID?]`\n * `payload_length = 6 + DU bytes + media bytes`\n *\n * Returns `null` when:\n * - the packet is too small / malformed,\n * - `payload_length` cannot contain the remaining six MPU-header bytes,\n * - the declared payload overruns the packet,\n * - no bytes remain between `payload_length` and the SS_ID,\n * - the trailer's `ext_type` isn't {@link MMTP_EXT_TYPE_ALTA_AUTH},\n * - the declared `ext_length` would extend past the SS_ID boundary.\n *\n * Non-MPU packets (repair, signaling) always return `null`.\n *\n * @param options.skipFecId When true, do NOT reserve 4 trailing bytes for the\n * Source FEC Payload ID. Use on FEC-recovered symbols where the PID has\n * already been stripped upstream.\n */\nexport function extractAltaTrailer(\n mmtpPacket: Uint8Array,\n options?: { skipFecId?: boolean },\n): AltaTrailer | null {\n if (mmtpPacket.length < MMTP_HEADER_SIZE + MPU_HEADER_SIZE) return null\n // ISO/IEC 23008-1:2023 Figure 8 places V=0 packet_type in the low six bits.\n const packetType = mmtpPacket[1]! & 0x3f\n if (packetType !== PACKET_TYPE_MPU) return null\n\n const fecType = (mmtpPacket[0]! >> 3) & 0x03\n let headerLength = MMTP_HEADER_SIZE\n if (fecType < 2 && (mmtpPacket[0]! & 0x20) !== 0) headerLength += 4\n if (fecType < 2 && (mmtpPacket[0]! & 0x02) !== 0) {\n if (headerLength + 4 > mmtpPacket.length) return null\n const extensionLength = new DataView(\n mmtpPacket.buffer,\n mmtpPacket.byteOffset + headerLength + 2,\n 2,\n ).getUint16(0, false)\n headerLength += 4 + extensionLength\n }\n if (headerLength + MPU_HEADER_SIZE > mmtpPacket.length) return null\n\n const payload = mmtpPacket.subarray(headerLength)\n\n // Inline a minimal MPU-header read \u2014 only the fields extractAltaTrailer needs.\n // payloadLength: 16 BE at bytes 0-1.\n // Byte 2 packs FT(4) | T(1) | FI(2) | A(1).\n const payloadLength = (payload[0]! << 8) | payload[1]!\n const flagsByte = payload[2]!\n const fragmentType = (flagsByte >> 4) & 0x0f\n const timed = ((flagsByte >> 3) & 0x01) === 1\n const fragmentationIndicator = (flagsByte >> 1) & 0x03\n\n // Only MFU packets (FT=2) carry the detached trailer.\n if (fragmentType !== 2) return null\n\n // FI=0/1 structurally carries a DU header; FI=2/3 does not. Require at\n // least one media byte after that deterministic layout so the bytes at the\n // declared boundary cannot impersonate ALTA for a header-only fragment.\n const dataUnitHeaderSize = fragmentationIndicator <= 1\n ? (timed ? TIMED_MFU_DU_HEADER_SIZE : NONTIMED_MFU_DU_HEADER_SIZE)\n : 0\n if (payloadLength <= MPU_HEADER_REMAINDER_SIZE + dataUnitHeaderSize) return null\n\n if (fecType > 1) return null\n const hasFecId = !options?.skipFecId && fecType === 1\n const payloadEnd = hasFecId ? payload.length - 4 : payload.length\n const declaredEnd = MPU_LENGTH_FIELD_SIZE + payloadLength\n if (declaredEnd > payloadEnd) return null\n\n if (declaredEnd + MMTP_EXT_TRAILER_HEADER_SIZE > payloadEnd) return null\n const extType = (payload[declaredEnd]! << 8) | payload[declaredEnd + 1]!\n if (extType !== MMTP_EXT_TYPE_ALTA_AUTH) return null\n const extLen = (payload[declaredEnd + 2]! << 8) | payload[declaredEnd + 3]!\n\n const authStart = declaredEnd + MMTP_EXT_TRAILER_HEADER_SIZE\n if (authStart + extLen !== payloadEnd) return null\n\n return {\n auth: payload.subarray(authStart, payloadEnd),\n signedEnd: headerLength + declaredEnd,\n }\n}\n", "import {\n MMTP_EXT_TYPE_ALTA_AUTH as _LEAF_MMTP_EXT_TYPE_ALTA_AUTH,\n MMTP_EXT_TRAILER_HEADER_SIZE as _LEAF_MMTP_EXT_TRAILER_HEADER_SIZE,\n extractAltaTrailer as _leafExtractAltaTrailer,\n type AltaTrailer as _LeafAltaTrailer,\n} from '@blockcast/mmt-alta-parse'\n\n/**\n * @mmt/container - MMTP Parser\n *\n * MMTP (MMT Protocol) packet parser based on ISO/IEC 23008-1:2023 Section 9.2\n *\n * MMTP header format (12 bytes):\n * - Byte 0: V(2) | C(1) | FEC_type(2) | r(1) | X(1) | R(1)\n * - Byte 1: reserved(2) | packet_type(6)\n * - Bytes 2-3: packet_id (big-endian)\n * - Bytes 4-7: timestamp (big-endian, 32-bit)\n * - Bytes 8-11: sequence_number (big-endian)\n *\n * FEC_type values:\n * - 0: No FEC / source packet\n * - 1: FEC mode 0 (source with FEC payload ID)\n * - 2: FEC repair packet mode 0\n * - 3: FEC repair packet mode 1\n *\n * @packageDocumentation\n */\n\nexport interface MMTPHeader {\n version: number\n /** Packet type: 0x00=MPU, 0x02=Signaling, 0x03=Repair */\n packetType: number\n packetId: number\n timestamp: bigint\n sequenceNumber: number\n payloadLength: number\n fecType: number\n /** C flag: header carries a 32-bit packet_counter. */\n packetCounterFlag: boolean\n packetCounter?: number\n /** X flag: header carries an extension header and value. */\n extensionFlag: boolean\n extension?: { type: number; data: Uint8Array }\n /** Byte offset at which the MMTP payload begins. */\n headerLength: number\n /** Random Access Point flag - indicates keyframe (ISO 23008-1, byte 0 bit 0) */\n rapFlag: boolean\n}\n\nexport interface MPUHeader {\n mpuSequenceNumber: number\n fragmentationIndicator: number // FI: 0=complete, 1=first, 2=middle, 3=last\n /** 8-bit MPU fragment_counter from byte 3. */\n fragmentCounter: number\n /** T flag: 1=timed media (14-byte MFU DU header), 0=non-timed (4-byte header) */\n timedFlag: number\n /** A flag: aggregated MPU payload. This strict profile requires A=0. */\n aggregationFlag: boolean\n /** MPU payload_length (bytes 0-1): bytes after the length field, including\n * the remaining six MPU-header bytes and all data-unit bytes. */\n payloadLength: number\n}\n\nexport interface MFUDuHeader {\n movieFragmentSequenceNumber: number\n sampleNumber: number\n offset: number\n priority: number\n dependencyCounter: number\n}\n\nexport interface MMTPPacket {\n header: MMTPHeader\n payload: Uint8Array\n}\n\nexport const MMTP_HEADER_SIZE = 12\nexport const MPU_HEADER_SIZE = 8\nexport const MFU_DU_HEADER_SIZE_TIMED = 14 // T=1: timed media (video/audio samples)\nexport const MFU_DU_HEADER_SIZE_NONTIMED = 4 // T=0: non-timed media (item_id only)\n\nconst MPU_LENGTH_FIELD_SIZE = 2\nconst MPU_HEADER_REMAINDER_SIZE = MPU_HEADER_SIZE - MPU_LENGTH_FIELD_SIZE\nconst SOURCE_FEC_PAYLOAD_ID_SIZE = 4\n\n// MMTP Packet Types (ISO/IEC 23008-1:2023 Section 9.2.2)\nexport const PACKET_TYPE_MPU = 0x00\nexport const PACKET_TYPE_SIGNALING = 0x02\nexport const PACKET_TYPE_REPAIR = 0x03\n\n// AL-FEC Signaling Message ID (ISO/IEC 23008-1:2023 Amendment 1:2025)\nexport const ALFEC_MESSAGE_ID = 0x0203\n\n// FEC Code IDs\nexport const FEC_CODE_XOR = 1\nexport const FEC_CODE_RAPTORQ = 2\n\n/**\n * Parse MMTP header from buffer\n */\nexport function parseMMTPHeader(buffer: Uint8Array): MMTPHeader {\n if (buffer.length < MMTP_HEADER_SIZE) {\n throw new Error(`MMTP packet too small: ${buffer.length} bytes`)\n }\n\n const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)\n\n const version = (buffer[0]! >> 6) & 0x03\n if (version !== 0) {\n throw new Error(`Unsupported MMTP version: ${version}`)\n }\n\n // Extract FEC type from byte 0, bits 3-4\n const fecType = (buffer[0]! >> 3) & 0x03\n const packetCounterFlag = (buffer[0]! & 0x20) !== 0\n const extensionFlag = (buffer[0]! & 0x02) !== 0\n\n // Extract RAP flag from byte 0, bit 0 (R bit - Random Access Point)\n const rapFlag = (buffer[0]! & 0x01) === 1\n\n // ISO/IEC 23008-1:2023 Figure 8 (V=0) places reserved(2) before\n // packet_type(6), so packet_type occupies the low six bits of byte 1.\n const packetType = buffer[1]! & 0x3F\n\n let offset = 2\n\n // Packet ID (2 bytes, big-endian)\n const packetId = view.getUint16(offset, false)\n offset += 2\n\n // Timestamp (4 bytes, big-endian)\n const timestamp = BigInt(view.getUint32(offset, false))\n offset += 4\n\n // Sequence number (4 bytes, big-endian)\n const sequenceNumber = view.getUint32(offset, false)\n offset += 4\n\n let packetCounter: number | undefined\n if (packetCounterFlag) {\n if (offset + 4 > buffer.length) throw new Error('MMTP packet truncated in packet_counter')\n packetCounter = view.getUint32(offset, false)\n offset += 4\n }\n\n let extension: { type: number; data: Uint8Array } | undefined\n if (extensionFlag) {\n if (offset + 4 > buffer.length) throw new Error('MMTP packet truncated in header extension')\n const type = view.getUint16(offset, false)\n const length = view.getUint16(offset + 2, false)\n offset += 4\n if (offset + length > buffer.length) throw new Error('MMTP packet truncated in header extension value')\n extension = { type, data: buffer.subarray(offset, offset + length) }\n offset += length\n }\n\n return {\n version,\n packetType,\n packetId,\n timestamp,\n sequenceNumber,\n payloadLength: buffer.length - offset,\n fecType,\n packetCounterFlag,\n packetCounter,\n extensionFlag,\n extension,\n headerLength: offset,\n rapFlag,\n }\n}\n\n/**\n * Unwrap MMTP packet to extract payload\n */\nexport function unwrapMMTP(buffer: Uint8Array): MMTPPacket {\n const header = parseMMTPHeader(buffer)\n const payload = buffer.subarray(header.headerLength)\n\n return { header, payload }\n}\n\n/**\n * Parse MPU header from payload\n * ISO/IEC 23008-1:2023 Section 9.2.3.3\n *\n * MPU Header format (8 bytes) as written by FFmpeg/libmmt:\n * - Bytes 0-1: payload_length (16 bits, big-endian)\n * - Byte 2: FT(4) | T(1) | FI(2) | A(1)\n * - Byte 3: fragment_counter (8 bits)\n * - Bytes 4-7: MPU_sequence_number (32 bits, big-endian)\n */\nexport function parseMPUHeader(payload: Uint8Array): MPUHeader {\n if (payload.length < MPU_HEADER_SIZE) {\n throw new Error(`Payload too small for MPU header: ${payload.length} bytes`)\n }\n\n const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength)\n\n // Bytes 0-1: payload_length (16 bits, big-endian)\n const payloadLength = view.getUint16(0, false)\n\n // Byte 2: FT(4) | T(1) | FI(2) | A(1)\n const flagsByte = payload[2]!\n const timedFlag = (flagsByte >> 3) & 0x01\n const fragmentationIndicator = (flagsByte >> 1) & 0x03\n const aggregationFlag = (flagsByte & 0x01) !== 0\n\n // Byte 3: fragment_counter (8 bits). The high bit is part of the counter in\n // the current libmmt/FFmpeg writer ABI.\n const fragmentCounter = payload[3]!\n\n // Bytes 4-7: MPU_sequence_number (32 bits, big-endian)\n const mpuSequenceNumber = view.getUint32(4, false)\n\n return {\n mpuSequenceNumber,\n fragmentationIndicator,\n fragmentCounter,\n timedFlag,\n aggregationFlag,\n payloadLength,\n }\n}\n\nexport function parseTimedMfuDuHeader(payload: Uint8Array, offset: number): MFUDuHeader | null {\n if (offset < 0 || offset + MFU_DU_HEADER_SIZE_TIMED > payload.length) return null\n const view = new DataView(payload.buffer, payload.byteOffset + offset, MFU_DU_HEADER_SIZE_TIMED)\n return {\n movieFragmentSequenceNumber: view.getUint32(0, false),\n sampleNumber: view.getUint32(4, false),\n offset: view.getUint32(8, false),\n priority: payload[offset + 12]!,\n dependencyCounter: payload[offset + 13]!,\n }\n}\n\n/**\n * Why `extractMFUPayload` refused a packet.\n *\n * These identifiers are part of the public contract: callers surface them in\n * diagnostics, so renaming one is a breaking change.\n */\nexport type MFURejectionGate =\n | 'packet-shorter-than-mmtp-plus-mpu-header'\n | 'mmtp-header-unparseable'\n | 'not-an-mpu-packet'\n | 'payload-shorter-than-mpu-header'\n | 'aggregation-flag-set'\n | 'mpu-payload-length-below-header-remainder'\n | 'mpu-declared-end-exceeds-payload'\n | 'mfu-offset-at-or-past-declared-end'\n | 'source-fec-payload-id-width-mismatch'\n | 'declared-trailers-unresolved'\n\nexport interface MFURejection {\n gate: MFURejectionGate\n /** Human-readable detail, including the byte arithmetic that decided it. */\n detail: string\n}\n\ninterface MfuPayloadLayout {\n hasMfuDuHeader: boolean\n mfuOffset: number\n dataEnd: number\n}\n\nfunction resolveMfuPayloadLayout(\n mpu: MPUHeader,\n fragmentType: number,\n payload: Uint8Array,\n): { layout: MfuPayloadLayout } | { rejection: MFURejection } {\n if (mpu.payloadLength < MPU_HEADER_REMAINDER_SIZE) {\n return {\n rejection: {\n gate: 'mpu-payload-length-below-header-remainder',\n detail: `payload_length=${mpu.payloadLength} < ${MPU_HEADER_REMAINDER_SIZE}`,\n },\n }\n }\n\n // ISO/IEC 23008-1 defines payload_length from immediately after its own\n // two-byte field. It therefore includes the remaining six MPU-header bytes.\n const declaredEnd = MPU_LENGTH_FIELD_SIZE + mpu.payloadLength\n if (declaredEnd > payload.length) {\n return {\n rejection: {\n gate: 'mpu-declared-end-exceeds-payload',\n detail:\n `payload_length=${mpu.payloadLength} implies end=${declaredEnd}, ` +\n `payload is ${payload.length} bytes`,\n },\n }\n }\n\n const hasHeader = fragmentType === 2 && mpu.fragmentationIndicator <= 1\n const mfuHeaderSize = mpu.timedFlag ? MFU_DU_HEADER_SIZE_TIMED : MFU_DU_HEADER_SIZE_NONTIMED\n const mfuOffset = MPU_HEADER_SIZE + (hasHeader ? mfuHeaderSize : 0)\n if (mfuOffset >= declaredEnd) {\n return {\n rejection: {\n gate: 'mfu-offset-at-or-past-declared-end',\n detail: `mfuOffset=${mfuOffset} >= declaredEnd=${declaredEnd}`,\n },\n }\n }\n\n return {\n layout: {\n hasMfuDuHeader: hasHeader,\n mfuOffset,\n dataEnd: declaredEnd,\n },\n }\n}\n\nfunction isEmptyOrExactAltaTrailer(payload: Uint8Array, start: number, end: number): boolean {\n if (start === end) return true\n if (start < 0 || end > payload.length || start + _LEAF_MMTP_EXT_TRAILER_HEADER_SIZE > end) {\n return false\n }\n\n const view = new DataView(\n payload.buffer,\n payload.byteOffset + start,\n end - start,\n )\n if (view.getUint16(0, false) !== _LEAF_MMTP_EXT_TYPE_ALTA_AUTH) return false\n\n const authLength = view.getUint16(2, false)\n return start + _LEAF_MMTP_EXT_TRAILER_HEADER_SIZE + authLength === end\n}\n\ninterface DeclaredTrailerLayout {\n hasFecId: boolean\n}\n\nfunction resolveDeclaredTrailers(\n payload: Uint8Array,\n declaredEnd: number,\n fecType: number,\n options?: { skipFecId?: boolean },\n): DeclaredTrailerLayout | null {\n if (declaredEnd > payload.length) return null\n\n if (options?.skipFecId) {\n return isEmptyOrExactAltaTrailer(payload, declaredEnd, payload.length)\n ? { hasFecId: false }\n : null\n }\n\n if (fecType === 1) {\n const fecStart = payload.length - SOURCE_FEC_PAYLOAD_ID_SIZE\n if (fecStart < declaredEnd || !isEmptyOrExactAltaTrailer(payload, declaredEnd, fecStart)) {\n return null\n }\n return { hasFecId: true }\n }\n if (fecType !== 0) return null\n\n if (isEmptyOrExactAltaTrailer(payload, declaredEnd, payload.length)) {\n return { hasFecId: false }\n }\n\n return null\n}\n\n/**\n * Extract NAL unit payload from MMTP packet\n */\nexport function extractNALUnit(mmtpPacket: Uint8Array): Uint8Array {\n const extraction = extractMFUPayload(mmtpPacket)\n if (!extraction) throw new Error('Malformed MMTP MPU payload')\n return extraction.data\n}\n\n/** Result of extracting MFU payload from an MMTP packet */\nexport interface MFUExtraction {\n /** MMTP header fields */\n header: MMTPHeader\n /** MPU header fields */\n mpu: MPUHeader\n /** Fragment type (FT field, 4 bits): 0=metadata, 2=MFU data */\n fragmentType: number\n /** MFU payload data (video/audio bytes, headers stripped, FEC ID excluded) */\n data: Uint8Array\n /** Parsed timed MFU DU header when present, otherwise null */\n mfuDuHeader: MFUDuHeader | null\n /** Non-timed MFU Item_ID when the 4-byte DU header is present. */\n itemId: number | null\n /** Source FEC Payload ID if present (`FEC_type == 1`), or null */\n fecPayloadId: { ssId: number } | null\n}\n\n/**\n * Extract MFU payload from a raw MMTP packet.\n *\n * Handles all the byte arithmetic for:\n * - MMTP header (12 bytes)\n * - MPU sub-header (8 bytes, payloadLength field)\n * - MFU DU header (14 bytes timed / 4 bytes non-timed, only for FI \u2264 1)\n * - Source FEC Payload ID (4 bytes at end, only when `FEC_type == 1`)\n *\n * `payloadLength` is the ISO length-after-field value: six remaining MPU-header\n * bytes, then the MFU DU header when present, then media. ALTA and Source FEC\n * trailers are outside that declared span and must consume the exact suffix.\n *\n * @param mmtpPacket Raw MMTP packet (from multicast or MoQ)\n * @param options.skipFecId When true, do NOT subtract the 4-byte Source FEC Payload ID\n * from the payload boundary, even if fecType >= 1 in the MMTP header. Use this for\n * FEC-recovered symbols where the FEC PID was already stripped before WASM decoding\n * but the fecType bits in byte 0 still reflect the original packet (FEC Type=1 per\n * draft-ramadan-moq-mmt-00 \u00A73.1).\n * @returns Extracted MFU data + metadata, or null if packet is too small\n */\ninterface MfuPlan {\n header: MMTPHeader\n payload: Uint8Array\n mpu: MPUHeader\n fragmentType: number\n layout: MfuPayloadLayout\n trailerLayout: DeclaredTrailerLayout\n}\n\n/**\n * Single source of truth for whether a packet yields an MFU payload.\n *\n * `extractMFUPayload` and `explainMFURejection` both delegate here, so the\n * reason reported to operators can never drift from the decision the parser\n * actually made.\n */\nfunction planMfuExtraction(\n mmtpPacket: Uint8Array,\n options?: { skipFecId?: boolean },\n): { plan: MfuPlan } | { rejection: MFURejection } {\n if (mmtpPacket.length < MMTP_HEADER_SIZE + MPU_HEADER_SIZE) {\n return {\n rejection: {\n gate: 'packet-shorter-than-mmtp-plus-mpu-header',\n detail: `${mmtpPacket.length} bytes < ${MMTP_HEADER_SIZE + MPU_HEADER_SIZE}`,\n },\n }\n }\n\n let header: MMTPHeader\n try {\n header = parseMMTPHeader(mmtpPacket)\n } catch (error) {\n return {\n rejection: {\n gate: 'mmtp-header-unparseable',\n detail: error instanceof Error ? error.message : String(error),\n },\n }\n }\n if (header.packetType !== PACKET_TYPE_MPU) {\n return {\n rejection: {\n gate: 'not-an-mpu-packet',\n detail: `packetType=0x${header.packetType.toString(16).padStart(2, '0')}`,\n },\n }\n }\n\n const payload = mmtpPacket.subarray(header.headerLength)\n if (payload.length < MPU_HEADER_SIZE) {\n return {\n rejection: {\n gate: 'payload-shorter-than-mpu-header',\n detail: `${payload.length} bytes < ${MPU_HEADER_SIZE}`,\n },\n }\n }\n\n const mpu = parseMPUHeader(payload)\n if (mpu.aggregationFlag) {\n return {\n rejection: { gate: 'aggregation-flag-set', detail: 'strict profile requires A=0' },\n }\n }\n\n // Fragment type from byte 2 upper nibble (not returned by parseMPUHeader)\n const fragmentType = (payload[2]! >> 4) & 0x0f\n\n const layoutResult = resolveMfuPayloadLayout(mpu, fragmentType, payload)\n if ('rejection' in layoutResult) return layoutResult\n const { layout } = layoutResult\n\n const trailerLayout = resolveDeclaredTrailers(\n payload,\n layout.dataEnd,\n header.fecType,\n options,\n )\n if (!trailerLayout) {\n // The most common cause is a producer whose Source FEC Payload ID width\n // disagrees with ISO/IEC 23008-1 \u00A7C.5.2. Name that explicitly rather than\n // leaving operators to infer it from a generic trailer error.\n if (!options?.skipFecId && header.fecType === 1) {\n const observed = payload.length - layout.dataEnd\n if (observed !== SOURCE_FEC_PAYLOAD_ID_SIZE) {\n return {\n rejection: {\n gate: 'source-fec-payload-id-width-mismatch',\n detail:\n `producer wrote a ${observed}-byte Source FEC Payload ID, ` +\n `ISO/IEC 23008-1 \u00A7C.5.2 requires ${SOURCE_FEC_PAYLOAD_ID_SIZE} ` +\n `(payload=${payload.length}, declaredEnd=${layout.dataEnd})`,\n },\n }\n }\n }\n return {\n rejection: {\n gate: 'declared-trailers-unresolved',\n detail:\n `trailer bytes [${layout.dataEnd}, ${payload.length}) are neither empty ` +\n `nor an exact ALTA trailer (fecType=${header.fecType})`,\n },\n }\n }\n\n return { plan: { header, payload, mpu, fragmentType, layout, trailerLayout } }\n}\n\n/**\n * Report why `extractMFUPayload` would refuse this packet, or null if it would\n * accept it.\n *\n * `extractMFUPayload` returns bare `null` on ten distinct conditions, which\n * makes a producer/consumer framing disagreement indistinguishable from a\n * publisher that never started \u2014 both render as silence. Use this wherever\n * that distinction matters: diagnostics, contract tests, and operator-facing\n * logs.\n */\nexport function explainMFURejection(\n mmtpPacket: Uint8Array,\n options?: { skipFecId?: boolean },\n): MFURejection | null {\n const result = planMfuExtraction(mmtpPacket, options)\n return 'rejection' in result ? result.rejection : null\n}\n\nexport function extractMFUPayload(\n mmtpPacket: Uint8Array,\n options?: { skipFecId?: boolean },\n): MFUExtraction | null {\n const result = planMfuExtraction(mmtpPacket, options)\n if ('rejection' in result) return null\n const { header, payload, mpu, fragmentType, layout, trailerLayout } = result.plan\n\n const mfuDuHeaderPresent = layout.hasMfuDuHeader\n const mfuOffset = layout.mfuOffset\n const dataEnd = layout.dataEnd\n\n const mfuDuHeader =\n mfuDuHeaderPresent && mpu.timedFlag === 1\n ? parseTimedMfuDuHeader(payload, MPU_HEADER_SIZE)\n : null\n const itemId =\n mfuDuHeaderPresent && mpu.timedFlag === 0\n ? new DataView(payload.buffer, payload.byteOffset + MPU_HEADER_SIZE, 4).getUint32(0, false)\n : null\n\n const data = payload.subarray(mfuOffset, dataEnd)\n\n const fecPayloadId = trailerLayout.hasFecId\n ? {\n ssId: new DataView(\n mmtpPacket.buffer,\n mmtpPacket.byteOffset + mmtpPacket.length - SOURCE_FEC_PAYLOAD_ID_SIZE,\n SOURCE_FEC_PAYLOAD_ID_SIZE,\n ).getUint32(0, false),\n }\n : null\n\n return { header, mpu, fragmentType, data, mfuDuHeader, itemId, fecPayloadId }\n}\n\n/**\n * Extract timestamp from MMTP packet\n */\nexport function extractTimestamp(mmtpPacket: Uint8Array): bigint {\n const { header } = unwrapMMTP(mmtpPacket)\n return header.timestamp\n}\n\n/**\n * Check if MMTP packet is an FEC repair packet\n * FEC_type 2 and 3 are repair packets\n */\nexport function isFecRepairPacket(mmtpPacket: Uint8Array): boolean {\n if (mmtpPacket.length < 1) return false\n const fecType = (mmtpPacket[0]! >> 3) & 0x03\n return fecType >= 2\n}\n\n/**\n * Extract Source FEC Payload ID (SS_ID) from the last 4 bytes of an MMTP\n * source packet per ISO/IEC 23008-1:2023 Section C.5.2 Figure C.10.\n *\n * SS_ID is a flat 32-bit monotonic counter (incremented by 1 per packet\n * for ssbg_mode0 and ssbg_mode1). Block membership and ESI are derived\n * at recovery time from repair packet SS_Start and SSB_length:\n * SBN = floor(SS_ID / K), ESI = SS_ID % K\n * SS_Start = SBN * K (first SS_ID of the block)\n *\n * This matches FFmpeg moqenc_mmt.c, the drafts (draft-ramadan-moq-fec \u00A76.2),\n * and ATSC A/331 \u00A78.1.2.5 which defers to ISO 23008-1 Annex C.\n */\nexport function extractFecPayloadId(mmtpPacket: Uint8Array): { ssId: number } | null {\n if (!hasSourceFecPayloadId(mmtpPacket)) return null\n // Flat 4-byte SS_ID: encoder writes block_id * K + symbol_id\n const off = mmtpPacket.length - SOURCE_FEC_PAYLOAD_ID_SIZE\n const view = new DataView(\n mmtpPacket.buffer,\n mmtpPacket.byteOffset + off,\n SOURCE_FEC_PAYLOAD_ID_SIZE,\n )\n return { ssId: view.getUint32(0, false) }\n}\n\n/**\n * Return true when FEC_type=1 and the exact suffix after the ISO-declared MPU\n * payload contains a four-byte Source FEC Payload ID.\n */\nexport function hasSourceFecPayloadId(mmtpPacket: Uint8Array): boolean {\n if (mmtpPacket.length < MMTP_HEADER_SIZE + MPU_HEADER_SIZE) return false\n\n let header: MMTPHeader\n try {\n header = parseMMTPHeader(mmtpPacket)\n } catch {\n return false\n }\n if (header.packetType !== PACKET_TYPE_MPU) return false\n\n const payload = mmtpPacket.subarray(header.headerLength)\n if (payload.length < MPU_HEADER_SIZE) return false\n const mpu = parseMPUHeader(payload)\n if (mpu.payloadLength < MPU_HEADER_REMAINDER_SIZE) return false\n const declaredEnd = MPU_LENGTH_FIELD_SIZE + mpu.payloadLength\n return resolveDeclaredTrailers(payload, declaredEnd, header.fecType)?.hasFecId ?? false\n}\n\n/**\n * MMTP header-extension ext_type assigned to the detached ALTA authenticator\n * trailer (Path 2 / 08-07). Carried in an `[ext_type][ext_length][auth]`\n * block appended after the MPU's declared payload bytes, before the 4-byte\n * Source FEC Payload ID. MMTP X-bit stays 0 \u2014 non-ALTA MMTP receivers treat\n * the trailer as bytes past `payload_length` and skip it (per ISO 23008-1\n * \u00A79.2.2 \"may be discarded without impacting correct processing\").\n */\n// Re-export the ALTA trailer helper from the zero-dep leaf package. The leaf\n// owns the implementation so container and FEC consumers share one parser\n// without creating a package cycle.\nexport const MMTP_EXT_TYPE_ALTA_AUTH = _LEAF_MMTP_EXT_TYPE_ALTA_AUTH\nexport const MMTP_EXT_TRAILER_HEADER_SIZE = _LEAF_MMTP_EXT_TRAILER_HEADER_SIZE\nexport type AltaTrailer = _LeafAltaTrailer\nexport const extractAltaTrailer = _leafExtractAltaTrailer\n\n/** Size of Repair FEC Payload ID per ISO/IEC 23008-1 Section C.5.3 */\nexport const REPAIR_FEC_PID_SIZE = 13\n\n/** Parse the 13-byte Repair FEC Payload ID after the complete dynamic MMTP header. */\nfunction readRepairFecPayloadIdFields(mmtpPacket: Uint8Array): {\n packetId: number; ssStart: number; rsbLength: number; rsId: number; ssbLength: number; dataOffset: number\n} | null {\n let header: MMTPHeader\n try {\n header = parseMMTPHeader(mmtpPacket)\n } catch {\n return null\n }\n if (header.packetType !== PACKET_TYPE_REPAIR || header.fecType !== 2) return null\n\n const off = header.headerLength\n if (mmtpPacket.length < off + REPAIR_FEC_PID_SIZE) return null\n const view = new DataView(mmtpPacket.buffer, mmtpPacket.byteOffset + off, REPAIR_FEC_PID_SIZE)\n const ssStart = view.getUint32(0, false) // 32 bits\n const rsbLength = (mmtpPacket[off + 4]! << 16) | (mmtpPacket[off + 5]! << 8) | mmtpPacket[off + 6]! // 24 bits\n const rsId = (mmtpPacket[off + 7]! << 16) | (mmtpPacket[off + 8]! << 8) | mmtpPacket[off + 9]! // 24 bits\n const ssbLength = (mmtpPacket[off + 10]! << 16) | (mmtpPacket[off + 11]! << 8) | mmtpPacket[off + 12]! // 24 bits\n return {\n packetId: header.packetId,\n ssStart,\n rsbLength,\n rsId,\n ssbLength,\n dataOffset: off + REPAIR_FEC_PID_SIZE,\n }\n}\n\n/**\n * Extract Repair FEC Payload ID from a raw-multicast MMTP repair packet.\n * Per ISO/IEC 23008-1:2023 Section C.5.3 (ssbg_mode0, one-stage, no FFSRP_TS):\n * [MMTP header][SS_Start:4][RSB_length:3][RS_ID:3][SSB_length:3][repair data]\n * OTI is delivered via AL-FEC signaling message (Table C.3), not per-packet.\n *\n * Byte 1 is reserved(2)|packet_type(6) for V=0, so repair type 0x03 is 0x03.\n * Pre-migration high-bits bytes (0x0c) are rejected \u2014 no compatibility decode.\n */\nexport function extractRepairFecPayloadId(mmtpPacket: Uint8Array): {\n ssStart: number; rsbLength: number; rsId: number; ssbLength: number\n} | null {\n const fields = readRepairFecPayloadIdFields(mmtpPacket)\n if (!fields) return null\n return {\n ssStart: fields.ssStart,\n rsbLength: fields.rsbLength,\n rsId: fields.rsId,\n ssbLength: fields.ssbLength,\n }\n}\n\n/** Parsed MoQ repair frame per ISO/IEC 23008-1 Section C.4.3 + C.5.3 */\nexport interface MoqRepairFrame {\n /** MMTP packetId (1=video, 2=audio) \u2014 for routing to correct FEC decoder */\n packetId: number\n /** SS_Start (32 bits): SS_ID of first source symbol in block */\n ssStart: number\n /** RSB_length (24 bits): number of repair symbols (P) */\n rsbLength: number\n /** RS_ID (24 bits): repair symbol index (0-based) */\n rsId: number\n /** SSB_length (24 bits): number of source symbols (K) */\n ssbLength: number\n /** Repair symbol data after the dynamic MMTP header and 13-byte FEC payload ID. */\n symbolData: Uint8Array\n}\n\n/**\n * Parse a MoQ repair frame (ISO/IEC 23008-1 Annex C format).\n *\n * Wire format per ISO 23008-1 \u00A7C.4.3 + \u00A7C.5.3:\n * MMTP Header: fixed 12 bytes plus C/X optional fields\n * then SS_Start (4 bytes) \u2192 block identifier\n * then RSB_length (3 bytes) \u2192 P\n * then RS_ID (3 bytes) \u2192 ESI = K + RS_ID\n * then SSB_length (3 bytes) \u2192 K\n * then Repair Symbol Data (T bytes)\n *\n * @param frame - Raw MoQ repair frame bytes\n * @returns Parsed frame or null if invalid\n */\nexport function parseMoqRepairFrame(frame: Uint8Array): MoqRepairFrame | null {\n const repairId = readRepairFecPayloadIdFields(frame)\n if (!repairId) return null\n\n const symbolData = frame.subarray(repairId.dataOffset)\n if (\n repairId.rsbLength === 0 ||\n repairId.ssbLength === 0 ||\n repairId.rsId >= repairId.rsbLength ||\n symbolData.length === 0\n ) return null\n\n return {\n packetId: repairId.packetId,\n ssStart: repairId.ssStart,\n rsbLength: repairId.rsbLength,\n rsId: repairId.rsId,\n ssbLength: repairId.ssbLength,\n symbolData,\n }\n}\n\n/**\n * AL-FEC signaling configuration parsed from ISO/IEC 23008-1:2023 Table C.3 message.\n */\nexport interface AlFecConfig {\n fecCodeId: number\n fecPayloadIdMode: 0\n repairSymbolSize: number\n maximumK: number\n maximumP: number\n interleaveDepth: number\n oti: Uint8Array\n}\n\nfunction canonicalRaptorQOtiK(oti: Uint8Array, repairSymbolSize: number): number | null {\n if (oti.length !== 12 || oti[5] !== 0) return null\n const transferLength = (oti[0]! * 0x1_0000_0000) +\n (((oti[1]! << 24) | (oti[2]! << 16) | (oti[3]! << 8) | oti[4]!) >>> 0)\n const symbolSize = (oti[6]! << 8) | oti[7]!\n const sourceBlocks = oti[8]!\n const subBlocks = (oti[9]! << 8) | oti[10]!\n const alignment = oti[11]!\n if (!Number.isSafeInteger(transferLength) || transferLength <= 0 ||\n symbolSize !== repairSymbolSize || symbolSize === 0 || symbolSize % 8 !== 0 ||\n sourceBlocks !== 1 || subBlocks !== 1 || alignment !== 8 ||\n transferLength % symbolSize !== 0) {\n return null\n }\n const k = transferLength / symbolSize\n return Number.isInteger(k) && k >= 1 && k <= 56_403 ? k : null\n}\n\n/**\n * Parse AL-FEC signaling message from a full MMTP signaling packet.\n *\n * Wire format (ISO/IEC 23008-1:2023 Table C.3, Amendment 1:2025):\n * [12-byte MMTP header (packet_type=0x02)]\n * message_id(2) = 0x0203\n * version(1)\n * message_length(2) = length of remaining payload\n * flags(1) = fec_flag(1) | private_fec_flag(1) | reserved(6)\n * fec_flow_descriptor:\n * length(2)\n * num_flows(1)\n * per flow:\n * fec_flow_id(1), source_flow_id(1), num_assets(1), packet_ids(2*N),\n * coding_params(1), repair_symbol_size(2),\n * [one-stage]: repair_flow_id(2), fec_code_id(1),\n * [private_fec_flag]: private_header(1){flag(1)|len(7)},\n * current RaptorQ profile OTI(12) + interleave_depth(1)\n * max_k(3), max_p(3), protection_window_time(4), protection_window_size(4)\n *\n * @param mmtpPacket Full MMTP packet including 12-byte header\n * @returns Parsed config or null if not an AL-FEC signaling message\n */\nexport function parseAlFecMessage(mmtpPacket: Uint8Array): AlFecConfig | null {\n if (mmtpPacket.length < MMTP_HEADER_SIZE + 9) return null\n let header: MMTPHeader\n try {\n header = parseMMTPHeader(mmtpPacket)\n } catch {\n return null\n }\n if (header.packetType !== PACKET_TYPE_SIGNALING || header.fecType !== 0) return null\n const payload = mmtpPacket.subarray(header.headerLength)\n if (payload.length < 9) return null\n const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength)\n let off = 0\n\n const messageId = view.getUint16(off, false); off += 2\n if (messageId !== ALFEC_MESSAGE_ID) return null\n const version = payload[off]!; off += 1\n const messageLength = view.getUint16(off, false); off += 2\n if (version !== 1 || messageLength === 0 || messageLength !== payload.length - off) return null\n\n const flags = payload[off]!; off += 1\n const fecFlag = (flags >> 7) & 1\n const privateFecFlag = (flags >> 6) & 1\n if (fecFlag !== 1 || privateFecFlag !== 1 || (flags & 0x3f) !== 0x3f) return null\n\n if (off + 2 > payload.length) return null\n const descriptorLength = view.getUint16(off, false); off += 2\n const descriptorEnd = off + descriptorLength\n if (descriptorLength === 0 || descriptorEnd !== payload.length) return null\n\n const numFlows = payload[off]!; off += 1\n if (numFlows !== 1 || off + 3 > descriptorEnd) return null\n\n off += 2 // fec_flow_id, source_flow_id\n const numAssets = payload[off]!; off += 1\n if (numAssets === 0 || off + (numAssets * 2) > descriptorEnd) return null\n off += numAssets * 2\n\n if (off + 3 > descriptorEnd) return null\n const codingParams = payload[off]!; off += 1\n const fecCodingStructure = (codingParams >> 4) & 0x0f\n const ssbgMode = (codingParams >> 2) & 0x03\n const ffsrptsFlag = (codingParams >> 1) & 0x01\n const fecPayloadIdMode = codingParams & 0x01\n if (fecCodingStructure !== 1 || ssbgMode !== 0 || ffsrptsFlag !== 0 || fecPayloadIdMode !== 0) {\n return null\n }\n const repairSymbolSize = view.getUint16(off, false); off += 2\n if (repairSymbolSize === 0 || repairSymbolSize % 8 !== 0) return null\n\n if (off + 4 > descriptorEnd) return null\n off += 2 // Amendment 1:2025 replaces Table C.3 with a 16-bit repair_flow_id\n const fecCodeId = payload[off]!; off += 1\n if (fecCodeId !== FEC_CODE_RAPTORQ) return null\n const privateHeader = payload[off]!; off += 1\n const privateFlag = privateHeader >> 7\n const privateFieldLength = privateHeader & 0x7f\n if (privateFlag !== 1 || privateFieldLength !== 13 || off + 13 > descriptorEnd) return null\n const oti = payload.slice(off, off + 12); off += 12\n const interleaveDepth = payload[off]!; off += 1\n const otiK = canonicalRaptorQOtiK(oti, repairSymbolSize)\n if (otiK === null || interleaveDepth === 0) return null\n\n if (off + 14 !== descriptorEnd) return null\n const maximumK = (payload[off]! << 16) | (payload[off + 1]! << 8) | payload[off + 2]!\n off += 3\n const maximumP = (payload[off]! << 16) | (payload[off + 1]! << 8) | payload[off + 2]!\n off += 3\n if (maximumK !== otiK || maximumP === 0 || maximumK + maximumP - 1 > 0x00ff_ffff) {\n return null\n }\n off += 8 // protection_window_time, protection_window_size\n if (off !== descriptorEnd) return null\n\n return { fecCodeId, fecPayloadIdMode, repairSymbolSize, maximumK, maximumP, interleaveDepth, oti }\n}\n", "/**\n * @mmt/container - MFU Fragment Reassembler\n *\n * Handles authored fragmented MFUs (Media Fragment Units) according to\n * ISO/IEC 23008-1:2023 Section 9.2.3.3. Fragmented runs are admitted in the\n * exact FI/fragment_counter countdown carried on the wire. Transport-run\n * association additionally requires the repository's contiguous-source\n * producer profile; ISO-permitted interleaving remains incomplete and fails\n * closed.\n *\n * Fragmentation Indicator (FI) values:\n * - 0: Complete MFU (single packet, no fragmentation)\n * - 1: First fragment\n * - 2: Middle fragment\n * - 3: Last fragment\n *\n * @packageDocumentation\n */\n\nimport {\n extractMFUPayload,\n isFecRepairPacket,\n} from '@blockcast/mmt-base'\n\n/** Source transport admitted by the MMTP router. */\nexport type MmtpSourcePath = 'multicast' | 'moq'\n\n/**\n * Strict whole-frame delivery provenance, folded over EVERY contributing\n * fragment rather than the head fragment alone.\n *\n * This is deliberately NOT `source`. `source` answers a routing question \u2014\n * \"is this the reliable-MoQ copy that must not confirm multicast takeover?\" \u2014\n * and head-fragment-wins is the documented, deterministic answer to it.\n * Provenance answers an evidence question: \"did every byte of this frame\n * physically arrive over multicast?\" A frame with a multicast head and a\n * QUIC-delivered tail is a legitimate routing win for `source: 'multicast'`\n * and is emphatically NOT multicast-exclusive delivery.\n *\n * - 'multicast' \u2014 every contributing fragment was explicitly multicast.\n * The ONLY value that may be counted as physical-delivery evidence.\n * - 'mixed' \u2014 at least one contributing fragment arrived over MoQ.\n * - 'unknown' \u2014 no fragment arrived over MoQ, but at least one carried no\n * attribution at all. Absence is preserved as its own state rather than\n * defaulted, so a consumer cannot mistake \"never recorded\" for \"proven\".\n */\nexport type MmtpDeliveryProvenance = 'multicast' | 'mixed' | 'unknown'\n\n/**\n * Fold one fragment's `source` into a running provenance verdict.\n *\n * Fail-closed, order-independent and associative: 'mixed' absorbs everything,\n * a missing attribution degrades 'multicast' to 'unknown', and nothing ever\n * upgrades a verdict. Fold over an empty set is 'unknown' \u2014 no fragment ever\n * proved anything.\n */\nexport function foldDeliveryProvenance(\n verdict: MmtpDeliveryProvenance,\n source: MmtpSourcePath | undefined,\n): MmtpDeliveryProvenance {\n if (verdict === 'mixed') return 'mixed'\n if (source === 'moq') return 'mixed'\n if (source === undefined) return 'unknown'\n return verdict\n}\n\n/**\n * One fragment's own provenance.\n *\n * An explicit `deliveryProvenance` wins: FEC-recovered fragments carry no\n * `source` (they were never delivered as themselves) but their block's symbol\n * provenance IS known, and the router supplies it. Falling back to `source`\n * keeps directly-delivered fragments working unchanged.\n */\nfunction fragmentProvenance(fragment: {\n source?: MmtpSourcePath\n deliveryProvenance?: MmtpDeliveryProvenance\n}): MmtpDeliveryProvenance {\n if (fragment.deliveryProvenance !== undefined) return fragment.deliveryProvenance\n if (fragment.source === 'moq') return 'mixed'\n if (fragment.source === 'multicast') return 'multicast'\n return 'unknown'\n}\n\n/** Strict provenance for a complete fragment set. */\nexport function deliveryProvenanceOf(\n fragments: readonly {\n source?: MmtpSourcePath\n deliveryProvenance?: MmtpDeliveryProvenance\n }[],\n): MmtpDeliveryProvenance {\n if (fragments.length === 0) return 'unknown'\n let verdict: MmtpDeliveryProvenance = 'multicast'\n for (const fragment of fragments) {\n const own = fragmentProvenance(fragment)\n verdict =\n verdict === 'mixed' || own === 'mixed'\n ? 'mixed'\n : verdict === 'unknown' || own === 'unknown'\n ? 'unknown'\n : 'multicast'\n }\n return verdict\n}\n\n/**\n * MFU Fragment for reassembly\n */\nexport interface MFUFragment {\n fragmentationIndicator: number\n mpuSequenceNumber: number\n fragmentCounter: number\n data: Uint8Array\n timestamp: bigint\n /** Random Access Point flag from MMTP header - indicates keyframe */\n rapFlag: boolean\n /** MFU DU priority. FFmpeg marks random-access samples with high priority. */\n priority?: number\n sampleNumber?: number\n movieFragmentSequenceNumber?: number\n sampleOffset?: number\n /** Non-timed MFU Item_ID from the 4-byte DU header. */\n itemId?: number\n /** Authored u32 MMTP packet_sequence_number, including on recovered packets. */\n packetSequenceNumber?: number\n /** True when this accepted source packet was reconstructed by FEC. */\n recovered?: boolean\n /** Transport that supplied this accepted fragment. Absent for recovered data. */\n source?: MmtpSourcePath\n /**\n * Explicit provenance for this fragment, overriding what `source` implies.\n * Set by the router for FEC-recovered fragments, which have no `source` of\n * their own but whose FEC block's symbol provenance is known.\n */\n deliveryProvenance?: MmtpDeliveryProvenance\n /** Immutable catalog identity supplied by the owning ingress subscription. */\n catalogTrackName?: string\n /** Physical MMTP stream identity when no catalog identity is available. */\n packetId?: number\n}\n\n/**\n * Reassembled MFU result\n */\nexport interface ReassembledMFU {\n mpuSequenceNumber: number\n /** MMTP packet_sequence_number of the first fragment in delivery order. */\n packetSequenceNumber?: number\n /** Every authoritative MMTP source-packet sequence that formed this MFU. */\n packetSequenceNumbers?: number[]\n /** Subset of packetSequenceNumbers reconstructed by FEC. */\n repairedPacketSequenceNumbers?: number[]\n data: Uint8Array\n timestamp: bigint\n fragmentCount: number\n /** Random Access Point flag - indicates keyframe (from first fragment) */\n rapFlag: boolean\n /** MFU DU priority from the first fragment that carried it. */\n priority?: number\n sampleNumber?: number\n movieFragmentSequenceNumber?: number\n /**\n * This DU's authored base byte offset within its sample (moqcast #37). 0\n * for a whole-sample DU; nonzero identifies one subsample DU among\n * siblings partitioning an oversized sample. Constant across the DU's own\n * fragments \u2014 feed into a sample combiner to reassemble the full sample.\n */\n sampleOffset?: number\n /**\n * Transport that supplied the accepted FI=1 head fragment (or the complete\n * FI=0 frame). This is the deterministic winner for mixed-path assembly.\n *\n * ROUTING ONLY. It describes one fragment, so it is not evidence about the\n * whole frame \u2014 read {@link ReassembledMFU.deliveryProvenance} for that.\n */\n source?: MmtpSourcePath\n /**\n * Strict provenance folded over every contributing fragment. Only\n * 'multicast' proves multicast-exclusive delivery of this frame.\n */\n deliveryProvenance: MmtpDeliveryProvenance\n /** Catalog identity from the accepted FI=1 head fragment, or FI=0 frame. */\n catalogTrackName?: string\n}\n\n/**\n * Reassembler statistics\n */\nexport interface ReassemblerStats {\n totalFragments: number\n reassembledMFUs: number\n /** Fragments rejected by strict authored DU-state validation. */\n rejectedFragments: number\n /** Incomplete MFUs discarded after their configured deadline. */\n timedOutMFUs: number\n /** Incomplete MFUs discarded to enforce the configured memory bound. */\n evictedMemoryLimit: number\n outOfOrderFragments: number\n}\n\nexport const MFU_REASSEMBLY_ERROR_CODES = [\n 'invalid-fragment-state',\n 'missing-data-unit-identity',\n 'missing-packet-sequence',\n 'conflicting-data-unit-identity',\n 'overlapping-data-unit',\n 'fragment-counter-mismatch',\n 'data-unit-identity-mismatch',\n 'offset-overflow',\n 'active-data-unit-limit',\n 'incomplete-terminal-fragment',\n] as const\n\nexport type MfuReassemblyErrorCode = typeof MFU_REASSEMBLY_ERROR_CODES[number]\n\nconst mfuReassemblyErrorCodes = new Set<string>(MFU_REASSEMBLY_ERROR_CODES)\n\nexport function isMfuReassemblyErrorCode(value: unknown): value is MfuReassemblyErrorCode {\n return typeof value === 'string' && mfuReassemblyErrorCodes.has(value)\n}\n\nexport class MfuReassemblyError extends Error {\n readonly name = 'MfuReassemblyError'\n\n constructor(readonly code: MfuReassemblyErrorCode, message: string) {\n super(message)\n }\n}\n\nfunction assembledPacketSequences(fragments: readonly MFUFragment[]): {\n packetSequenceNumbers?: number[]\n repairedPacketSequenceNumbers?: number[]\n} {\n const packetSequenceNumbers: number[] = []\n const repairedPacketSequenceNumbers: number[] = []\n const seen = new Set<number>()\n const repaired = new Set<number>()\n for (const fragment of fragments) {\n const sequence = fragment.packetSequenceNumber\n if (typeof sequence !== 'number' || !Number.isSafeInteger(sequence) ||\n sequence < 0 || sequence > 0xffffffff) {\n return {}\n }\n if (!seen.has(sequence)) {\n seen.add(sequence)\n packetSequenceNumbers.push(sequence)\n }\n if (fragment.recovered === true && !repaired.has(sequence)) {\n repaired.add(sequence)\n repairedPacketSequenceNumbers.push(sequence)\n }\n }\n return {packetSequenceNumbers, repairedPacketSequenceNumbers}\n}\n\nexport interface PendingMfuDebug {\n key: string\n fragments: number\n fi0: number\n fi1: number\n fi2: number\n fi3: number\n firstFi: number\n lastFi: number\n firstOrder: number\n lastOrder: number\n minCounter: number\n maxCounter: number\n minOffset?: number\n maxOffset?: number\n movieFragmentSequenceNumber?: number\n sampleNumber?: number\n mpuSequenceNumber?: number\n sortedHead: Array<{ fi: number; counter: number; order: number; seq?: number; offset?: number }>\n sortedTail: Array<{ fi: number; counter: number; order: number; seq?: number; offset?: number }>\n}\n\nexport interface MFUReassemblerOptions {\n /** Timeout (ms) for incomplete MFUs. Derive from frame duration or FEC interleaveDepthMs.\n * Pass null for live clock-free operation; memory remains bounded by maxBuffered. */\n timeoutMs: number | null\n /** Max concurrent incomplete MFUs, including continuations awaiting FI=1. */\n maxBuffered?: number\n}\n\n/** Reassembly surface consumed by MmtpContainerParser and MmtpRouter.\n * Implemented by both the TypeScript engine and the shared\n * Rust/WASM IFC adapter. */\nexport interface MfuReassemblerBackend {\n timeoutMs: number | null\n readonly stats: ReassemblerStats\n onDeferredAssembly?: (result: ReassembledMFU) => void\n /** Returns null only for a valid incomplete DU; strict rejection throws\n * `MfuReassemblyError`. */\n addFragment(fragment: MFUFragment): ReassembledMFU | null\n flush(): void\n resetStream(catalogTrackName: string): void\n reset(): void\n readonly pendingCount: number\n getStatus(): {\n bufferedMFUs: number\n pendingFragments: number\n pendingSamples: PendingMfuDebug[]\n stats: ReassemblerStats\n }\n}\n\nfunction streamScope(fragment: MFUFragment): readonly [kind: string, identity: string | number | null] {\n if (fragment.catalogTrackName !== undefined) return ['catalog', fragment.catalogTrackName]\n if (fragment.packetId !== undefined) return ['packet', fragment.packetId]\n return ['unspecified', null]\n}\n\nfunction isU32(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 0xffffffff\n}\n\n/**\n * Producer-profile transport coordinate shared by every contiguous source\n * fragment in one data-unit run. This is association state only; objectKey\n * remains the intrinsic DU identity. ISO-permitted interleaving creates a\n * different key and therefore cannot cross-associate samples.\n */\nfunction fragmentRunKey(fragment: MFUFragment): string {\n if (!isU32(fragment.packetSequenceNumber)) {\n throw new Error('[MFUReassembler] fragmented value has no validated packet sequence')\n }\n const terminalPacketSequence =\n (fragment.packetSequenceNumber + fragment.fragmentCounter) % 0x1_0000_0000\n return JSON.stringify([\n ...streamScope(fragment),\n fragment.mpuSequenceNumber,\n terminalPacketSequence,\n ])\n}\n\nfunction hasAnySampleIdentityField(fragment: MFUFragment): boolean {\n return fragment.movieFragmentSequenceNumber !== undefined ||\n fragment.sampleNumber !== undefined || fragment.sampleOffset !== undefined\n}\n\ntype IdentifiedSampleFragment = MFUFragment & Required<Pick<\n MFUFragment,\n 'movieFragmentSequenceNumber' | 'sampleNumber' | 'sampleOffset'\n>>\n\nfunction hasSampleIdentity(fragment: MFUFragment): fragment is IdentifiedSampleFragment {\n return isU32(fragment.movieFragmentSequenceNumber) && fragment.movieFragmentSequenceNumber > 0 &&\n isU32(fragment.sampleNumber) && fragment.sampleNumber > 0 && isU32(fragment.sampleOffset)\n}\n\nfunction hasValidFragmentHeader(fragment: MFUFragment): boolean {\n const { fragmentationIndicator: fi, fragmentCounter: counter } = fragment\n if (!Number.isInteger(fi) || fi < 0 || fi > 3) return false\n if (!Number.isInteger(counter) || counter < 0 || counter > 0xff) return false\n return fi === 0 || fi === 3 ? counter === 0 : counter > 0\n}\n\nfunction fragmentCounterOrder(fragment: MFUFragment): number {\n return 0xff - fragment.fragmentCounter\n}\n\nfunction objectKey(fragment: MFUFragment): string {\n const scope = streamScope(fragment)\n if (fragment.itemId !== undefined) {\n return JSON.stringify([\n ...scope,\n fragment.mpuSequenceNumber,\n 'item',\n fragment.itemId,\n ])\n }\n if (hasSampleIdentity(fragment)) {\n return JSON.stringify([\n ...scope,\n fragment.mpuSequenceNumber,\n 'sample',\n fragment.movieFragmentSequenceNumber,\n fragment.sampleNumber,\n // The DU's authored base offset (moqcast #37): sibling subsample DUs\n // of one sample get distinct keys instead of colliding. Only ever\n // called with the unmutated FI=1 (or FI=0) fragment, whose\n // sampleOffset is that authored base -- never the accumulating\n // per-continuation value written by #associateDataUnit.\n fragment.sampleOffset,\n ])\n }\n return JSON.stringify([\n ...scope,\n fragment.mpuSequenceNumber,\n 'unidentified',\n ])\n}\n\nfunction ordersByOffset(fragments: MFUFragment[]): boolean {\n return fragments.every((fragment) => hasSampleIdentity(fragment))\n}\n\ntype ActiveDataUnit = {\n bufferKey: string\n nextFragmentCounter: number\n catalogTrackName?: string\n} & (\n | {\n kind: 'sample'\n movieFragmentSequenceNumber: number\n sampleNumber: number\n nextOffset: number\n }\n | {\n kind: 'item'\n itemId: number\n }\n)\n\ninterface DataUnitAssociation {\n bufferKey: string\n first: boolean\n terminal: boolean\n}\n\ninterface PendingContinuationRun {\n fragments: Map<number, MFUFragment>\n startedAt: number\n timeoutId?: ReturnType<typeof setTimeout>\n}\n\ninterface BufferTimeoutState {\n startedAt: number\n timeoutId?: ReturnType<typeof setTimeout>\n}\n\nfunction checkedSampleEnd(offset: number, byteLength: number): number | null {\n const end = offset + byteLength\n return Number.isSafeInteger(end) && end <= 0xffffffff ? end : null\n}\n\n/**\n * MFU Reassembler with bounded reordered-fragment association\n * Based on ISO/IEC 23008-1:2023 Section 9.2.3.3\n */\nexport class MFUReassembler {\n // Fragment buffers use only the authored MFU DU identity. Continuations are\n // admitted through bounded producer-profile runs keyed by physical stream,\n // MPU, and the wrapping terminal packet sequence. This requires contiguous\n // source-packet sequences within a fragmented DU; interleaving stays\n // separated and incomplete. Continuations may wait in a counter-indexed queue\n // until FI=1 supplies intrinsic identity; MMTP packet send time is never an\n // association key.\n #buffers: Map<string, MFUFragment[]> = new Map()\n #timeouts: Map<string, BufferTimeoutState> = new Map()\n #activeDataUnits: Map<string, ActiveDataUnit> = new Map()\n #pendingContinuations: Map<string, PendingContinuationRun> = new Map()\n #emitted: Set<string> = new Set() // same sample keys \u2014 reject FEC-recovered duplicates\n #emittedOrder: string[] = []\n #timeoutMs: number | null\n #maxBuffered: number\n\n /** Statistics for debugging */\n readonly stats: ReassemblerStats = {\n totalFragments: 0,\n reassembledMFUs: 0,\n rejectedFragments: 0,\n timedOutMFUs: 0,\n evictedMemoryLimit: 0,\n outOfOrderFragments: 0,\n }\n\n constructor(options: MFUReassemblerOptions) {\n if (options.timeoutMs !== null && (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)) {\n throw new Error('[MFUReassembler] timeoutMs must be > 0 (derive from frame duration or FEC config)')\n }\n const maxBuffered = options.maxBuffered ?? 100\n if (!Number.isInteger(maxBuffered) || maxBuffered <= 0) {\n throw new Error('[MFUReassembler] maxBuffered must be a positive integer')\n }\n this.#timeoutMs = options.timeoutMs\n this.#maxBuffered = maxBuffered\n }\n\n /** Update the expiry policy for all retained and future incomplete MFUs. */\n set timeoutMs(ms: number | null) {\n if (ms !== null && (!Number.isFinite(ms) || ms <= 0)) {\n throw new Error('[MFUReassembler] timeoutMs must be > 0 (derive from frame duration or FEC config)')\n }\n this.#timeoutMs = ms\n const now = Date.now()\n for (const [bufferKey, state] of this.#timeouts) {\n if (state.timeoutId !== undefined) clearTimeout(state.timeoutId)\n delete state.timeoutId\n if (ms !== null) {\n state.timeoutId = setTimeout(\n () => this.#onTimeout(bufferKey),\n Math.max(0, state.startedAt + ms - now),\n )\n }\n }\n for (const [runKey, pending] of this.#pendingContinuations) {\n if (pending.timeoutId !== undefined) clearTimeout(pending.timeoutId)\n delete pending.timeoutId\n if (ms !== null && !this.#activeDataUnits.has(runKey)) {\n pending.timeoutId = setTimeout(\n () => this.#onPendingTimeout(runKey),\n Math.max(0, pending.startedAt + ms - now),\n )\n }\n }\n }\n get timeoutMs(): number | null { return this.#timeoutMs }\n\n /**\n * Add a fragment and return reassembled MFU if complete\n */\n addFragment(fragment: MFUFragment): ReassembledMFU | null {\n this.stats.totalFragments++\n\n if (!hasValidFragmentHeader(fragment)) {\n this.#reject('invalid-fragment-state', 'invalid MFU fragmentation indicator or counter')\n }\n if (fragment.itemId !== undefined && hasAnySampleIdentityField(fragment)) {\n this.#reject(\n 'conflicting-data-unit-identity',\n 'MFU carries timed and non-timed DU identities',\n )\n }\n\n const { mpuSequenceNumber, fragmentationIndicator } = fragment\n\n // A complete FT=2 data unit still requires its intrinsic DU identity.\n // The transport parser strips the deterministic timed/non-timed DU header\n // before calling this layer; direct callers must provide the same identity.\n // Don't check or update #emitted: in MMTP over MoQ, multiple complete MFUs\n // share the same mpuSequenceNumber (all frames in a GOP have the same mpuSeq).\n // Blocking FI=0 would prevent keyframe fragment assembly at the same mpuSeq.\n if (fragmentationIndicator === 0) {\n const sampleIdentity = hasSampleIdentity(fragment)\n const hasSampleFields = hasAnySampleIdentityField(fragment)\n const hasItemIdentity = fragment.itemId !== undefined\n if (!sampleIdentity && !hasItemIdentity) {\n this.#reject('missing-data-unit-identity', 'complete MFU has no intrinsic DU identity')\n }\n if (hasSampleFields && !sampleIdentity) {\n this.#reject('missing-data-unit-identity', 'complete MFU has an incomplete sample identity')\n }\n if (hasItemIdentity && !isU32(fragment.itemId)) {\n this.#reject('missing-data-unit-identity', 'complete MFU has an invalid Item_ID')\n }\n this.stats.reassembledMFUs++\n return {\n mpuSequenceNumber,\n packetSequenceNumber: fragment.packetSequenceNumber,\n ...assembledPacketSequences([fragment]),\n data: fragment.data,\n timestamp: fragment.timestamp,\n fragmentCount: 1,\n rapFlag: fragment.rapFlag,\n priority: fragment.priority,\n sampleNumber: fragment.sampleNumber,\n movieFragmentSequenceNumber: fragment.movieFragmentSequenceNumber,\n sampleOffset: fragment.sampleOffset,\n source: fragment.source,\n deliveryProvenance: deliveryProvenanceOf([fragment]),\n catalogTrackName: fragment.catalogTrackName,\n }\n }\n\n if (!isU32(fragment.packetSequenceNumber)) {\n this.#reject(\n 'missing-packet-sequence',\n 'fragmented MFU has no MMTP packet sequence number',\n )\n }\n const runKey = fragmentRunKey(fragment)\n if (\n fragmentationIndicator === 1 &&\n (hasSampleIdentity(fragment) || isU32(fragment.itemId)) &&\n this.#emitted.has(objectKey(fragment))\n ) {\n this.#deletePendingRun(runKey)\n return null\n }\n\n if (fragmentationIndicator !== 1) {\n const active = this.#activeDataUnits.get(runKey)\n if (active !== undefined && fragment.fragmentCounter > active.nextFragmentCounter) {\n this.#reject(\n 'fragment-counter-mismatch',\n 'MFU continuation is behind the authored fragment-counter countdown',\n )\n }\n if (active === undefined || fragment.fragmentCounter < active.nextFragmentCounter) {\n this.#parkContinuation(runKey, fragment)\n return null\n }\n } else if (this.#activeDataUnits.has(runKey)) {\n this.#reject('overlapping-data-unit', 'fragmented MFU overlaps an active data unit')\n } else {\n const pending = this.#pendingContinuations.get(runKey)\n if (pending !== undefined && [...pending.fragments.keys()].some(\n counter => counter >= fragment.fragmentCounter,\n )) {\n this.#reject(\n 'fragment-counter-mismatch',\n 'queued continuation counter is not below the authored first-fragment counter',\n )\n }\n }\n\n const pendingStartedAt = fragmentationIndicator === 1\n ? this.#pendingContinuations.get(runKey)?.startedAt\n : undefined\n const result = this.#addAssociatedFragment(fragment, runKey, pendingStartedAt)\n if (fragmentationIndicator === 1) this.#clearPendingTimeout(runKey)\n if (result !== null) return result\n return this.#drainPendingContinuations(runKey)\n }\n\n #addAssociatedFragment(\n fragment: MFUFragment,\n runKey: string,\n startedAt?: number,\n ): ReassembledMFU | null {\n const association = this.#associateDataUnit(fragment, runKey)\n const { bufferKey, first, terminal } = association\n\n let fragments = this.#buffers.get(bufferKey)\n if (first) {\n if (fragments !== undefined) {\n this.#reject('overlapping-data-unit', 'intrinsic data-unit buffer already exists')\n }\n fragments = []\n this.#buffers.set(bufferKey, fragments)\n } else if (fragments === undefined) {\n throw new Error('[MFUReassembler] active data unit has no fragment buffer')\n }\n\n // A lossy-path deadline is measured from the first received fragment,\n // including a continuation that arrived before FI=1. Reliable paths are\n // clock-free and never install this timer.\n if (first) this.#setTimeout(bufferKey, startedAt)\n fragments.push(fragment)\n\n if (!terminal) return null\n const result = this.#tryReassemble(bufferKey)\n this.#activeDataUnits.delete(runKey)\n if (result === null) {\n this.#clearTimeout(bufferKey)\n this.#buffers.delete(bufferKey)\n this.#reject(\n 'incomplete-terminal-fragment',\n 'validated terminal fragment did not complete its data unit',\n )\n }\n return result\n }\n\n #parkContinuation(runKey: string, fragment: MFUFragment): void {\n let pending = this.#pendingContinuations.get(runKey)\n if (pending === undefined) {\n const awaitingFirst = !this.#activeDataUnits.has(runKey)\n if (awaitingFirst && this.#incompleteRunCount() >= this.#maxBuffered) {\n this.#reject('active-data-unit-limit', 'active MFU data-unit limit reached')\n }\n const startedAt = Date.now()\n pending = { fragments: new Map(), startedAt }\n if (awaitingFirst && this.#timeoutMs !== null) {\n pending.timeoutId = setTimeout(() => this.#onPendingTimeout(runKey), this.#timeoutMs)\n }\n this.#pendingContinuations.set(runKey, pending)\n }\n if (pending.fragments.has(fragment.fragmentCounter)) {\n this.#reject(\n 'fragment-counter-mismatch',\n 'duplicate queued continuation counter would replace retained media',\n )\n }\n pending.fragments.set(fragment.fragmentCounter, fragment)\n }\n\n #drainPendingContinuations(runKey: string): ReassembledMFU | null {\n while (true) {\n const active = this.#activeDataUnits.get(runKey)\n if (active === undefined) {\n this.#deletePendingRun(runKey)\n return null\n }\n const pending = this.#pendingContinuations.get(runKey)\n const fragment = pending?.fragments.get(active.nextFragmentCounter)\n if (fragment === undefined) return null\n pending!.fragments.delete(active.nextFragmentCounter)\n if (pending!.fragments.size === 0) this.#deletePendingRun(runKey)\n const result = this.#addAssociatedFragment(fragment, runKey)\n if (result !== null) {\n this.#deletePendingRun(runKey)\n return result\n }\n }\n }\n\n #incompleteRunCount(): number {\n let count = this.#activeDataUnits.size\n for (const runKey of this.#pendingContinuations.keys()) {\n if (!this.#activeDataUnits.has(runKey)) count++\n }\n return count\n }\n\n #reject(code: MfuReassemblyErrorCode, message: string): never {\n this.stats.rejectedFragments++\n throw new MfuReassemblyError(code, message)\n }\n\n #associateDataUnit(fragment: MFUFragment, runKey: string): DataUnitAssociation {\n const fi = fragment.fragmentationIndicator\n if (fi === 1) {\n if (this.#activeDataUnits.has(runKey)) {\n this.#reject('overlapping-data-unit', 'fragmented MFU overlaps an active data unit')\n }\n if (!this.#pendingContinuations.has(runKey) &&\n this.#incompleteRunCount() >= this.#maxBuffered) {\n this.#reject('active-data-unit-limit', 'active MFU data-unit limit reached')\n }\n\n const sampleIdentity = hasSampleIdentity(fragment)\n const hasSampleFields = hasAnySampleIdentityField(fragment)\n const hasItemIdentity = fragment.itemId !== undefined\n if (sampleIdentity && hasItemIdentity) {\n this.#reject(\n 'conflicting-data-unit-identity',\n 'fragmented MFU carries timed and non-timed DU identities',\n )\n }\n if (!sampleIdentity && !hasItemIdentity) {\n this.#reject('missing-data-unit-identity', 'first fragment has no intrinsic DU identity')\n }\n if (hasSampleFields && !sampleIdentity) {\n this.#reject('missing-data-unit-identity', 'first fragment has an incomplete sample identity')\n }\n if (hasItemIdentity && !isU32(fragment.itemId)) {\n this.#reject('missing-data-unit-identity', 'first fragment has an invalid Item_ID')\n }\n\n const bufferKey = objectKey(fragment)\n if (this.#buffers.has(bufferKey)) {\n this.#reject('overlapping-data-unit', 'intrinsic data-unit buffer already exists')\n }\n\n let active: ActiveDataUnit\n if (sampleIdentity) {\n const nextOffset = checkedSampleEnd(fragment.sampleOffset, fragment.data.byteLength)\n if (nextOffset === null) this.#reject('offset-overflow', 'sample byte offset overflow')\n active = {\n kind: 'sample',\n bufferKey,\n nextFragmentCounter: fragment.fragmentCounter - 1,\n movieFragmentSequenceNumber: fragment.movieFragmentSequenceNumber,\n sampleNumber: fragment.sampleNumber,\n nextOffset,\n ...(fragment.catalogTrackName === undefined\n ? {}\n : { catalogTrackName: fragment.catalogTrackName }),\n }\n } else {\n active = {\n kind: 'item',\n bufferKey,\n nextFragmentCounter: fragment.fragmentCounter - 1,\n itemId: fragment.itemId!,\n ...(fragment.catalogTrackName === undefined\n ? {}\n : { catalogTrackName: fragment.catalogTrackName }),\n }\n }\n this.#activeDataUnits.set(runKey, active)\n return { bufferKey, first: true, terminal: false }\n }\n\n const active = this.#activeDataUnits.get(runKey)\n if (active === undefined) {\n throw new Error('[MFUReassembler] continuation was not parked before association')\n }\n if (fragment.fragmentCounter !== active.nextFragmentCounter) {\n this.#reject(\n 'fragment-counter-mismatch',\n 'MFU continuation does not follow the authored fragment-counter countdown',\n )\n }\n\n if (active.kind === 'sample') {\n if (fragment.itemId !== undefined) {\n this.#reject('data-unit-identity-mismatch', 'sample continuation carries an Item_ID')\n }\n if (hasAnySampleIdentityField(fragment) && (\n !hasSampleIdentity(fragment) ||\n fragment.movieFragmentSequenceNumber !== active.movieFragmentSequenceNumber ||\n fragment.sampleNumber !== active.sampleNumber || fragment.sampleOffset !== active.nextOffset\n )) {\n this.#reject('data-unit-identity-mismatch', 'sample continuation identity does not match')\n }\n const nextOffset = checkedSampleEnd(active.nextOffset, fragment.data.byteLength)\n if (nextOffset === null) this.#reject('offset-overflow', 'sample byte offset overflow')\n fragment.movieFragmentSequenceNumber = active.movieFragmentSequenceNumber\n fragment.sampleNumber = active.sampleNumber\n fragment.sampleOffset = active.nextOffset\n if (fi === 2) {\n active.nextOffset = nextOffset\n active.nextFragmentCounter = fragment.fragmentCounter - 1\n }\n } else {\n if (hasAnySampleIdentityField(fragment) ||\n (fragment.itemId !== undefined && fragment.itemId !== active.itemId)) {\n this.#reject('data-unit-identity-mismatch', 'Item_ID continuation identity does not match')\n }\n fragment.itemId = active.itemId\n if (fi === 2) active.nextFragmentCounter = fragment.fragmentCounter - 1\n }\n\n return {\n bufferKey: active.bufferKey,\n first: false,\n terminal: fi === 3,\n }\n }\n\n #tryReassemble(bufferKey: string): ReassembledMFU | null {\n const fragments = this.#buffers.get(bufferKey)\n if (!fragments || fragments.length === 0) {\n return null\n }\n\n const sorted = [...fragments].sort((a, b) => this.#orderValue(a) - this.#orderValue(b))\n\n if (\n sorted[0]!.fragmentationIndicator !== 1 ||\n sorted[sorted.length - 1]!.fragmentationIndicator !== 3\n ) {\n return null\n }\n if (sorted.slice(1, -1).some((fragment) => fragment.fragmentationIndicator !== 2)) {\n return null\n }\n\n // ISO fragment_counter is the number of succeeding payloads. After\n // normalization (`255 - counter`), a complete non-wrapping chain is strictly\n // consecutive. This also caps a data unit at 256 payloads.\n for (let i = 1; i < sorted.length; i++) {\n if (this.#orderValue(sorted[i]!) !== this.#orderValue(sorted[i - 1]!) + 1) {\n return null\n }\n }\n\n // When every fragment carries a timed-MFU byte offset, independently prove\n // byte adjacency within this data unit. Counter order remains authoritative;\n // conflicting offsets fail closed instead of changing the fragment order.\n // sorted[0]'s offset is this DU's authored base (moqcast #37: zero for a\n // whole-sample DU, nonzero for one subsample DU of a partitioned sample) --\n // never asserted against a literal zero.\n if (ordersByOffset(sorted)) {\n for (let i = 1; i < sorted.length; i++) {\n const previous = sorted[i - 1]!\n if (\n sorted[i]!.sampleOffset !==\n previous.sampleOffset! + previous.data.byteLength\n ) {\n return null\n }\n }\n }\n\n fragments.splice(0, fragments.length, ...sorted)\n return this.#assemble(bufferKey, fragments)\n }\n\n #assemble(bufferKey: string, fragments: MFUFragment[]): ReassembledMFU {\n // Reassemble: concatenate all fragment data\n const totalSize = fragments.reduce((sum, f) => sum + f.data.length, 0)\n const data = new Uint8Array(totalSize)\n\n let offset = 0\n for (const fragment of fragments) {\n data.set(fragment.data, offset)\n offset += fragment.data.length\n }\n\n // Cleanup + mark the intrinsic identity as emitted to prevent a recovered\n // duplicate from starting another fragmented run.\n this.#clearTimeout(bufferKey)\n this.#buffers.delete(bufferKey)\n this.#markEmitted(bufferKey)\n this.stats.reassembledMFUs++\n\n return {\n mpuSequenceNumber: fragments[0]!.mpuSequenceNumber,\n packetSequenceNumber: fragments[0]!.packetSequenceNumber,\n ...assembledPacketSequences(fragments),\n data,\n timestamp: fragments[0]!.timestamp,\n fragmentCount: fragments.length,\n rapFlag: fragments[0]!.rapFlag,\n priority: fragments.find((f) => f.priority !== undefined)?.priority,\n sampleNumber: fragments[0]!.sampleNumber,\n movieFragmentSequenceNumber: fragments[0]!.movieFragmentSequenceNumber,\n sampleOffset: fragments[0]!.sampleOffset,\n source: fragments[0]!.source,\n deliveryProvenance: deliveryProvenanceOf(fragments),\n catalogTrackName: fragments[0]!.catalogTrackName,\n }\n }\n\n #setTimeout(bufferKey: string, startedAt = Date.now()): void {\n const state: BufferTimeoutState = { startedAt }\n if (this.#timeoutMs !== null) {\n state.timeoutId = setTimeout(\n () => this.#onTimeout(bufferKey),\n Math.max(0, startedAt + this.#timeoutMs - Date.now()),\n )\n }\n this.#timeouts.set(bufferKey, state)\n }\n\n #clearPendingTimeout(runKey: string): void {\n const pending = this.#pendingContinuations.get(runKey)\n if (pending?.timeoutId !== undefined) clearTimeout(pending.timeoutId)\n if (pending !== undefined) {\n delete pending.timeoutId\n }\n }\n\n #deletePendingRun(runKey: string): void {\n this.#clearPendingTimeout(runKey)\n this.#pendingContinuations.delete(runKey)\n }\n\n #onPendingTimeout(runKey: string): void {\n const pending = this.#pendingContinuations.get(runKey)\n if (pending === undefined) return\n this.stats.timedOutMFUs++\n console.warn(\n `[MfuReassembler] timeout: run=${runKey} fragments=${pending.fragments.size} ` +\n '(continuations awaiting first fragment, discarded)',\n )\n this.#pendingContinuations.delete(runKey)\n }\n\n #clearTimeout(bufferKey: string): void {\n const state = this.#timeouts.get(bufferKey)\n if (state !== undefined) {\n if (state.timeoutId !== undefined) clearTimeout(state.timeoutId)\n this.#timeouts.delete(bufferKey)\n }\n }\n\n /** Callback for deferred assembly results (set by caller for async frame delivery) */\n onDeferredAssembly?: (result: ReassembledMFU) => void\n\n #markEmitted(bufferKey: string): void {\n if (this.#emitted.has(bufferKey)) return\n this.#emitted.add(bufferKey)\n this.#emittedOrder.push(bufferKey)\n while (this.#emittedOrder.length > this.#maxBuffered) {\n const oldest = this.#emittedOrder.shift()\n if (oldest !== undefined) this.#emitted.delete(oldest)\n }\n }\n\n #orderValue(fragment: MFUFragment): number {\n return fragmentCounterOrder(fragment)\n }\n\n #removeActiveDataUnitForBuffer(bufferKey: string): void {\n for (const [runKey, active] of this.#activeDataUnits) {\n if (active.bufferKey === bufferKey) {\n this.#activeDataUnits.delete(runKey)\n this.#deletePendingRun(runKey)\n }\n }\n }\n\n #onTimeout(bufferKey: string): void {\n const fragments = this.#buffers.get(bufferKey)\n if (!fragments || fragments.length === 0) {\n this.#buffers.delete(bufferKey)\n this.#timeouts.delete(bufferKey)\n this.#removeActiveDataUnitForBuffer(bufferKey)\n this.stats.timedOutMFUs++\n console.warn(`[MfuReassembler] timeout: key=${bufferKey} fragments=0 (no data buffered)`)\n return\n }\n\n // Discard partial MFUs \u2014 incomplete AVCC data crashes WebCodecs with\n // \"Unable to determine size of bitstream buffer\". FEC recovery handles\n // loss; partial assembly only produces garbage frames.\n this.stats.timedOutMFUs++\n console.warn(\n `[MfuReassembler] timeout: key=${bufferKey} fragments=${fragments.length} (partial, discarded)`,\n )\n\n this.#buffers.delete(bufferKey)\n this.#timeouts.delete(bufferKey)\n this.#removeActiveDataUnitForBuffer(bufferKey)\n }\n\n /**\n * Flush all buffered fragments\n */\n flush(): void {\n for (const key of this.#buffers.keys()) {\n this.#clearTimeout(key)\n }\n this.#buffers.clear()\n this.#timeouts.clear()\n this.#activeDataUnits.clear()\n for (const runKey of this.#pendingContinuations.keys()) {\n this.#clearPendingTimeout(runKey)\n }\n this.#pendingContinuations.clear()\n this.#emitted.clear()\n this.#emittedOrder.length = 0\n }\n\n /** Drop one catalog stream's incomplete and dedup state. */\n resetStream(catalogTrackName: string): void {\n const belongsToStream = (key: string): boolean => {\n try {\n const decoded = JSON.parse(key)\n return Array.isArray(decoded) && decoded[0] === 'catalog' && decoded[1] === catalogTrackName\n } catch {\n return false\n }\n }\n const discarded = new Set<string>()\n for (const [key, fragments] of this.#buffers) {\n if (fragments.some((fragment) => fragment.catalogTrackName === catalogTrackName)) {\n discarded.add(key)\n }\n }\n for (const [runKey, active] of this.#activeDataUnits) {\n if (active.catalogTrackName === catalogTrackName) {\n discarded.add(active.bufferKey)\n this.#activeDataUnits.delete(runKey)\n }\n }\n for (const [runKey, pending] of this.#pendingContinuations) {\n if ([...pending.fragments.values()].some(\n fragment => fragment.catalogTrackName === catalogTrackName,\n )) {\n this.#deletePendingRun(runKey)\n }\n }\n for (const key of this.#emitted) {\n if (belongsToStream(key)) discarded.add(key)\n }\n for (const key of discarded) {\n this.#clearTimeout(key)\n this.#buffers.delete(key)\n this.#emitted.delete(key)\n }\n this.#emittedOrder = this.#emittedOrder.filter((key) => !discarded.has(key))\n }\n\n /** Reset all state \u2014 flush buffers and zero stats */\n reset(): void {\n this.flush()\n this.stats.totalFragments = 0\n this.stats.reassembledMFUs = 0\n this.stats.rejectedFragments = 0\n this.stats.timedOutMFUs = 0\n this.stats.evictedMemoryLimit = 0\n this.stats.outOfOrderFragments = 0\n }\n\n /**\n * Get number of pending MFUs\n */\n get pendingCount(): number {\n let count = this.#buffers.size\n for (const runKey of this.#pendingContinuations.keys()) {\n if (!this.#activeDataUnits.has(runKey)) count++\n }\n return count\n }\n\n /**\n * Get current buffer status\n */\n getStatus(): {\n bufferedMFUs: number\n pendingFragments: number\n pendingSamples: PendingMfuDebug[]\n stats: ReassemblerStats\n } {\n let pendingFragments = 0\n for (const fragments of this.#buffers.values()) {\n pendingFragments += fragments.length\n }\n for (const pending of this.#pendingContinuations.values()) {\n pendingFragments += pending.fragments.size\n }\n\n return {\n bufferedMFUs: this.pendingCount,\n pendingFragments,\n pendingSamples: this.#pendingDebugSamples(),\n stats: { ...this.stats },\n }\n }\n\n #pendingDebugSamples(): PendingMfuDebug[] {\n const out: PendingMfuDebug[] = []\n for (const [key, fragments] of this.#buffers) {\n if (fragments.length === 0) continue\n const sorted = [...fragments].sort((a, b) => this.#orderValue(a) - this.#orderValue(b))\n const fiCounts = [0, 0, 0, 0]\n let minCounter = Infinity\n let maxCounter = -Infinity\n let minOffset = Infinity\n let maxOffset = -Infinity\n for (const fragment of sorted) {\n fiCounts[fragment.fragmentationIndicator] =\n (fiCounts[fragment.fragmentationIndicator] ?? 0) + 1\n minCounter = Math.min(minCounter, fragment.fragmentCounter)\n maxCounter = Math.max(maxCounter, fragment.fragmentCounter)\n if (typeof fragment.sampleOffset === 'number') {\n minOffset = Math.min(minOffset, fragment.sampleOffset)\n maxOffset = Math.max(maxOffset, fragment.sampleOffset)\n }\n }\n const point = (fragment: MFUFragment) => ({\n fi: fragment.fragmentationIndicator,\n counter: fragment.fragmentCounter,\n order: this.#orderValue(fragment),\n ...(typeof fragment.packetSequenceNumber === 'number' ? { seq: fragment.packetSequenceNumber } : {}),\n ...(typeof fragment.sampleOffset === 'number' ? { offset: fragment.sampleOffset } : {}),\n })\n const summary: PendingMfuDebug = {\n key,\n fragments: sorted.length,\n fi0: fiCounts[0] ?? 0,\n fi1: fiCounts[1] ?? 0,\n fi2: fiCounts[2] ?? 0,\n fi3: fiCounts[3] ?? 0,\n firstFi: sorted[0]!.fragmentationIndicator,\n lastFi: sorted[sorted.length - 1]!.fragmentationIndicator,\n firstOrder: this.#orderValue(sorted[0]!),\n lastOrder: this.#orderValue(sorted[sorted.length - 1]!),\n minCounter,\n maxCounter,\n movieFragmentSequenceNumber: sorted.find((f) => f.movieFragmentSequenceNumber !== undefined)\n ?.movieFragmentSequenceNumber,\n sampleNumber: sorted.find((f) => f.sampleNumber !== undefined)?.sampleNumber,\n mpuSequenceNumber: sorted[0]!.mpuSequenceNumber,\n sortedHead: sorted.slice(0, 6).map(point),\n sortedTail: sorted.slice(-6).map(point),\n }\n if (minOffset !== Infinity) summary.minOffset = minOffset\n if (maxOffset !== -Infinity) summary.maxOffset = maxOffset\n out.push(summary)\n if (out.length >= 12) break\n }\n return out\n }\n}\n\n/**\n * Create MFU fragment from MMTP packet for reassembly\n */\nexport function createFragment(mmtpPacket: Uint8Array): MFUFragment {\n const extraction = extractMFUPayload(mmtpPacket)\n if (!extraction) throw new Error('Unable to extract MFU payload from MMTP packet')\n const { header, mpu, data, mfuDuHeader, itemId } = extraction\n\n return {\n fragmentationIndicator: mpu.fragmentationIndicator,\n mpuSequenceNumber: mpu.mpuSequenceNumber,\n fragmentCounter: mpu.fragmentCounter,\n data,\n timestamp: header.timestamp,\n rapFlag: header.rapFlag,\n sampleNumber: mfuDuHeader?.sampleNumber,\n movieFragmentSequenceNumber: mfuDuHeader?.movieFragmentSequenceNumber,\n sampleOffset: mfuDuHeader?.offset,\n priority: mfuDuHeader?.priority,\n itemId: itemId ?? undefined,\n packetSequenceNumber: header.sequenceNumber,\n packetId: header.packetId,\n }\n}\n\n/**\n * Process MMTP packet with fragment reassembly\n */\nexport function processMMTPWithReassembly(\n mmtpPacket: Uint8Array,\n reassembler: MFUReassembler,\n): ReassembledMFU | null {\n // Skip FEC repair packets\n if (isFecRepairPacket(mmtpPacket)) {\n return null\n }\n\n const fragment = createFragment(mmtpPacket)\n return reassembler.addFragment(fragment)\n}\n\n// =============================================================================\n// Inline Tests (vitest)\n// =============================================================================\n\nif (import.meta.vitest) {\n const { describe, test, expect, vi } = import.meta.vitest\n\n const expectRejection = (call: () => unknown, code: MfuReassemblyErrorCode): void => {\n let rejection: unknown\n try {\n call()\n } catch (error) {\n rejection = error\n }\n expect(rejection).toBeInstanceOf(MfuReassemblyError)\n expect((rejection as MfuReassemblyError).code).toBe(code)\n }\n\n const testPacketSequence = (mpu: number, counter: number, run = 0): number =>\n (mpu * 1000 + run - counter + 0x1_0000_0000) % 0x1_0000_0000\n\n describe('MFUReassembler', () => {\n test('should return complete MFU for FI=0', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const result = reassembler.addFragment({\n fragmentationIndicator: 0,\n mpuSequenceNumber: 1,\n fragmentCounter: 0,\n itemId: 1,\n data: new Uint8Array([1, 2, 3, 4]),\n timestamp: 1000n,\n\n rapFlag: true,\n })\n expect(result).not.toBeNull()\n expect(result?.data).toEqual(new Uint8Array([1, 2, 3, 4]))\n expect(result?.fragmentCount).toBe(1)\n expect(result?.rapFlag).toBe(true)\n })\n\n test('rejects a complete MFU without a valid sample identity', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const complete = (identity: Partial<MFUFragment>): MFUFragment => ({\n fragmentationIndicator: 0,\n mpuSequenceNumber: 1,\n fragmentCounter: 0,\n data: new Uint8Array([1]),\n timestamp: 1000n,\n rapFlag: true,\n ...identity,\n })\n expectRejection(\n () => reassembler.addFragment(complete({})),\n 'missing-data-unit-identity',\n )\n expectRejection(\n () => reassembler.addFragment(complete({\n movieFragmentSequenceNumber: 2,\n sampleNumber: 1,\n })),\n 'missing-data-unit-identity',\n )\n })\n\n test('accepts a complete subsample MFU with a nonzero authored offset', () => {\n // moqcast #37: a subsample DU's offset is its authored base byte\n // position within the sample -- nonzero identifies one subsample DU\n // among siblings partitioning an oversized sample.\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const result = reassembler.addFragment({\n fragmentationIndicator: 0,\n mpuSequenceNumber: 1,\n fragmentCounter: 0,\n movieFragmentSequenceNumber: 2,\n sampleNumber: 1,\n sampleOffset: 4,\n data: new Uint8Array([1]),\n timestamp: 1000n,\n rapFlag: true,\n })\n expect(result).not.toBeNull()\n expect(result?.sampleOffset).toBe(4)\n })\n\n test('accepts a fragmented subsample DU whose first fragment has a nonzero authored offset', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 2,\n fragmentCounter: 1,\n movieFragmentSequenceNumber: 2,\n sampleNumber: 1,\n sampleOffset: 4,\n packetSequenceNumber: testPacketSequence(2, 1),\n data: new Uint8Array([0xa1]),\n timestamp: 1000n,\n rapFlag: true,\n })).toBeNull()\n expect(reassembler.pendingCount).toBe(1)\n expect(reassembler.getStatus().pendingFragments).toBe(1)\n\n const out = reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 2,\n fragmentCounter: 0,\n data: new Uint8Array([0xa2]),\n timestamp: 1001n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(2, 0),\n })\n expect(out?.data).toEqual(new Uint8Array([0xa1, 0xa2]))\n expect(out?.sampleOffset).toBe(4)\n })\n\n test('sibling subsample DUs of one sample reassemble independently by offset', () => {\n // moqcast #37: each subsample DU of a partitioned sample runs its own\n // FI chain and gets its own buffer, keyed in part by its authored base\n // offset -- distinct from a sibling DU sharing (movie, sample).\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n expect(reassembler.addFragment({\n mpuSequenceNumber: 3,\n movieFragmentSequenceNumber: 5,\n sampleNumber: 9,\n fragmentationIndicator: 1,\n fragmentCounter: 1,\n sampleOffset: 0,\n data: new Uint8Array([0xa1]),\n timestamp: 2000n,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(3, 1, 0),\n })).toBeNull()\n expect(reassembler.addFragment({\n mpuSequenceNumber: 3,\n movieFragmentSequenceNumber: 5,\n sampleNumber: 9,\n fragmentationIndicator: 1,\n fragmentCounter: 1,\n sampleOffset: 3,\n data: new Uint8Array([0xb1]),\n timestamp: 2001n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(3, 1, 1),\n })).toBeNull()\n expect(reassembler.pendingCount).toBe(2)\n\n const first = reassembler.addFragment({\n mpuSequenceNumber: 3,\n fragmentationIndicator: 3,\n fragmentCounter: 0,\n data: new Uint8Array([0xa2]),\n timestamp: 2000n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(3, 0, 0),\n })\n expect(first?.data).toEqual(new Uint8Array([0xa1, 0xa2]))\n expect(first?.sampleOffset).toBe(0)\n\n const second = reassembler.addFragment({\n mpuSequenceNumber: 3,\n fragmentationIndicator: 3,\n fragmentCounter: 0,\n data: new Uint8Array([0xb2]),\n timestamp: 2001n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(3, 0, 1),\n })\n expect(second?.data).toEqual(new Uint8Array([0xb1, 0xb2]))\n expect(second?.sampleOffset).toBe(3)\n expect(reassembler.pendingCount).toBe(0)\n })\n\n test('isolates colliding fragment coordinates by catalog track identity', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const fragment = (\n catalogTrackName: string,\n fragmentationIndicator: number,\n fragmentCounter: number,\n byte: number,\n ): MFUFragment => ({\n itemId: 1,\n fragmentationIndicator,\n fragmentCounter,\n mpuSequenceNumber: 1,\n data: new Uint8Array([byte]),\n timestamp: 1000n,\n rapFlag: fragmentationIndicator === 1,\n catalogTrackName,\n packetSequenceNumber: testPacketSequence(1, fragmentCounter),\n })\n\n expect(reassembler.addFragment(fragment('video/720p', 1, 1, 0x71))).toBeNull()\n expect(reassembler.addFragment(fragment('video/540p', 1, 1, 0x51))).toBeNull()\n const high = reassembler.addFragment(fragment('video/720p', 3, 0, 0x72))\n const low = reassembler.addFragment(fragment('video/540p', 3, 0, 0x52))\n\n expect(high?.data).toEqual(new Uint8Array([0x71, 0x72]))\n expect(high?.catalogTrackName).toBe('video/720p')\n expect(low?.data).toEqual(new Uint8Array([0x51, 0x52]))\n expect(low?.catalogTrackName).toBe('video/540p')\n })\n\n test('rejects an overlapping non-timed item without replacing the active run', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const fragment = (\n itemId: number,\n fragmentationIndicator: number,\n fragmentCounter: number,\n byte: number,\n ): MFUFragment => ({\n itemId,\n fragmentationIndicator,\n fragmentCounter,\n mpuSequenceNumber: 1,\n data: new Uint8Array([byte]),\n timestamp: 1000n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, fragmentCounter),\n })\n\n expect(reassembler.addFragment(fragment(10, 1, 1, 0x10))).toBeNull()\n expectRejection(\n () => reassembler.addFragment(fragment(20, 1, 1, 0x20)),\n 'overlapping-data-unit',\n )\n expect(reassembler.pendingCount).toBe(1)\n expect(reassembler.addFragment(fragment(10, 3, 0, 0x11))?.data)\n .toEqual(new Uint8Array([0x10, 0x11]))\n expect(reassembler.pendingCount).toBe(0)\n })\n\n test('associates continuations by authored state when packet timestamps change', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const fragment = (\n itemId: number | undefined,\n fragmentationIndicator: number,\n fragmentCounter: number,\n byte: number,\n timestamp: bigint,\n ): MFUFragment => ({\n ...(itemId === undefined ? {} : { itemId }),\n fragmentationIndicator,\n fragmentCounter,\n mpuSequenceNumber: 1,\n data: new Uint8Array([byte]),\n timestamp,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, fragmentCounter),\n })\n\n expect(reassembler.addFragment(fragment(10, 1, 2, 0x10, 1000n))).toBeNull()\n expect(reassembler.addFragment(fragment(undefined, 2, 1, 0x11, 1001n))).toBeNull()\n const out = reassembler.addFragment(fragment(undefined, 3, 0, 0x12, 1002n))\n expect(out?.data).toEqual(new Uint8Array([0x10, 0x11, 0x12]))\n expect(out?.timestamp).toBe(1000n)\n })\n\n test('should buffer and reassemble 2 fragments', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n // First fragment (FI=1)\n const result1 = reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 1,\n fragmentCounter: 1,\n itemId: 1,\n data: new Uint8Array([1, 2]),\n timestamp: 1000n,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(1, 1),\n })\n expect(result1).toBeNull()\n\n // Last fragment (FI=3)\n const result2 = reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 1,\n fragmentCounter: 0,\n data: new Uint8Array([3, 4]),\n timestamp: 1000n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 0),\n })\n expect(result2).not.toBeNull()\n expect(result2?.data).toEqual(new Uint8Array([1, 2, 3, 4]))\n expect(result2?.fragmentCount).toBe(2)\n expect(result2?.rapFlag).toBe(true) // Should use first fragment's rapFlag\n })\n\n test('buffers a terminal continuation until its authored first fragment arrives', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n // Last fragment first (FI=3)\n expect(reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 1,\n fragmentCounter: 0,\n data: new Uint8Array([3, 4]),\n timestamp: 1000n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 0),\n })).toBeNull()\n expect(reassembler.pendingCount).toBe(1)\n\n // Then first fragment (FI=1)\n const completed = reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 1,\n fragmentCounter: 1,\n itemId: 1,\n data: new Uint8Array([1, 2]),\n timestamp: 1000n,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(1, 1),\n })\n\n expect(completed?.data).toEqual(new Uint8Array([1, 2, 3, 4]))\n expect(completed?.rapFlag).toBe(true)\n expect(reassembler.pendingCount).toBe(0)\n })\n\n test('clock-free mode keeps an admitted MFU until completion', async () => {\n const reassembler = new MFUReassembler({ timeoutMs: null })\n\n reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 1,\n fragmentCounter: 1,\n itemId: 1,\n data: new Uint8Array([1, 2]),\n timestamp: 1000n,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(1, 1),\n })\n\n await new Promise(resolve => setTimeout(resolve, 5))\n\n const result = reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 1,\n fragmentCounter: 0,\n data: new Uint8Array([3, 4]),\n timestamp: 1000n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 0),\n })\n\n expect(result).not.toBeNull()\n expect(result?.data).toEqual(new Uint8Array([1, 2, 3, 4]))\n expect(reassembler.stats.timedOutMFUs).toBe(0)\n })\n\n test('should track pending count', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n expect(reassembler.pendingCount).toBe(0)\n\n reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 1,\n fragmentCounter: 1,\n itemId: 1,\n data: new Uint8Array([1]),\n timestamp: 1000n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 1),\n })\n expect(reassembler.pendingCount).toBe(1)\n\n reassembler.flush()\n expect(reassembler.pendingCount).toBe(0)\n })\n\n test('should reassemble 3 fragments (FI=1, FI=2, FI=3)', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n // First fragment\n expect(reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 10,\n fragmentCounter: 2, itemId: 1, data: new Uint8Array([0xAA, 0xBB]),\n timestamp: 5000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(10, 2),\n })).toBeNull()\n\n // Middle fragment\n expect(reassembler.addFragment({\n fragmentationIndicator: 2, mpuSequenceNumber: 10,\n fragmentCounter: 1, data: new Uint8Array([0xCC, 0xDD]),\n timestamp: 5000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(10, 1),\n })).toBeNull()\n\n // Last fragment \u2014 triggers reassembly\n const result = reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 10,\n fragmentCounter: 0, data: new Uint8Array([0xEE, 0xFF]),\n timestamp: 5000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(10, 0),\n })\n\n expect(result).not.toBeNull()\n expect(result!.data).toEqual(new Uint8Array([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]))\n expect(result!.fragmentCount).toBe(3)\n expect(result!.rapFlag).toBe(true) // from first fragment\n expect(result!.mpuSequenceNumber).toBe(10)\n })\n\n test('should handle interleaved MPU sequences', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n // MPU 1: first fragment\n reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 1,\n fragmentCounter: 1, itemId: 1, data: new Uint8Array([0x01]),\n timestamp: 100n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 1),\n })\n // MPU 2: complete (FI=0)\n const r2 = reassembler.addFragment({\n fragmentationIndicator: 0, mpuSequenceNumber: 2,\n fragmentCounter: 0, itemId: 2, data: new Uint8Array([0x02]),\n timestamp: 200n, rapFlag: false,\n })\n expect(r2).not.toBeNull()\n expect(r2!.mpuSequenceNumber).toBe(2)\n\n // MPU 1: last fragment\n const r1 = reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 1,\n fragmentCounter: 0, data: new Uint8Array([0x03]),\n timestamp: 100n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 0),\n })\n expect(r1).not.toBeNull()\n expect(r1!.data).toEqual(new Uint8Array([0x01, 0x03]))\n })\n\n test('rejects overlapping fragmented MFUs sharing one stream and MPU', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const mpuSeq = 5\n\n expect(\n reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: mpuSeq,\n fragmentCounter: 1, itemId: 10,\n data: new Uint8Array([0xa1]), timestamp: 100n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(mpuSeq, 1),\n }),\n ).toBeNull()\n expectRejection(\n () => reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: mpuSeq,\n fragmentCounter: 1, itemId: 20,\n data: new Uint8Array([0xb1]), timestamp: 200n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(mpuSeq, 1),\n }),\n 'overlapping-data-unit',\n )\n expect(reassembler.pendingCount).toBe(1)\n\n const a = reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: mpuSeq,\n fragmentCounter: 0, data: new Uint8Array([0xa2]), timestamp: 101n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(mpuSeq, 0),\n })\n expect(a).not.toBeNull()\n expect(a!.data).toEqual(new Uint8Array([0xa1, 0xa2]))\n expect(a!.rapFlag).toBe(true) // from A's first fragment\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: mpuSeq,\n fragmentCounter: 1, itemId: 20,\n data: new Uint8Array([0xb1]), timestamp: 200n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(mpuSeq, 1, 10),\n })).toBeNull()\n const b = reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: mpuSeq,\n fragmentCounter: 0, data: new Uint8Array([0xb2]), timestamp: 201n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(mpuSeq, 0, 10),\n })\n expect(b).not.toBeNull()\n expect(b!.data).toEqual(new Uint8Array([0xb1, 0xb2]))\n })\n\n test('reassembles FFmpeg timed MFU fragments by sample number and byte offset', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const common = {\n mpuSequenceNumber: 0,\n movieFragmentSequenceNumber: 9,\n sampleNumber: 17,\n }\n\n expect(reassembler.addFragment({\n ...common,\n fragmentationIndicator: 1,\n fragmentCounter: 2,\n sampleOffset: 0,\n data: new Uint8Array([0xa1]),\n timestamp: 1000n,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(0, 2),\n })).toBeNull()\n expect(reassembler.addFragment({\n ...common,\n fragmentationIndicator: 2,\n fragmentCounter: 1,\n sampleOffset: 1,\n data: new Uint8Array([0xb2]),\n timestamp: 1001n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(0, 1),\n })).toBeNull()\n const out = reassembler.addFragment({\n ...common,\n fragmentationIndicator: 3,\n fragmentCounter: 0,\n sampleOffset: 2,\n data: new Uint8Array([0xc3]),\n timestamp: 1002n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(0, 0),\n })\n\n expect(out).not.toBeNull()\n expect(out!.data).toEqual(new Uint8Array([0xa1, 0xb2, 0xc3]))\n expect(out!.timestamp).toBe(1000n)\n expect(out!.sampleNumber).toBe(17)\n expect(out!.movieFragmentSequenceNumber).toBe(9)\n })\n\n test('buffers a counter gap without advancing the active data unit', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const common = {\n mpuSequenceNumber: 0,\n movieFragmentSequenceNumber: 9,\n sampleNumber: 17,\n timestamp: 1000n,\n rapFlag: true,\n }\n\n expect(reassembler.addFragment({\n ...common,\n fragmentationIndicator: 1,\n fragmentCounter: 2,\n sampleOffset: 0,\n data: new Uint8Array([0xa1, 0xa2]),\n packetSequenceNumber: testPacketSequence(0, 2),\n })).toBeNull()\n expect(reassembler.addFragment({\n ...common,\n fragmentationIndicator: 3,\n fragmentCounter: 0,\n sampleOffset: 4,\n data: new Uint8Array([0xc1, 0xc2]),\n packetSequenceNumber: testPacketSequence(0, 0),\n })).toBeNull()\n expect(reassembler.pendingCount).toBe(1)\n\n const out = reassembler.addFragment({\n ...common,\n fragmentationIndicator: 2,\n fragmentCounter: 1,\n sampleOffset: 2,\n data: new Uint8Array([0xb1, 0xb2]),\n packetSequenceNumber: testPacketSequence(0, 1),\n })\n expect(out?.data).toEqual(\n new Uint8Array([0xa1, 0xa2, 0xb1, 0xb2, 0xc1, 0xc2]),\n )\n })\n\n test('reassembles first-only DU-header fragments across changing packet timestamps', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 44,\n fragmentCounter: 2,\n movieFragmentSequenceNumber: 9,\n sampleNumber: 17,\n sampleOffset: 0,\n data: new Uint8Array([0xa1]),\n timestamp: 12345n,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(44, 2),\n })).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 2,\n mpuSequenceNumber: 44,\n fragmentCounter: 1,\n data: new Uint8Array([0xb2]),\n timestamp: 12346n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(44, 1),\n })).toBeNull()\n const out = reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 44,\n fragmentCounter: 0,\n data: new Uint8Array([0xc3]),\n timestamp: 12347n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(44, 0),\n })\n\n expect(out).not.toBeNull()\n expect(out!.data).toEqual(new Uint8Array([0xa1, 0xb2, 0xc3]))\n expect(out!.timestamp).toBe(12345n)\n expect(out!.sampleNumber).toBe(17)\n expect(out!.movieFragmentSequenceNumber).toBe(9)\n })\n\n test('reassembles first-only DU-header fragments with an ISO countdown', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const timestamp = 12345n\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 44,\n fragmentCounter: 3,\n movieFragmentSequenceNumber: 9,\n sampleNumber: 17,\n sampleOffset: 0,\n data: new Uint8Array([0xa1]),\n timestamp,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(44, 3),\n })).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 2,\n mpuSequenceNumber: 44,\n fragmentCounter: 2,\n data: new Uint8Array([0xb2]),\n timestamp,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(44, 2),\n })).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 2,\n mpuSequenceNumber: 44,\n fragmentCounter: 1,\n data: new Uint8Array([0xc3]),\n timestamp,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(44, 1),\n })).toBeNull()\n const out = reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 44,\n fragmentCounter: 0,\n data: new Uint8Array([0xd4]),\n timestamp,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(44, 0),\n })\n\n expect(out).not.toBeNull()\n expect(out!.data).toEqual(new Uint8Array([0xa1, 0xb2, 0xc3, 0xd4]))\n expect(out!.sampleNumber).toBe(17)\n expect(out!.movieFragmentSequenceNumber).toBe(9)\n })\n\n test('rejects fragmented MFUs without an authored DU identity', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const timestamp = 22222n\n\n expectRejection(() => reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 55,\n fragmentCounter: 2,\n data: new Uint8Array([0xa1]),\n timestamp,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(55, 2),\n }), 'missing-data-unit-identity')\n expect(reassembler.pendingCount).toBe(0)\n })\n\n test('rejects fragmented MFUs without an authored packet sequence', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n expectRejection(() => reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 55,\n fragmentCounter: 1,\n itemId: 1,\n data: new Uint8Array([0xa1]),\n timestamp: 22222n,\n rapFlag: true,\n }), 'missing-packet-sequence')\n expect(reassembler.pendingCount).toBe(0)\n })\n\n test('rejects fragmented MFUs whose authored packet sequence is not u32', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n for (const packetSequenceNumber of [-1, 0x1_0000_0000, 1.5, Number.NaN]) {\n expectRejection(() => reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 55,\n fragmentCounter: 1,\n itemId: 1,\n data: new Uint8Array([0xa1]),\n timestamp: 22222n,\n rapFlag: true,\n packetSequenceNumber,\n }), 'missing-packet-sequence')\n }\n expect(reassembler.pendingCount).toBe(0)\n })\n\n test('fails closed when one fragmented DU has interleaved packet sequence gaps', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const timestamp = 66666n\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 80,\n fragmentCounter: 17,\n movieFragmentSequenceNumber: 241,\n sampleNumber: 1,\n sampleOffset: 0,\n packetSequenceNumber: 1000,\n data: new Uint8Array([0xa0]),\n timestamp,\n rapFlag: true,\n })).toBeNull()\n\n for (let i = 1; i < 17; i++) {\n expect(reassembler.addFragment({\n fragmentationIndicator: 2,\n mpuSequenceNumber: 80,\n fragmentCounter: 17 - i,\n packetSequenceNumber: 1000 + i * 2,\n data: new Uint8Array([0xa0 + i]),\n timestamp,\n rapFlag: false,\n })).toBeNull()\n }\n\n const out = reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 80,\n fragmentCounter: 0,\n packetSequenceNumber: 1040,\n data: new Uint8Array([0xb1]),\n timestamp,\n rapFlag: false,\n })\n\n expect(out).toBeNull()\n expect(reassembler.pendingCount).toBe(18)\n expect(reassembler.stats.reassembledMFUs).toBe(0)\n })\n\n test('does not combine adjacent reordered MFUs in one MPU', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const common = { mpuSequenceNumber: 80, packetId: 7, timestamp: 66666n }\n\n expect(reassembler.addFragment({\n ...common,\n fragmentationIndicator: 3,\n fragmentCounter: 0,\n packetSequenceNumber: 103,\n data: new Uint8Array([0xb2]),\n rapFlag: false,\n })).toBeNull()\n expect(reassembler.addFragment({\n ...common,\n fragmentationIndicator: 1,\n fragmentCounter: 1,\n packetSequenceNumber: 100,\n movieFragmentSequenceNumber: 241,\n sampleNumber: 1,\n sampleOffset: 0,\n data: new Uint8Array([0xa1]),\n rapFlag: true,\n })).toBeNull()\n\n const earlier = reassembler.addFragment({\n ...common,\n fragmentationIndicator: 3,\n fragmentCounter: 0,\n packetSequenceNumber: 101,\n data: new Uint8Array([0xa2]),\n rapFlag: false,\n })\n expect(earlier?.data).toEqual(new Uint8Array([0xa1, 0xa2]))\n\n const later = reassembler.addFragment({\n ...common,\n fragmentationIndicator: 1,\n fragmentCounter: 1,\n packetSequenceNumber: 102,\n movieFragmentSequenceNumber: 241,\n sampleNumber: 2,\n sampleOffset: 0,\n data: new Uint8Array([0xb1]),\n rapFlag: false,\n })\n expect(later?.data).toEqual(new Uint8Array([0xb1, 0xb2]))\n })\n\n test('wraps the fragmented run coordinate at u32 packet sequence', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n expect(reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 81,\n fragmentCounter: 1,\n packetSequenceNumber: 0xffffffff,\n itemId: 1,\n data: new Uint8Array([0xa1]),\n timestamp: 66666n,\n rapFlag: true,\n })).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 81,\n fragmentCounter: 0,\n packetSequenceNumber: 0,\n data: new Uint8Array([0xa2]),\n timestamp: 66667n,\n rapFlag: false,\n })?.data).toEqual(new Uint8Array([0xa1, 0xa2]))\n })\n\n test('dedupes recovered copies by ISO fragment-counter position', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const timestamp = 44444n\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 77,\n fragmentCounter: 2,\n movieFragmentSequenceNumber: 12,\n sampleNumber: 1,\n sampleOffset: 0,\n packetSequenceNumber: 2000,\n data: new Uint8Array([0xa1]),\n timestamp,\n rapFlag: true,\n })).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 2,\n mpuSequenceNumber: 77,\n fragmentCounter: 1,\n packetSequenceNumber: 2001,\n data: new Uint8Array([0xb2]),\n timestamp,\n rapFlag: false,\n })).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 77,\n fragmentCounter: 0,\n packetSequenceNumber: 2002,\n data: new Uint8Array([0xc3]),\n timestamp,\n rapFlag: false,\n })).not.toBeNull()\n\n reassembler.flush()\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 78,\n fragmentCounter: 2,\n movieFragmentSequenceNumber: 13,\n sampleNumber: 1,\n sampleOffset: 0,\n packetSequenceNumber: 3000,\n data: new Uint8Array([0xd4]),\n timestamp,\n rapFlag: true,\n })).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 2,\n mpuSequenceNumber: 78,\n fragmentCounter: 1,\n packetSequenceNumber: 3001,\n data: new Uint8Array([0xe5]),\n timestamp,\n rapFlag: false,\n })).toBeNull()\n expectRejection(() => reassembler.addFragment({\n fragmentationIndicator: 2,\n mpuSequenceNumber: 78,\n fragmentCounter: 1,\n packetSequenceNumber: 3001,\n data: new Uint8Array([0xe5]),\n timestamp,\n rapFlag: false,\n }), 'fragment-counter-mismatch')\n const out = reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 78,\n fragmentCounter: 0,\n packetSequenceNumber: 3002,\n data: new Uint8Array([0xf6]),\n timestamp,\n rapFlag: false,\n })\n\n expect(out).not.toBeNull()\n expect(out!.data).toEqual(new Uint8Array([0xd4, 0xe5, 0xf6]))\n })\n\n test('reassembles middle and terminal continuations that arrive before first', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const timestamp = 54321n\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 2,\n mpuSequenceNumber: 45,\n fragmentCounter: 1,\n data: new Uint8Array([0xb2]),\n timestamp,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(45, 1),\n })).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 45,\n fragmentCounter: 0,\n data: new Uint8Array([0xc3]),\n timestamp: timestamp + 1n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(45, 0),\n })).toBeNull()\n expect(reassembler.pendingCount).toBe(1)\n const out = reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 45,\n fragmentCounter: 2,\n movieFragmentSequenceNumber: 10,\n sampleNumber: 18,\n sampleOffset: 0,\n data: new Uint8Array([0xa1]),\n timestamp,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(45, 2),\n })\n\n expect(out).not.toBeNull()\n expect(out!.data).toEqual(new Uint8Array([0xa1, 0xb2, 0xc3]))\n expect(out!.sampleNumber).toBe(18)\n expect(out!.movieFragmentSequenceNumber).toBe(10)\n expect(reassembler.pendingCount).toBe(0)\n })\n\n test('rejects a duplicate continuation before first without replacing retained media', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const timestamp = 54322n\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 46,\n fragmentCounter: 0,\n data: new Uint8Array([0xc3]),\n timestamp,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(46, 0),\n })).toBeNull()\n expectRejection(() => reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 46,\n fragmentCounter: 0,\n data: new Uint8Array([0xff]),\n timestamp: timestamp + 1n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(46, 0),\n }), 'fragment-counter-mismatch')\n expect(reassembler.addFragment({\n fragmentationIndicator: 2,\n mpuSequenceNumber: 46,\n fragmentCounter: 1,\n data: new Uint8Array([0xb2]),\n timestamp: timestamp + 2n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(46, 1),\n })).toBeNull()\n\n const out = reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 46,\n fragmentCounter: 2,\n movieFragmentSequenceNumber: 10,\n sampleNumber: 19,\n sampleOffset: 0,\n data: new Uint8Array([0xa1]),\n timestamp: timestamp + 3n,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(46, 2),\n })\n\n expect(out).not.toBeNull()\n expect(out!.data).toEqual(new Uint8Array([0xa1, 0xb2, 0xc3]))\n expect(reassembler.pendingCount).toBe(0)\n })\n\n test('rejects invalid ISO fragmentation-indicator and counter combinations', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const invalidHeaders = [\n { fragmentationIndicator: 0, fragmentCounter: 1 },\n { fragmentationIndicator: 3, fragmentCounter: 1 },\n { fragmentationIndicator: 1, fragmentCounter: 0 },\n { fragmentationIndicator: 2, fragmentCounter: 0 },\n { fragmentationIndicator: -1, fragmentCounter: 1 },\n { fragmentationIndicator: 4, fragmentCounter: 1 },\n { fragmentationIndicator: 1.5, fragmentCounter: 1 },\n { fragmentationIndicator: 1, fragmentCounter: -1 },\n { fragmentationIndicator: 1, fragmentCounter: 256 },\n { fragmentationIndicator: 1, fragmentCounter: 1.5 },\n { fragmentationIndicator: 1, fragmentCounter: Number.NaN },\n ]\n\n for (const header of invalidHeaders) {\n expectRejection(() => reassembler.addFragment({\n ...header,\n mpuSequenceNumber: 48,\n data: new Uint8Array([0xa1]),\n timestamp: 54324n,\n rapFlag: false,\n }), 'invalid-fragment-state')\n }\n\n expect(reassembler.pendingCount).toBe(0)\n expect(reassembler.stats.reassembledMFUs).toBe(0)\n })\n\n test('reassembles the maximum ISO chain of 256 payloads', () => {\n const reassembler = new MFUReassembler({ timeoutMs: null })\n const common = {\n mpuSequenceNumber: 47,\n timestamp: 54323n,\n rapFlag: false,\n }\n\n expect(reassembler.addFragment({\n ...common,\n fragmentationIndicator: 1,\n fragmentCounter: 255,\n itemId: 1,\n data: new Uint8Array([0]),\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(47, 255),\n })).toBeNull()\n for (let counter = 254; counter > 0; counter--) {\n expect(reassembler.addFragment({\n ...common,\n fragmentationIndicator: 2,\n fragmentCounter: counter,\n data: new Uint8Array([255 - counter]),\n packetSequenceNumber: testPacketSequence(47, counter),\n })).toBeNull()\n }\n const out = reassembler.addFragment({\n ...common,\n fragmentationIndicator: 3,\n fragmentCounter: 0,\n data: new Uint8Array([255]),\n packetSequenceNumber: testPacketSequence(47, 0),\n })\n\n expect(out?.fragmentCount).toBe(256)\n expect(out?.data).toEqual(Uint8Array.from({ length: 256 }, (_, index) => index))\n })\n\n test('should not reassemble without last fragment (FI=3)', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 1,\n fragmentCounter: 2, itemId: 1, data: new Uint8Array([1]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 2),\n })\n const result = reassembler.addFragment({\n fragmentationIndicator: 2, mpuSequenceNumber: 1,\n fragmentCounter: 1, data: new Uint8Array([2]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 1),\n })\n expect(result).toBeNull()\n expect(reassembler.pendingCount).toBe(1)\n })\n\n test('bounds continuations that arrive before their first fragments', () => {\n const reassembler = new MFUReassembler({ timeoutMs: null, maxBuffered: 1 })\n expect(reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 1,\n fragmentCounter: 0, data: new Uint8Array([1]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 0),\n })).toBeNull()\n expectRejection(() => reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 2,\n fragmentCounter: 0, data: new Uint8Array([2]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(2, 0),\n }), 'active-data-unit-limit')\n expectRejection(() => reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 2,\n fragmentCounter: 1, itemId: 2, data: new Uint8Array([2]),\n timestamp: 1000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(2, 1),\n }), 'active-data-unit-limit')\n expect(reassembler.pendingCount).toBe(1)\n expect(reassembler.getStatus().pendingFragments).toBe(1)\n\n const result = reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 1,\n fragmentCounter: 1, itemId: 1, data: new Uint8Array([3]),\n timestamp: 1000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(1, 1),\n })\n expect(result?.data).toEqual(new Uint8Array([3, 1]))\n })\n\n test('expires a continuation that never receives its first fragment', () => {\n vi.useFakeTimers()\n try {\n const reassembler = new MFUReassembler({ timeoutMs: 50, maxBuffered: 1 })\n expect(reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 1,\n fragmentCounter: 0, data: new Uint8Array([1]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 0),\n })).toBeNull()\n vi.advanceTimersByTime(50)\n expect(reassembler.pendingCount).toBe(0)\n expect(reassembler.stats.timedOutMFUs).toBe(1)\n } finally {\n vi.useRealTimers()\n }\n })\n\n test('retimes retained continuations when the timeout policy changes', () => {\n vi.useFakeTimers()\n try {\n const enabled = new MFUReassembler({ timeoutMs: null, maxBuffered: 1 })\n expect(enabled.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 1,\n fragmentCounter: 0, data: new Uint8Array([1]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 0),\n })).toBeNull()\n enabled.timeoutMs = 10\n vi.advanceTimersByTime(10)\n expect(enabled.pendingCount).toBe(0)\n\n const disabled = new MFUReassembler({ timeoutMs: 10, maxBuffered: 1 })\n expect(disabled.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 2,\n fragmentCounter: 0, data: new Uint8Array([2]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(2, 0),\n })).toBeNull()\n disabled.timeoutMs = null\n vi.advanceTimersByTime(10)\n expect(disabled.pendingCount).toBe(1)\n disabled.flush()\n } finally {\n vi.useRealTimers()\n }\n })\n\n test('bounds active data units and rejects a new first at maxBuffered', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000, maxBuffered: 2 })\n\n // Two runs remain active; the third first fragment is rejected.\n for (let i = 0; i < 2; i++) {\n reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: i,\n fragmentCounter: 1, itemId: i, data: new Uint8Array([i]),\n timestamp: BigInt(i * 100), rapFlag: false,\n packetSequenceNumber: testPacketSequence(i, 1),\n })\n }\n expectRejection(() => reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 2,\n fragmentCounter: 1, itemId: 2, data: new Uint8Array([2]),\n timestamp: 200n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(2, 1),\n }), 'active-data-unit-limit')\n expect(reassembler.pendingCount).toBe(2)\n expect(reassembler.stats.timedOutMFUs).toBe(0)\n expect(reassembler.stats.evictedMemoryLimit).toBe(0)\n })\n\n test('should report stats correctly', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n // One complete MFU\n reassembler.addFragment({\n fragmentationIndicator: 0, mpuSequenceNumber: 1,\n fragmentCounter: 0, itemId: 1, data: new Uint8Array([1]),\n timestamp: 1000n, rapFlag: false,\n })\n\n const status = reassembler.getStatus()\n expect(status.bufferedMFUs).toBe(0)\n expect(status.stats.totalFragments).toBe(1)\n expect(status.stats.reassembledMFUs).toBe(1)\n })\n\n test('rejects an overlapping first without replacing the original fragment', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 1,\n fragmentCounter: 1, itemId: 1, data: new Uint8Array([0xAA]),\n timestamp: 1000n, rapFlag: true, source: 'multicast',\n packetSequenceNumber: testPacketSequence(1, 1),\n })\n // Duplicate of fragmentCounter=1\n expectRejection(() => reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 1,\n fragmentCounter: 1, itemId: 2, data: new Uint8Array([0xBB]),\n timestamp: 1000n, rapFlag: true, source: 'moq',\n packetSequenceNumber: testPacketSequence(1, 1),\n }), 'overlapping-data-unit')\n\n const result = reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 1,\n fragmentCounter: 0, data: new Uint8Array([0xCC]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 0),\n })\n expect(result).not.toBeNull()\n expect(result!.data).toEqual(new Uint8Array([0xAA, 0xCC]))\n expect(result!.fragmentCount).toBe(2)\n expect(result!.source).toBe('multicast')\n })\n })\n\n test('should retain an assembly with a gap in fragment counters', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n // First fragment declares three succeeding payloads.\n reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 1,\n fragmentCounter: 3, itemId: 1, data: new Uint8Array([0xAA]),\n timestamp: 1000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(1, 3),\n })\n // Counter 1 arrives while counter 2 is missing.\n expect(reassembler.addFragment({\n fragmentationIndicator: 2, mpuSequenceNumber: 1,\n fragmentCounter: 1, data: new Uint8Array([0xCC]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 1),\n })).toBeNull()\n // Last fragment has the required zero counter.\n expect(reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 1,\n fragmentCounter: 0, data: new Uint8Array([0xDD]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 0),\n })).toBeNull()\n expect(reassembler.pendingCount).toBe(1)\n expect(reassembler.getStatus().pendingFragments).toBe(3)\n })\n\n test('accepts a reordered countdown and rejects a stale duplicate', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n // Counters 3, 1, 0 arrive (gap at 2).\n reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 1,\n fragmentCounter: 3, itemId: 1, data: new Uint8Array([0xAA]),\n timestamp: 1000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(1, 3),\n })\n expect(reassembler.addFragment({\n fragmentationIndicator: 2, mpuSequenceNumber: 1,\n fragmentCounter: 1, data: new Uint8Array([0xCC]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 1),\n })).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 2, mpuSequenceNumber: 1,\n fragmentCounter: 2, data: new Uint8Array([0xBB]),\n timestamp: 1000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 2),\n })).toBeNull()\n expectRejection(() => reassembler.addFragment({\n fragmentationIndicator: 2, mpuSequenceNumber: 1,\n fragmentCounter: 1, data: new Uint8Array([0xCC]),\n timestamp: 1001n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 1),\n }), 'fragment-counter-mismatch')\n const result = reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 1,\n fragmentCounter: 0, data: new Uint8Array([0xDD]),\n timestamp: 1002n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(1, 0),\n })\n expect(result).not.toBeNull()\n expect(result!.data).toEqual(new Uint8Array([0xAA, 0xBB, 0xCC, 0xDD]))\n expect(result!.fragmentCount).toBe(4)\n })\n\n test('rejects an overlapping first without discarding queued continuations', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const fragment = (\n fragmentationIndicator: number,\n fragmentCounter: number,\n byte: number,\n ): MFUFragment => ({\n fragmentationIndicator,\n mpuSequenceNumber: 2,\n fragmentCounter,\n data: new Uint8Array([byte]),\n timestamp: 1000n,\n rapFlag: fragmentationIndicator === 1,\n packetSequenceNumber: testPacketSequence(2, fragmentCounter),\n ...(fragmentationIndicator === 1 ? { itemId: 9 } : {}),\n })\n\n expect(reassembler.addFragment(fragment(1, 3, 0xAA))).toBeNull()\n expect(reassembler.addFragment(fragment(2, 1, 0xCC))).toBeNull()\n expectRejection(\n () => reassembler.addFragment(fragment(1, 1, 0xEE)),\n 'overlapping-data-unit',\n )\n expect(reassembler.addFragment(fragment(2, 2, 0xBB))).toBeNull()\n expect(reassembler.addFragment(fragment(3, 0, 0xDD))?.data).toEqual(\n new Uint8Array([0xAA, 0xBB, 0xCC, 0xDD]),\n )\n })\n\n test('rejects a duplicate emitted intrinsic identity', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 42,\n fragmentCounter: 1, itemId: 1, data: new Uint8Array([0xAA]),\n timestamp: 1000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(42, 1),\n })).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 42,\n fragmentCounter: 0, data: new Uint8Array([0xAB]),\n timestamp: 1001n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(42, 0),\n })).not.toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 42,\n fragmentCounter: 0, data: new Uint8Array([0xBC]),\n timestamp: 1002n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(42, 0, 10),\n })).toBeNull()\n expect(reassembler.pendingCount).toBe(1)\n expect(reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 42,\n fragmentCounter: 1, itemId: 1, data: new Uint8Array([0xBB]),\n timestamp: 2000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(42, 1, 10),\n })).toBeNull()\n expect(reassembler.pendingCount).toBe(0)\n\n const result = reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 43,\n fragmentCounter: 1, itemId: 1, data: new Uint8Array([0xCC]),\n timestamp: 2000n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(43, 1),\n })\n expect(result).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 43,\n fragmentCounter: 0, data: new Uint8Array([0xDD]),\n timestamp: 2001n, rapFlag: false,\n packetSequenceNumber: testPacketSequence(43, 0),\n })?.data).toEqual(new Uint8Array([0xCC, 0xDD]))\n })\n\n test('does not create active state for an emitted identity duplicate', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 50,\n fragmentCounter: 1,\n movieFragmentSequenceNumber: 10,\n sampleNumber: 18,\n sampleOffset: 0,\n data: new Uint8Array([0xa1]),\n timestamp: 1000n,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(50, 1),\n })).toBeNull()\n expect(reassembler.addFragment({\n fragmentationIndicator: 3,\n mpuSequenceNumber: 50,\n fragmentCounter: 0,\n data: new Uint8Array([0xb2]),\n timestamp: 1000n,\n rapFlag: false,\n packetSequenceNumber: testPacketSequence(50, 0),\n })?.data).toEqual(new Uint8Array([0xa1, 0xb2]))\n expect(reassembler.pendingCount).toBe(0)\n\n expect(reassembler.addFragment({\n fragmentationIndicator: 1,\n mpuSequenceNumber: 50,\n fragmentCounter: 1,\n movieFragmentSequenceNumber: 10,\n sampleNumber: 18,\n sampleOffset: 0,\n data: new Uint8Array([0xa1]),\n timestamp: 2000n,\n rapFlag: true,\n packetSequenceNumber: testPacketSequence(50, 1, 10),\n })).toBeNull()\n expect(reassembler.pendingCount).toBe(0)\n })\n\n test('flush should clear emitted set and allow re-assembly', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n\n // Use fragmented MFU (FI=1 start + FI=3 end) \u2014 only fragmented MFUs\n // go through the #emitted dedup set. FI=0 (complete) bypasses it.\n const first = reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 42,\n fragmentCounter: 1, itemId: 1, data: new Uint8Array([0xAA]),\n timestamp: 1000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(42, 1),\n })\n expect(first).toBeNull() // first fragment, not yet complete\n const assembled = reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 42,\n fragmentCounter: 0, data: new Uint8Array([0xBB]),\n timestamp: 1000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(42, 0),\n })\n expect(assembled).not.toBeNull() // complete \u2014 mpuSeq 42 now in emitted set\n\n // Rejected before flush \u2014 same mpuSeq already emitted\n expect(reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 42,\n fragmentCounter: 1, itemId: 1, data: new Uint8Array([0xCC]),\n timestamp: 1000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(42, 1, 10),\n })).toBeNull()\n\n // After flush, same mpuSeq should work again\n reassembler.flush()\n const r2 = reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 42,\n fragmentCounter: 1, itemId: 1, data: new Uint8Array([0xDD]),\n timestamp: 1000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(42, 1),\n })\n expect(r2).toBeNull() // first fragment of new assembly\n const r3 = reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 42,\n fragmentCounter: 0, data: new Uint8Array([0xEE]),\n timestamp: 1000n, rapFlag: true,\n packetSequenceNumber: testPacketSequence(42, 0),\n })\n expect(r3).not.toBeNull()\n expect(r3!.data).toEqual(new Uint8Array([0xDD, 0xEE]))\n })\n\n describe('createFragment', () => {\n test('should create fragment from complete timed MMTP packet', () => {\n // Build: MMTP(12) + MPU(8, T=1 FI=0 payloadLength=25) + MFU_DU(14) + data(5)\n const packet = new Uint8Array(12 + 8 + 14 + 5)\n // MMTP header: byte0 = rap=1, byte1 = MPU type\n packet[0] = 0x01 // RAP flag set\n packet[1] = 0x00 // packet_type = MPU\n // packetId = 1\n const view = new DataView(packet.buffer)\n view.setUint16(2, 1, false)\n view.setUint32(4, 42, false) // timestamp\n view.setUint32(8, 100, false) // sequence number\n\n // MPU header at offset 12\n view.setUint16(12, 25, false) // 6 remaining MPU bytes + 14 DU + 5 media\n packet[14] = 0x28 // FT=2, T=1, FI=0, A=0\n packet[15] = 0 // fragment_counter\n view.setUint32(16, 999, false) // mpuSequenceNumber\n\n // MFU DU header (14 bytes) at offset 20.\n view.setUint32(20, 7, false) // movie_fragment_sequence_number\n view.setUint32(24, 1, false) // sample_number\n // Video data at offset 34\n packet[34] = 0xDE; packet[35] = 0xAD; packet[36] = 0xBE\n packet[37] = 0xEF; packet[38] = 0x01\n\n const frag = createFragment(packet)\n expect(frag.mpuSequenceNumber).toBe(999)\n expect(frag.fragmentationIndicator).toBe(0)\n expect(frag.rapFlag).toBe(true)\n expect(frag.movieFragmentSequenceNumber).toBe(7)\n expect(frag.sampleNumber).toBe(1)\n expect(frag.sampleOffset).toBe(0)\n expect(frag.data.length).toBe(5) // 5 bytes of video data\n })\n\n test('reads Item_ID from a non-timed MFU DU header', () => {\n const packet = new Uint8Array(12 + 8 + 4 + 2)\n const view = new DataView(packet.buffer)\n view.setUint16(2, 1, false)\n view.setUint32(4, 42, false)\n view.setUint32(8, 100, false)\n view.setUint16(12, 12, false) // 6 remaining MPU bytes + 4 DU + 2 media\n packet[14] = 0x20 // FT=2, T=0, FI=0\n view.setUint32(16, 999, false)\n view.setUint32(20, 0x01020304, false)\n packet.set([0xde, 0xad], 24)\n\n const fragment = createFragment(packet)\n expect(fragment.itemId).toBe(0x01020304)\n expect(fragment.data).toEqual(new Uint8Array([0xde, 0xad]))\n })\n })\n\n describe('processMMTPWithReassembly', () => {\n test('should skip FEC repair packets', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const packet = new Uint8Array(12 + 8 + 14 + 4)\n packet[0] = 0x10 // fecType=2 (repair)\n const result = processMMTPWithReassembly(packet, reassembler)\n expect(result).toBeNull()\n })\n\n test('should return reassembled MFU for complete packet', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const packet = new Uint8Array(12 + 8 + 14 + 4)\n packet[0] = 0x01 // RAP\n packet[1] = 0x00 // MPU\n const view = new DataView(packet.buffer)\n view.setUint16(2, 1, false) // packetId\n view.setUint32(4, 100, false) // timestamp\n view.setUint32(8, 1, false) // seq\n // MPU: payloadLength=24 (6 + 14 + 4), FT=2 T=1 FI=0 A=0\n view.setUint16(12, 24, false)\n packet[14] = 0x28\n view.setUint32(16, 42, false) // mpuSeq\n view.setUint32(20, 7, false) // movie_fragment_sequence_number\n view.setUint32(24, 1, false) // sample_number\n\n packet[34] = 0x00; packet[35] = 0x00; packet[36] = 0x00; packet[37] = 0x01\n\n const result = processMMTPWithReassembly(packet, reassembler)\n expect(result).not.toBeNull()\n expect(result!.mpuSequenceNumber).toBe(42)\n expect(result!.rapFlag).toBe(true)\n })\n })\n\n describe('strict delivery provenance', () => {\n test('folds to multicast only when every fragment is explicitly multicast', () => {\n expect(deliveryProvenanceOf([{ source: 'multicast' }, { source: 'multicast' }]))\n .toBe('multicast')\n })\n\n test('a single moq fragment makes the whole frame mixed', () => {\n expect(deliveryProvenanceOf([{ source: 'multicast' }, { source: 'moq' }]))\n .toBe('mixed')\n // ...and it does not matter where in the run it lands.\n expect(deliveryProvenanceOf([{ source: 'moq' }, { source: 'multicast' }]))\n .toBe('mixed')\n })\n\n test('an unattributed fragment degrades multicast to unknown, never to proven', () => {\n expect(deliveryProvenanceOf([{ source: 'multicast' }, {}])).toBe('unknown')\n expect(deliveryProvenanceOf([{}])).toBe('unknown')\n })\n\n test('mixed absorbs unknown \u2014 a moq byte is worse news than a missing label', () => {\n expect(deliveryProvenanceOf([{ source: 'moq' }, {}])).toBe('mixed')\n expect(deliveryProvenanceOf([{}, { source: 'moq' }])).toBe('mixed')\n })\n\n test('an empty fragment set proves nothing', () => {\n expect(deliveryProvenanceOf([])).toBe('unknown')\n })\n\n test('the fold never upgrades a verdict', () => {\n expect(foldDeliveryProvenance('mixed', 'multicast')).toBe('mixed')\n expect(foldDeliveryProvenance('unknown', 'multicast')).toBe('unknown')\n expect(foldDeliveryProvenance('unknown', 'moq')).toBe('mixed')\n })\n\n test('a multicast head with a non-multicast tail is NOT multicast-exclusive', () => {\n // This is the leak this field exists to close. `source` legitimately\n // reports 'multicast' \u2014 head-fragment-wins is the routing contract \u2014\n // but the frame contains bytes that never crossed a multicast socket,\n // so it must never be counted as physical-delivery evidence.\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 1,\n fragmentCounter: 1, itemId: 1, data: new Uint8Array([0xAA]),\n timestamp: 1000n, rapFlag: true, source: 'multicast',\n packetSequenceNumber: testPacketSequence(1, 1),\n })\n const result = reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 1,\n fragmentCounter: 0, data: new Uint8Array([0xCC]),\n timestamp: 1000n, rapFlag: false, source: 'moq',\n packetSequenceNumber: testPacketSequence(1, 0),\n })\n expect(result).not.toBeNull()\n expect(result!.fragmentCount).toBe(2)\n expect(result!.source).toBe('multicast')\n expect(result!.deliveryProvenance).toBe('mixed')\n })\n\n test('an all-multicast fragmented frame is multicast-exclusive', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n reassembler.addFragment({\n fragmentationIndicator: 1, mpuSequenceNumber: 2,\n fragmentCounter: 1, itemId: 1, data: new Uint8Array([0xAA]),\n timestamp: 2000n, rapFlag: true, source: 'multicast',\n packetSequenceNumber: testPacketSequence(2, 1),\n })\n const result = reassembler.addFragment({\n fragmentationIndicator: 3, mpuSequenceNumber: 2,\n fragmentCounter: 0, data: new Uint8Array([0xCC]),\n timestamp: 2000n, rapFlag: false, source: 'multicast',\n packetSequenceNumber: testPacketSequence(2, 0),\n })\n expect(result).not.toBeNull()\n expect(result!.deliveryProvenance).toBe('multicast')\n })\n\n test('an unlabelled complete frame proves nothing', () => {\n const reassembler = new MFUReassembler({ timeoutMs: 1000 })\n const result = reassembler.addFragment({\n fragmentationIndicator: 0, mpuSequenceNumber: 3,\n fragmentCounter: 0, itemId: 1, data: new Uint8Array([1]),\n timestamp: 3000n, rapFlag: true,\n })\n expect(result).not.toBeNull()\n expect(result!.deliveryProvenance).toBe('unknown')\n })\n })\n}\n", "/**\n * @mmt/container - Sample-level combining of subsample data units (moqcast #37)\n *\n * {@link MFUReassembler} reassembles exactly one data unit -- a whole-sample\n * DU, or one subsample DU of a partitioned sample. When a timed sample\n * exceeds one data unit's 256-payload capacity, the origin packetizer\n * partitions it into multiple subsample data units (each its own FI chain,\n * its own authored base offset). This module combines those\n * already-reassembled data units back into one contiguous sample.\n *\n * Container-blind, matching {@link MFUReassembler}'s own doctrine: it never\n * parses ISOBMFF itself. The authored sample size a subsample-partitioned\n * sample must total to comes from the host's own FT=1 (movie-fragment-\n * metadata) parse, supplied via {@link SampleCombiner.registerAuthoredSize}.\n * Completion is a protocol event -- every constituent data unit reassembled,\n * byte-adjacent from zero, totaling the registered size -- never a\n * timer-based guess; on lossy paths the existing per-data-unit deadline in\n * {@link MFUReassembler} already bounds each constituent, so this module adds\n * no second timer tier, matching moqcast #37 section 5.2.1.\n *\n * A whole-sample data unit whose length already equals the registered\n * authored size passes through immediately, with no buffering. When\n * `requireAuthoredSize` is false, an offset-zero data unit with no registered\n * size at all also passes through immediately -- the pre-amendment shape, for\n * a host that does not drive FT=1. When true, that same data unit instead\n * buffers and waits for a size to be registered: FT=1 always publishes before\n * any FT=2 sample referencing it (moqcast #37), but on a lossy path FT=1 can\n * still *arrive* after an offset-zero data unit (reordering, or FT=1's own DU\n * FEC-recovered late) -- treating \"no size yet\" as \"whole sample\" in that\n * window would silently truncate a subsample-partitioned sample.\n *\n * Both `#pending` (incomplete samples) and `#authoredSizes` (registered but\n * not yet consumed) are bounded. `#pending` is bounded by `maxBuffered`\n * samples and `maxSegmentsPerSample` data units per sample; a full table\n * evicts its oldest sample by insertion order rather than throwing, so one\n * FEC-lost subsample DU cannot wedge every future sample. `#authoredSizes` is\n * bounded by retiring each key the moment its sample completes, keeping only a\n * bounded recent-retirement set so a late duplicate or FEC-recovered\n * retransmission for that same sample is dropped rather than silently\n * re-emitted or misread as a fresh whole sample.\n *\n * @packageDocumentation\n */\n\nimport type {\n MmtpSourcePath,\n ReassembledMFU,\n MmtpDeliveryProvenance,\n} from './mfu-reassembler.js'\n\n/** Identifies one authored sample: `(catalogTrackName, mpu, movieFragmentSequenceNumber, sampleNumber)`. */\ntype SampleKey = string\n\nfunction sampleKey(\n catalogTrackName: string | undefined,\n mpuSequenceNumber: number,\n movieFragmentSequenceNumber: number,\n sampleNumber: number,\n): SampleKey {\n return JSON.stringify([catalogTrackName ?? null, mpuSequenceNumber, movieFragmentSequenceNumber, sampleNumber])\n}\n\n/** The `catalogTrackName` a key was built from, or undefined when it had none. */\nfunction trackNameOfKey(key: SampleKey): string | undefined {\n const name = (JSON.parse(key) as [string | null, number, number, number])[0]\n return name ?? undefined\n}\n\n/** One authored sample combined from its constituent data unit(s). */\nexport interface CombinedSample {\n mpuSequenceNumber: number\n movieFragmentSequenceNumber: number\n sampleNumber: number\n /** The full sample's media bytes, in ascending-offset order. */\n data: Uint8Array\n timestamp: bigint\n /**\n * The sample's RAP flag is the RAP flag of the FI=0 or FI=1 object of its\n * offset-0 data unit (moqcast #37).\n */\n rapFlag: boolean\n priority?: number\n /** Every authoritative source-packet sequence across all constituent data units, in offset order. */\n packetSequenceNumbers?: number[]\n /** Subset of packetSequenceNumbers reconstructed by FEC. */\n repairedPacketSequenceNumbers?: number[]\n catalogTrackName?: string\n /** Number of subsample data units combined (1 for a whole-sample DU or a non-timed passthrough). */\n subsampleCount: number\n /** MMTP fragments that formed the sample, summed across constituent data units. */\n fragmentCount: number\n /**\n * Transport that supplied the offset-zero data unit's head fragment. Taken\n * from that data unit alone -- like {@link CombinedSample.rapFlag} -- rather\n * than from whichever sibling happened to complete last.\n */\n source?: MmtpSourcePath\n /**\n * Strict provenance folded across EVERY constituent data unit, and within\n * each of them across every MMTP fragment. Unlike {@link CombinedSample.source},\n * which is the offset-zero DU's routing tag, this is whole-sample evidence:\n * only 'multicast' proves that no byte of this sample arrived another way.\n */\n deliveryProvenance: MmtpDeliveryProvenance\n}\n\nexport const SAMPLE_COMBINE_ERROR_CODES = [\n 'duplicate-subsample-offset',\n 'overlapping-subsample',\n 'exceeds-authored-size',\n 'too-many-subsample-segments',\n] as const\n\nexport type SampleCombineErrorCode = typeof SAMPLE_COMBINE_ERROR_CODES[number]\n\n/**\n * Fail-closed rejection reasons for subsample combining. Distinct from\n * {@link MfuReassemblyError}, which governs one data unit's own fragment\n * chain; these govern combining already-reassembled data units into a\n * sample.\n */\nexport class SampleCombineError extends Error {\n readonly name = 'SampleCombineError'\n\n constructor(readonly code: SampleCombineErrorCode, message: string) {\n super(message)\n }\n}\n\nexport interface SampleCombinerStats {\n combinedSamples: number\n passthroughSamples: number\n timedOutSamples: number\n /** Incomplete samples discarded to enforce `maxBuffered`. */\n evictedSamples: number\n}\n\nexport interface SampleCombinerOptions {\n /**\n * Max concurrent incomplete samples. Enforced by evicting the oldest by\n * insertion order, never by throwing, so a host that never calls\n * {@link SampleCombiner.cleanupTimeouts} still recovers from a permanently\n * lost subsample data unit instead of wedging.\n */\n maxBuffered: number\n /**\n * When true, an offset-zero data unit with no registered authored size\n * buffers and waits for one rather than passing through immediately. See\n * the module doc.\n */\n requireAuthoredSize: boolean\n /**\n * Max subsample data units held for one sample at once. Bounds both memory\n * and the per-insert overlap scan; a legitimate subsample-partitioned\n * sample needs at most `ceil(sampleSize / (256 * maxPayload))` data units.\n */\n maxSegmentsPerSample: number\n}\n\ninterface PendingSample {\n /** Held data units keyed by their authored base offset. */\n segments: Map<number, ReassembledMFU>\n startedAt: number\n}\n\n/** Combines subsample data units of one sample into a contiguous whole. */\nexport class SampleCombiner {\n #maxBuffered: number\n #requireAuthoredSize: boolean\n #maxSegmentsPerSample: number\n #authoredSizes: Map<SampleKey, number> = new Map()\n /** Map iteration is insertion-ordered, so the first key is the oldest. */\n #pending: Map<SampleKey, PendingSample> = new Map()\n /**\n * Bounded, insertion-ordered set of recently-completed sample keys, so a\n * late duplicate or FEC-recovered retransmission is dropped rather than\n * re-emitted or misread as a fresh whole sample.\n */\n #retired: Set<SampleKey> = new Set()\n #stats: SampleCombinerStats = {\n combinedSamples: 0,\n passthroughSamples: 0,\n timedOutSamples: 0,\n evictedSamples: 0,\n }\n\n constructor(options: SampleCombinerOptions) {\n const { maxBuffered, requireAuthoredSize, maxSegmentsPerSample } = options\n if (!Number.isInteger(maxBuffered) || maxBuffered <= 0) {\n throw new Error('[SampleCombiner] maxBuffered must be a positive integer')\n }\n if (!Number.isInteger(maxSegmentsPerSample) || maxSegmentsPerSample <= 0) {\n throw new Error('[SampleCombiner] maxSegmentsPerSample must be a positive integer')\n }\n this.#maxBuffered = maxBuffered\n this.#requireAuthoredSize = requireAuthoredSize\n this.#maxSegmentsPerSample = maxSegmentsPerSample\n }\n\n /**\n * Register the authored sample size from the host's own FT=1 parse. Per\n * moqcast #37, FT=1 for a movie fragment publishes before any FT=2 sample\n * referencing it, so a host driving FT=1 as it arrives registers each\n * sample's size before that sample's own data unit(s) arrive.\n *\n * On a lossy path FT=1 can still *arrive* late, after data units this\n * combiner has already buffered. Registering a size therefore re-drives the\n * completion check and returns the combined sample when the buffered data\n * units already satisfy the newly-known size. Callers MUST consume the\n * return value: for a sample carried by a single data unit there is no\n * later {@link SampleCombiner.addMfu} to re-enter, so discarding it\n * silently drops the sample.\n *\n * Registering also clears the key from the retired set. Retirement exists\n * to drop data units that arrive *passively* after a sample completed \u2014 a\n * late duplicate, an FEC-recovered retransmission. A host calling this\n * method is instead asserting that a sample with this identity is authored\n * now, which is what happens when a publisher restarts and its MPU\n * sequence numbers begin again, or when MPU sequence wraps. Without this,\n * such a stream would silently drop every sample whose identity collided\n * with a retired one until the bounded set aged the key out.\n */\n registerAuthoredSize(\n catalogTrackName: string | undefined,\n mpuSequenceNumber: number,\n movieFragmentSequenceNumber: number,\n sampleNumber: number,\n size: number,\n ): CombinedSample | null {\n const key = sampleKey(catalogTrackName, mpuSequenceNumber, movieFragmentSequenceNumber, sampleNumber)\n this.#retired.delete(key)\n this.#authoredSizes.set(key, size)\n return this.#tryComplete(key, size)\n }\n\n /**\n * Add one reassembled data unit. Returns the combined sample once every\n * constituent data unit has arrived and totals the authored size.\n */\n addMfu(mfu: ReassembledMFU): CombinedSample | null {\n if (mfu.movieFragmentSequenceNumber === undefined || mfu.sampleNumber === undefined) {\n // Non-timed (Item) MFU: sample combining does not apply.\n this.#stats.passthroughSamples++\n return fromPassthrough(mfu)\n }\n const offset = mfu.sampleOffset ?? 0\n const key = sampleKey(\n mfu.catalogTrackName,\n mfu.mpuSequenceNumber,\n mfu.movieFragmentSequenceNumber,\n mfu.sampleNumber,\n )\n\n if (this.#retired.has(key)) {\n // Duplicate or late data unit for an already-retired sample (a\n // FEC-recovered retransmission, reordering after completion, or a\n // sample discarded by eviction/timeout). Drop it rather than\n // re-emitting a duplicate downstream or misreading a stray fragment as\n // a fresh whole sample.\n return null\n }\n\n const dataLen = mfu.data.byteLength\n const authoredSize = this.#authoredSizes.get(key)\n\n if (offset === 0 && !this.#pending.has(key)) {\n const passesThrough = authoredSize === undefined\n ? !this.#requireAuthoredSize\n : dataLen === authoredSize\n if (passesThrough) {\n this.#stats.passthroughSamples++\n this.#retire(key)\n return fromPassthrough(mfu)\n }\n // Either shorter than the authored total (a subsample), or awaiting a\n // size under requireAuthoredSize -- buffer below.\n }\n\n // Reject BEFORE mutating any state. An earlier revision allocated the\n // pending entry (evicting the oldest sample to make room) and only then\n // validated, so a data unit the combiner went on to reject could destroy\n // an unrelated in-flight sample and leave an empty entry in its slot.\n const thisEnd = offset + dataLen\n if (authoredSize !== undefined && thisEnd > authoredSize) {\n throw new SampleCombineError(\n 'exceeds-authored-size',\n 'combined subsample data would exceed the registered authored sample size',\n )\n }\n const existing = this.#pending.get(key)\n if (existing !== undefined) {\n if (existing.segments.has(offset)) {\n throw new SampleCombineError(\n 'duplicate-subsample-offset',\n 'subsample data unit duplicates an offset already held for this sample',\n )\n }\n if (existing.segments.size >= this.#maxSegmentsPerSample) {\n throw new SampleCombineError(\n 'too-many-subsample-segments',\n 'a sample already holds the maximum number of subsample data units',\n )\n }\n for (const [segOffset, seg] of existing.segments) {\n const segEnd = segOffset + seg.data.byteLength\n if (offset < segEnd && segOffset < thisEnd) {\n throw new SampleCombineError(\n 'overlapping-subsample',\n \"subsample data unit overlaps a preceding data unit's byte range\",\n )\n }\n }\n }\n\n let pending = existing\n if (pending === undefined) {\n if (this.#pending.size >= this.#maxBuffered) this.#evictOldestPending()\n pending = { segments: new Map(), startedAt: Date.now() }\n this.#pending.set(key, pending)\n }\n pending.segments.set(offset, mfu)\n\n if (authoredSize === undefined) return null\n return this.#tryComplete(key, authoredSize)\n }\n\n /**\n * Emit the sample when its held data units are byte-adjacent from zero and\n * total `size`. Completion is a protocol event, never a timer.\n */\n #tryComplete(key: SampleKey, size: number): CombinedSample | null {\n const pending = this.#pending.get(key)\n if (pending === undefined) return null\n let expected = 0\n const sortedOffsets = [...pending.segments.keys()].sort((a, b) => a - b)\n for (const segOffset of sortedOffsets) {\n if (segOffset !== expected) return null // gap: not yet contiguous from zero.\n expected += pending.segments.get(segOffset)!.data.byteLength\n }\n if (expected !== size) return null // contiguous so far, short of the authored total.\n\n this.#pending.delete(key)\n this.#stats.combinedSamples++\n this.#retire(key)\n return fromSegments(pending.segments, sortedOffsets)\n }\n\n /**\n * Retire a sample's key: free its registered authored size and remember the\n * key in a bounded recency set. Called on every path that removes a sample\n * -- completion, passthrough, eviction, and timeout -- so `#authoredSizes`\n * cannot accumulate entries for samples that never complete, and so a later\n * data unit for a discarded sample is dropped rather than starting a fresh\n * buffer or being misread as a whole sample.\n *\n * The recency set holds `maxBuffered` keys. A duplicate delayed by more\n * than that many retirements escapes it; on a reliable path there is no\n * such duplicate, and on a lossy path the per-data-unit deadline in\n * {@link MFUReassembler} bounds the delay well inside this window.\n */\n #retire(key: SampleKey): void {\n this.#authoredSizes.delete(key)\n this.#retired.add(key)\n while (this.#retired.size > this.#maxBuffered) {\n const oldest = this.#retired.values().next().value\n if (oldest === undefined) break\n this.#retired.delete(oldest)\n }\n }\n\n /**\n * Discard the oldest pending sample by insertion order. This is the only\n * backstop against one FEC-lost subsample data unit wedging\n * {@link SampleCombiner.addMfu} for every future sample once `maxBuffered`\n * is reached, for a host that never drives\n * {@link SampleCombiner.cleanupTimeouts}.\n */\n #evictOldestPending(): void {\n const oldest = this.#pending.keys().next().value\n if (oldest === undefined) return\n this.#pending.delete(oldest)\n this.#stats.evictedSamples++\n this.#retire(oldest)\n }\n\n /**\n * Discard samples whose oldest held segment has waited past `timeoutMs`.\n * Mirrors {@link MFUReassembler}'s clock-driven shape; the per-data-unit\n * deadline inside {@link MFUReassembler} already bounds each constituent,\n * so this is a backstop against a host that registers an authored size but\n * never supplies every subsample DU.\n */\n cleanupTimeouts(timeoutMs: number): void {\n const now = Date.now()\n for (const [key, pending] of [...this.#pending]) {\n if (now - pending.startedAt > timeoutMs) {\n this.#pending.delete(key)\n this.#stats.timedOutSamples++\n this.#retire(key)\n }\n }\n }\n\n flush(): void {\n this.#pending.clear()\n this.#authoredSizes.clear()\n this.#retired.clear()\n }\n\n /**\n * Drop one stream's in-flight, registered-size, and retired state while\n * preserving every other stream (mirrors\n * {@link MFUReassembler.resetStream}).\n */\n resetStream(catalogTrackName: string): void {\n for (const key of this.#pending.keys()) {\n if (trackNameOfKey(key) === catalogTrackName) this.#pending.delete(key)\n }\n for (const key of this.#authoredSizes.keys()) {\n if (trackNameOfKey(key) === catalogTrackName) this.#authoredSizes.delete(key)\n }\n for (const key of this.#retired) {\n if (trackNameOfKey(key) === catalogTrackName) this.#retired.delete(key)\n }\n }\n\n get stats(): SampleCombinerStats {\n return { ...this.#stats }\n }\n\n get pendingCount(): number {\n return this.#pending.size\n }\n\n /**\n * Registered authored sizes still held. Diagnostic only: it exists so tests\n * and health reporting can assert this table stays bounded, since an\n * unbounded one is invisible from `pendingCount` alone.\n */\n get debugAuthoredSizeCount(): number {\n return this.#authoredSizes.size\n }\n\n /** Retired keys still remembered. Diagnostic only, bounded by `maxBuffered`. */\n get debugRetiredCount(): number {\n return this.#retired.size\n }\n}\n\nfunction fromPassthrough(mfu: ReassembledMFU): CombinedSample {\n return {\n mpuSequenceNumber: mfu.mpuSequenceNumber,\n movieFragmentSequenceNumber: mfu.movieFragmentSequenceNumber ?? 0,\n sampleNumber: mfu.sampleNumber ?? 0,\n data: mfu.data,\n timestamp: mfu.timestamp,\n rapFlag: mfu.rapFlag,\n priority: mfu.priority,\n packetSequenceNumbers: mfu.packetSequenceNumbers,\n repairedPacketSequenceNumbers: mfu.repairedPacketSequenceNumbers,\n catalogTrackName: mfu.catalogTrackName,\n subsampleCount: 1,\n fragmentCount: mfu.fragmentCount,\n source: mfu.source,\n // One data unit in, one sample out: its provenance IS the sample's.\n deliveryProvenance: mfu.deliveryProvenance\n }\n}\n\nfunction fromSegments(\n segments: Map<number, ReassembledMFU>,\n sortedOffsets: number[],\n): CombinedSample {\n const totalSize = sortedOffsets.reduce((sum, offset) => sum + segments.get(offset)!.data.byteLength, 0)\n const data = new Uint8Array(totalSize)\n let packetSequenceNumbers: number[] | undefined\n let repairedPacketSequenceNumbers: number[] | undefined\n let writeOffset = 0\n let first: ReassembledMFU | undefined\n let fragmentCount = 0\n // Fold across data units the same way the reassembler folds across the\n // fragments inside one: a sample is multicast-exclusive only if every\n // subsample that formed it was.\n let combinedProvenance: MmtpDeliveryProvenance =\n sortedOffsets.length === 0 ? 'unknown' : 'multicast'\n for (const offset of sortedOffsets) {\n const seg = segments.get(offset)!\n combinedProvenance =\n combinedProvenance === 'mixed' || seg.deliveryProvenance === 'mixed'\n ? 'mixed'\n : combinedProvenance === 'unknown' || seg.deliveryProvenance === 'unknown'\n ? 'unknown'\n : 'multicast'\n data.set(seg.data, writeOffset)\n writeOffset += seg.data.byteLength\n fragmentCount += seg.fragmentCount\n if (seg.packetSequenceNumbers !== undefined) {\n (packetSequenceNumbers ??= []).push(...seg.packetSequenceNumbers)\n }\n if (seg.repairedPacketSequenceNumbers !== undefined) {\n (repairedPacketSequenceNumbers ??= []).push(...seg.repairedPacketSequenceNumbers)\n }\n if (first === undefined) first = seg\n }\n return {\n mpuSequenceNumber: first!.mpuSequenceNumber,\n movieFragmentSequenceNumber: first!.movieFragmentSequenceNumber!,\n sampleNumber: first!.sampleNumber!,\n data,\n timestamp: first!.timestamp,\n rapFlag: first!.rapFlag,\n priority: first!.priority,\n packetSequenceNumbers,\n repairedPacketSequenceNumbers,\n catalogTrackName: first!.catalogTrackName,\n subsampleCount: segments.size,\n fragmentCount,\n source: first!.source,\n deliveryProvenance: combinedProvenance,\n }\n}\n\n// =============================================================================\n// Inline Tests (vitest)\n// =============================================================================\n\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest\n\n const combiner = (overrides: Partial<SampleCombinerOptions> = {}) =>\n new SampleCombiner({\n maxBuffered: 10,\n requireAuthoredSize: false,\n maxSegmentsPerSample: 8,\n ...overrides,\n })\n\n const mfu = (\n mpu: number,\n movie: number,\n sample: number,\n offset: number,\n data: number[],\n timestamp: bigint,\n rapFlag: boolean,\n deliveryProvenance: MmtpDeliveryProvenance = 'multicast',\n ): ReassembledMFU => ({\n mpuSequenceNumber: mpu,\n data: new Uint8Array(data),\n timestamp,\n fragmentCount: 1,\n rapFlag,\n sampleNumber: sample,\n movieFragmentSequenceNumber: movie,\n sampleOffset: offset,\n packetSequenceNumbers: [offset],\n deliveryProvenance,\n })\n\n describe('SampleCombiner', () => {\n test('whole-sample DU passes through immediately with no registered size', () => {\n const c = combiner()\n const out = c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))\n expect(out).not.toBeNull()\n expect(out!.data).toEqual(new Uint8Array([1, 2, 3, 4, 5]))\n expect(out!.subsampleCount).toBe(1)\n expect(c.pendingCount).toBe(0)\n })\n\n test('whole-sample DU passes through when it matches the registered size', () => {\n const c = combiner()\n c.registerAuthoredSize(undefined, 1, 9, 17, 5)\n const out = c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))\n expect(out?.data).toEqual(new Uint8Array([1, 2, 3, 4, 5]))\n })\n\n test('subsample data units combine once the authored size is met', () => {\n const c = combiner()\n c.registerAuthoredSize(undefined, 1, 9, 17, 10)\n\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()\n expect(c.pendingCount).toBe(1)\n\n const out = c.addMfu(mfu(1, 9, 17, 5, [6, 7, 8, 9, 10], 1001n, false))\n expect(out?.data).toEqual(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))\n expect(out?.subsampleCount).toBe(2)\n expect(out?.rapFlag).toBe(true) // offset-0 DU's RAP flag, per moqcast #37.\n expect(out?.timestamp).toBe(1000n)\n expect(c.pendingCount).toBe(0)\n expect(c.stats.combinedSamples).toBe(1)\n })\n\n test('subsample data units combine out of order', () => {\n const c = combiner()\n c.registerAuthoredSize(undefined, 1, 9, 17, 10)\n\n expect(c.addMfu(mfu(1, 9, 17, 5, [6, 7, 8, 9, 10], 1001n, false))).toBeNull()\n const out = c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))\n expect(out?.data).toEqual(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))\n })\n\n test('subsample without a registered size never completes', () => {\n // A non-zero-offset DU always buffers (it can never be a whole\n // sample). Without a registered authored size there is nothing to\n // combine against, so it -- and a sibling that arrives after it --\n // stay pending rather than being guessed complete.\n const c = combiner()\n expect(c.addMfu(mfu(1, 9, 17, 3, [1, 2, 3], 1001n, false))).toBeNull()\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3], 1000n, true))).toBeNull()\n expect(c.pendingCount).toBe(1)\n })\n\n test('requireAuthoredSize buffers an offset-zero DU instead of guessing complete', () => {\n // A moqcast-#37-aware host opts into fail-closed buffering: on a lossy\n // path FT=1 can arrive after an offset-zero data unit (reordering, or\n // FT=1's own DU recovered late by FEC). Treating \"no size yet\" as\n // \"whole sample\" would silently truncate a partitioned sample.\n const c = combiner({ requireAuthoredSize: true })\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()\n expect(c.pendingCount).toBe(1)\n\n c.registerAuthoredSize(undefined, 1, 9, 17, 10)\n const out = c.addMfu(mfu(1, 9, 17, 5, [6, 7, 8, 9, 10], 1001n, false))\n expect(out?.data).toEqual(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))\n })\n\n test('duplicate offset is rejected', () => {\n const c = combiner()\n c.registerAuthoredSize(undefined, 1, 9, 17, 10)\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()\n expect(() => c.addMfu(mfu(1, 9, 17, 0, [9, 9, 9, 9, 9], 2000n, true)))\n .toThrow(SampleCombineError)\n })\n\n test('overlapping subsample is rejected', () => {\n const c = combiner()\n c.registerAuthoredSize(undefined, 1, 9, 17, 10)\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()\n expect(() => c.addMfu(mfu(1, 9, 17, 3, [9, 9, 9, 9, 9], 2000n, true)))\n .toThrow(SampleCombineError)\n })\n\n test('exceeding the authored size is rejected', () => {\n const c = combiner()\n c.registerAuthoredSize(undefined, 1, 9, 17, 8)\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()\n expect(() => c.addMfu(mfu(1, 9, 17, 5, [6, 7, 8, 9, 10], 2000n, false)))\n .toThrow(SampleCombineError)\n })\n\n test('exceeding maxSegmentsPerSample is rejected', () => {\n const c = combiner({ maxSegmentsPerSample: 2 })\n c.registerAuthoredSize(undefined, 1, 9, 17, 100)\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2], 1000n, true))).toBeNull()\n expect(c.addMfu(mfu(1, 9, 17, 2, [3, 4], 1001n, false))).toBeNull()\n expect(() => c.addMfu(mfu(1, 9, 17, 4, [5, 6], 1002n, false)))\n .toThrow(SampleCombineError)\n })\n\n test('a full combiner evicts the oldest pending sample instead of throwing', () => {\n // Eviction is by insertion order, which is also the only backstop\n // against one permanently-lost subsample DU wedging every future\n // sample once maxBuffered incomplete samples accumulate.\n const c = combiner({ maxBuffered: 2 })\n c.registerAuthoredSize(undefined, 1, 9, 17, 10)\n c.registerAuthoredSize(undefined, 1, 9, 18, 10)\n c.registerAuthoredSize(undefined, 1, 9, 19, 10)\n\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 1, 1, 1, 1], 1000n, true))).toBeNull()\n expect(c.addMfu(mfu(1, 9, 18, 0, [2, 2, 2, 2, 2], 1001n, true))).toBeNull()\n expect(c.pendingCount).toBe(2)\n\n // A third distinct incomplete sample evicts sample 17, the oldest.\n expect(c.addMfu(mfu(1, 9, 19, 0, [3, 3, 3, 3, 3], 1002n, true))).toBeNull()\n expect(c.pendingCount).toBe(2)\n expect(c.stats.evictedSamples).toBe(1)\n\n // The surviving samples are undisturbed and still complete normally.\n expect(c.addMfu(mfu(1, 9, 18, 5, [8, 8, 8, 8, 8], 2001n, false))?.data)\n .toEqual(new Uint8Array([2, 2, 2, 2, 2, 8, 8, 8, 8, 8]))\n expect(c.addMfu(mfu(1, 9, 19, 5, [9, 9, 9, 9, 9], 2002n, false))?.data)\n .toEqual(new Uint8Array([3, 3, 3, 3, 3, 9, 9, 9, 9, 9]))\n\n // The combiner still accepts new work rather than being wedged.\n c.registerAuthoredSize(undefined, 1, 9, 20, 10)\n expect(c.addMfu(mfu(1, 9, 20, 0, [4, 4, 4, 4, 4], 3000n, true))).toBeNull()\n expect(c.addMfu(mfu(1, 9, 20, 5, [7, 7, 7, 7, 7], 3001n, false))?.data)\n .toEqual(new Uint8Array([4, 4, 4, 4, 4, 7, 7, 7, 7, 7]))\n })\n\n test('a completed sample frees its authored size and drops a late duplicate', () => {\n const c = combiner()\n c.registerAuthoredSize(undefined, 1, 9, 17, 10)\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()\n expect(c.addMfu(mfu(1, 9, 17, 5, [6, 7, 8, 9, 10], 1001n, false))).not.toBeNull()\n\n // A FEC-recovered retransmission of the completed sample's offset-0\n // data unit must not be re-emitted as a second complete sample.\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 2000n, true))).toBeNull()\n })\n\n test('resetStream drops one track and preserves the others', () => {\n const c = combiner()\n c.registerAuthoredSize('video/720p', 1, 9, 17, 10)\n c.registerAuthoredSize('audio', 1, 9, 17, 10)\n const video = { ...mfu(1, 9, 17, 0, [1, 1, 1, 1, 1], 1000n, true), catalogTrackName: 'video/720p' }\n const audio = { ...mfu(1, 9, 17, 0, [2, 2, 2, 2, 2], 1000n, true), catalogTrackName: 'audio' }\n expect(c.addMfu(video)).toBeNull()\n expect(c.addMfu(audio)).toBeNull()\n\n c.resetStream('video/720p')\n expect(c.pendingCount).toBe(1)\n\n const audioTail = { ...mfu(1, 9, 17, 5, [3, 3, 3, 3, 3], 1001n, false), catalogTrackName: 'audio' }\n expect(c.addMfu(audioTail)?.data).toEqual(new Uint8Array([2, 2, 2, 2, 2, 3, 3, 3, 3, 3]))\n })\n\n test('flush clears registered authored sizes', () => {\n const c = combiner()\n c.registerAuthoredSize(undefined, 1, 9, 17, 5)\n c.flush()\n // A now-unregistered size means an offset-zero DU passes through\n // immediately again (requireAuthoredSize is false here) rather than\n // waiting on a size flush() already discarded.\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))?.data)\n .toEqual(new Uint8Array([1, 2, 3, 4, 5]))\n })\n\n test('a healthy stream accumulates no bookkeeping', () => {\n // Regression: retirement ran only on completion paths, so an\n // abandoned sample's registered size stayed resident forever.\n const c = combiner({ maxBuffered: 4, requireAuthoredSize: true })\n for (let i = 0; i < 1000; i++) {\n expect(c.registerAuthoredSize(undefined, 1, 9, i, 10)).toBeNull()\n expect(c.addMfu(mfu(1, 9, i, 0, [1, 1, 1, 1, 1], 1000n, true))).toBeNull()\n expect(c.addMfu(mfu(1, 9, i, 5, [2, 2, 2, 2, 2], 1001n, false))).not.toBeNull()\n }\n expect(c.stats.combinedSamples).toBe(1000)\n expect(c.pendingCount).toBe(0)\n expect(c.debugAuthoredSizeCount).toBe(0)\n expect(c.debugRetiredCount).toBeLessThanOrEqual(4)\n })\n\n test('samples that never complete release their authored size', () => {\n const c = combiner({ maxBuffered: 4, requireAuthoredSize: true })\n for (let i = 0; i < 1000; i++) {\n expect(c.registerAuthoredSize(undefined, 1, 9, i, 10)).toBeNull()\n expect(c.addMfu(mfu(1, 9, i, 0, [1, 1, 1, 1, 1], 1000n, true))).toBeNull()\n // Deliberately never supply the tail.\n }\n c.cleanupTimeouts(-1) // expire everything still held\n expect(c.pendingCount).toBe(0)\n expect(c.debugAuthoredSizeCount).toBe(0)\n })\n\n test('a late authored size completes an already-buffered sample', () => {\n // Regression: with requireAuthoredSize the completion check ran only\n // inside addMfu, so a sample carried by a SINGLE data unit whose FT=1\n // arrived afterwards had no later data unit to re-enter on and was\n // silently lost.\n const c = combiner({ requireAuthoredSize: true })\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()\n expect(c.pendingCount).toBe(1)\n\n const out = c.registerAuthoredSize(undefined, 1, 9, 17, 5)\n expect(out?.data).toEqual(new Uint8Array([1, 2, 3, 4, 5]))\n expect(out?.subsampleCount).toBe(1)\n expect(c.pendingCount).toBe(0)\n })\n\n test('a rejected data unit does not evict a live sample', () => {\n // Regression: the pending slot was allocated (evicting the oldest\n // sample to make room) BEFORE validation, so a data unit the combiner\n // went on to reject destroyed an unrelated in-flight sample.\n const c = combiner({ maxBuffered: 2 })\n for (const s of [17, 18, 19]) c.registerAuthoredSize(undefined, 1, 9, s, 10)\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 1, 1, 1, 1], 1000n, true))).toBeNull()\n expect(c.addMfu(mfu(1, 9, 18, 0, [2, 2, 2, 2, 2], 1001n, true))).toBeNull()\n expect(c.pendingCount).toBe(2)\n\n // 8 + 5 = 13 exceeds sample 19's authored size of 10.\n expect(() => c.addMfu(mfu(1, 9, 19, 8, [9, 9, 9, 9, 9], 2000n, false)))\n .toThrow(SampleCombineError)\n expect(c.stats.evictedSamples).toBe(0)\n expect(c.pendingCount).toBe(2)\n\n // Sample 17 is untouched and still completes.\n expect(c.addMfu(mfu(1, 9, 17, 5, [3, 3, 3, 3, 3], 2001n, false))?.data)\n .toEqual(new Uint8Array([1, 1, 1, 1, 1, 3, 3, 3, 3, 3]))\n })\n\n test('an evicted sample is retired rather than reopened', () => {\n const c = combiner({ maxBuffered: 1 })\n for (const s of [17, 18]) c.registerAuthoredSize(undefined, 1, 9, s, 10)\n expect(c.addMfu(mfu(1, 9, 17, 0, [1, 1, 1, 1, 1], 1000n, true))).toBeNull()\n expect(c.addMfu(mfu(1, 9, 18, 0, [2, 2, 2, 2, 2], 1001n, true))).toBeNull()\n expect(c.stats.evictedSamples).toBe(1)\n\n // Sample 17's tail arrives after its eviction; it must not reopen.\n expect(c.addMfu(mfu(1, 9, 17, 5, [3, 3, 3, 3, 3], 2000n, false))).toBeNull()\n expect(c.pendingCount).toBe(1)\n })\n })\n\n describe('sample-level delivery provenance', () => {\n test('one non-multicast subsample makes the whole sample non-exclusive', () => {\n // A 4K/8K sample is split across subsample DUs. If any one of them\n // arrived over QUIC, the assembled sample contains bytes that never\n // crossed a multicast socket, so the sample is not physical evidence\n // even though every other DU was multicast.\n const c = combiner()\n c.registerAuthoredSize(undefined, 1, 1, 1, 4)\n expect(c.addMfu(mfu(1, 1, 1, 0, [1, 2], 100n, true, 'multicast'))).toBeNull()\n const done = c.addMfu(mfu(1, 1, 1, 2, [3, 4], 100n, false, 'mixed'))\n expect(done).not.toBeNull()\n expect(done!.subsampleCount).toBe(2)\n expect(done!.deliveryProvenance).toBe('mixed')\n })\n\n test('an unattributed subsample degrades the sample to unknown', () => {\n const c = combiner()\n c.registerAuthoredSize(undefined, 2, 1, 1, 4)\n expect(c.addMfu(mfu(2, 1, 1, 0, [1, 2], 100n, true, 'multicast'))).toBeNull()\n const done = c.addMfu(mfu(2, 1, 1, 2, [3, 4], 100n, false, 'unknown'))\n expect(done).not.toBeNull()\n expect(done!.deliveryProvenance).toBe('unknown')\n })\n\n test('an all-multicast sample stays multicast-exclusive', () => {\n const c = combiner()\n c.registerAuthoredSize(undefined, 3, 1, 1, 4)\n expect(c.addMfu(mfu(3, 1, 1, 0, [1, 2], 100n, true, 'multicast'))).toBeNull()\n const done = c.addMfu(mfu(3, 1, 1, 2, [3, 4], 100n, false, 'multicast'))\n expect(done).not.toBeNull()\n expect(done!.deliveryProvenance).toBe('multicast')\n })\n\n test('a passthrough sample inherits its data unit provenance verbatim', () => {\n const c = combiner()\n const done = c.addMfu(mfu(4, 1, 1, 0, [1, 2], 100n, true, 'mixed'))\n expect(done).not.toBeNull()\n expect(done!.subsampleCount).toBe(1)\n expect(done!.deliveryProvenance).toBe('mixed')\n })\n })\n}\n", "/**\n * H.264/AVC codec utilities for MMTP container format conversion.\n *\n * Shared between moq-lib (hang-mmt-fec) and moqtail players.\n * Handles AVCC\u2194Annex-B conversion, SPS/PPS extraction, fallback avcC generation,\n * and MMTP timestamp conversion.\n *\n * @packageDocumentation\n */\n\n// \u2500\u2500\u2500 Public Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Result of extracting a video codec configuration record from an fMP4 init segment. */\nexport interface AvcCInfo {\n codec: string\n description: Uint8Array\n}\n\n/** Result of extracting AAC AudioSpecificConfig from an fMP4 init segment. */\nexport interface AacAscInfo {\n /** Codec string like \"mp4a.40.2\" (AAC-LC). Derived from AOT in ASC[0] >> 3. */\n codec: string\n /** AudioSpecificConfig bytes \u2014 what AudioDecoder.configure({description}) needs for raw AAC. */\n description: Uint8Array\n}\n\n/** SPS and PPS NAL units extracted from an avcC record. */\nexport interface SpsPps {\n sps: Uint8Array\n pps: Uint8Array\n}\n\n/** Options for fallback avcC generation. */\nexport interface FallbackAvcCOptions {\n /** Codec string like \"avc1.640033\". Profile/constraint/level parsed from hex triplet. */\n codec?: string\n /** Coded width in pixels. Used in SPS pic_width_in_mbs. */\n width?: number\n /** Coded height in pixels. Used in SPS pic_height_in_map_units. */\n height?: number\n}\n\n// \u2500\u2500\u2500 Public Functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Extract the codec configuration record (avcC/hvcC/av1C/vpcC) from\n * an fMP4 init segment (moov box).\n * MMTP FT=0 packets contain a complete fMP4: moov > trak > mdia > minf > stbl > stsd > sample entry > codec config.\n *\n * Walks every trak and returns the first supported video sample entry. This\n * handles both per-track CMSF init segments and multiplexed ftyp+moov blobs\n * where the audio trak may appear before video.\n */\nexport function extractAvcCFromInitSegment(data: Uint8Array): AvcCInfo | undefined {\n if (!hasIsoBmffMagic(data)) return undefined\n\n for (const stsd of findTrackStsdBoxes(data)) {\n const info = extractVideoConfigFromStsd(data, stsd)\n if (info) return info\n }\n\n return undefined\n}\n\nfunction extractVideoConfigFromStsd(data: Uint8Array, stsd: { o: number; sz: number }): AvcCInfo | undefined {\n let s = stsd.o + 16\n const e = stsd.o + stsd.sz\n\n // H.264: avc1 VisualSampleEntry \u2192 avcC.\n const avc1 = findBox(data, s, e, 'avc1')\n if (avc1 && avc1.sz >= 86) {\n const avcC = findBox(data, avc1.o + 86, avc1.o + avc1.sz, 'avcC')\n if (avcC && avcC.sz >= 12) {\n const d = data.subarray(avcC.o + 8, avcC.o + avcC.sz)\n const codec = `avc1.${hex2(d[1])}${hex2(d[2])}${hex2(d[3])}`\n return { codec, description: d }\n }\n }\n // HEVC: hvc1/hev1 VisualSampleEntry \u2192 hvcC. Same +86 child-box offset as\n // avc1 (identical VisualSampleEntry layout). Without this branch, HEVC\n // ftyp+moov inits yield no descriptor, so the WebCodecs path configures the\n // VideoDecoder with no `description` and the first length-prefixed hvc1\n // keyframe decode() throws DataError (\"must fill out the description field\"),\n // which the player's MoQ pump catch swallows \u2192 video track silently 0-fps\n // (BLO-8054).\n const hvc1 = findBox(data, s, e, 'hvc1') ?? findBox(data, s, e, 'hev1')\n if (hvc1 && hvc1.sz >= 86) {\n const hvcC = findBox(data, hvc1.o + 86, hvc1.o + hvc1.sz, 'hvcC')\n // HEVCDecoderConfigurationRecord is \u226523 bytes (+8 box header).\n if (hvcC && hvcC.sz >= 8 + 23) {\n const d = data.subarray(hvcC.o + 8, hvcC.o + hvcC.sz)\n return { codec: hevcCodecStringFromHvcC(d), description: d }\n }\n }\n // AV1: av01 VisualSampleEntry -> av1C. Real FFmpeg MMTP inits can carry an\n // empty av1C box (size=8) while still providing the authoritative sample\n // entry/codec signal. Return an empty description for that shape so callers\n // can open their FT=0 gate without passing a zero-byte WebCodecs description.\n const av01 = findBox(data, s, e, 'av01')\n if (av01 && av01.sz >= 86) {\n const av1C = findBox(data, av01.o + 86, av01.o + av01.sz, 'av1C')\n if (av1C && av1C.sz >= 8) {\n const d = data.subarray(av1C.o + 8, av1C.o + av1C.sz)\n return { codec: codecStringFromAv1C(d), description: d }\n }\n }\n // VP9: vp09 VisualSampleEntry -> vpcC. Some encoders omit the VP codec record\n // payload; use the sample entry as readiness evidence and fall back to a\n // conservative vp09 codec string in that case.\n const vp09 = findBox(data, s, e, 'vp09')\n if (vp09 && vp09.sz >= 86) {\n const vpcC = findBox(data, vp09.o + 86, vp09.o + vp09.sz, 'vpcC')\n if (vpcC && vpcC.sz >= 8) {\n const d = data.subarray(vpcC.o + 8, vpcC.o + vpcC.sz)\n return { codec: codecStringFromVpcC(d), description: d }\n }\n }\n return undefined\n}\n\n/**\n * Generate a minimal avcC (AVCDecoderConfigurationRecord) from codec parameters.\n * Parses \"avc1.XXYYZZ\" \u2192 profile_idc=0xXX, constraint_flags=0xYY, level_idc=0xZZ.\n * Width/height are encoded in the SPS; if not provided, they're inferred from the\n * H.264 level's max frame size (e.g. level 4.2 \u2192 2048x1088).\n * Used when late MoQ subscribers miss the FT=0 init segment (moov/avcC).\n */\nexport function generateFallbackAvcC(options?: FallbackAvcCOptions | string): Uint8Array {\n const opts: FallbackAvcCOptions = typeof options === 'string' ? { codec: options } : (options ?? {})\n\n let profile = 0x64\n let constraint = 0x00\n let level = 0x2a\n\n if (opts.codec) {\n const match = opts.codec.match(/^avc[13]\\.([0-9a-fA-F]{6})$/)\n if (match) {\n profile = Number.parseInt(match[1].substring(0, 2), 16)\n constraint = Number.parseInt(match[1].substring(2, 4), 16)\n level = Number.parseInt(match[1].substring(4, 6), 16)\n }\n }\n\n const { width, height } = resolveResolution(opts.width, opts.height, level)\n const sps = buildMinimalSps(profile, constraint, level, width, height)\n const pps = buildMinimalPps(profile)\n\n const avcC = new Uint8Array(5 + 1 + 2 + sps.length + 1 + 2 + pps.length)\n let w = 0\n avcC[w++] = 0x01\n avcC[w++] = profile\n avcC[w++] = constraint\n avcC[w++] = level\n avcC[w++] = 0xff\n avcC[w++] = 0xe1\n avcC[w++] = (sps.length >> 8) & 0xff\n avcC[w++] = sps.length & 0xff\n avcC.set(sps, w)\n w += sps.length\n avcC[w++] = 0x01\n avcC[w++] = (pps.length >> 8) & 0xff\n avcC[w++] = pps.length & 0xff\n avcC.set(pps, w)\n return avcC\n}\n\n/**\n * Extract raw SPS and PPS NAL unit bytes from an avcC (AVCDecoderConfigurationRecord).\n * Returns the first SPS and first PPS found.\n */\nexport function extractSpsPpsFromAvcC(avcC: Uint8Array): SpsPps | undefined {\n if (avcC.length < 8) return undefined\n const numSPS = avcC[5] & 0x1f\n let offset = 6\n let sps: Uint8Array | undefined\n for (let i = 0; i < numSPS && offset + 2 <= avcC.length; i++) {\n const spsLen = (avcC[offset] << 8) | avcC[offset + 1]\n offset += 2\n if (offset + spsLen <= avcC.length) {\n if (!sps) sps = avcC.subarray(offset, offset + spsLen)\n offset += spsLen\n }\n }\n let pps: Uint8Array | undefined\n if (offset < avcC.length) {\n const numPPS = avcC[offset] & 0x1f\n offset++\n for (let i = 0; i < numPPS && offset + 2 <= avcC.length; i++) {\n const ppsLen = (avcC[offset] << 8) | avcC[offset + 1]\n offset += 2\n if (offset + ppsLen <= avcC.length) {\n if (!pps) pps = avcC.subarray(offset, offset + ppsLen)\n offset += ppsLen\n }\n }\n }\n return sps && pps ? { sps, pps } : undefined\n}\n\n/**\n * Convert AVCC (4-byte NAL length prefixed) to Annex-B (start code prefixed).\n * Prepends SPS/PPS NALs before keyframes.\n */\nexport function avccToAnnexB(avccData: Uint8Array, isKeyframe: boolean, spsPps: SpsPps): Uint8Array {\n let offset = 0\n let totalNalSize = 0\n let nalCount = 0\n while (offset + 4 <= avccData.length) {\n const nalLen =\n (avccData[offset] << 24) |\n (avccData[offset + 1] << 16) |\n (avccData[offset + 2] << 8) |\n avccData[offset + 3]\n offset += 4\n if (nalLen <= 0 || offset + nalLen > avccData.length) break\n totalNalSize += nalLen\n nalCount++\n offset += nalLen\n }\n if (nalCount === 0) return avccData\n\n let outSize = nalCount * 4 + totalNalSize\n if (isKeyframe) {\n outSize += 4 + spsPps.sps.length + 4 + spsPps.pps.length\n }\n const out = new Uint8Array(outSize)\n let w = 0\n\n if (isKeyframe) {\n out[w++] = 0; out[w++] = 0; out[w++] = 0; out[w++] = 1\n out.set(spsPps.sps, w); w += spsPps.sps.length\n out[w++] = 0; out[w++] = 0; out[w++] = 0; out[w++] = 1\n out.set(spsPps.pps, w); w += spsPps.pps.length\n }\n\n offset = 0\n while (offset + 4 <= avccData.length) {\n const nalLen =\n (avccData[offset] << 24) |\n (avccData[offset + 1] << 16) |\n (avccData[offset + 2] << 8) |\n avccData[offset + 3]\n offset += 4\n if (nalLen <= 0 || offset + nalLen > avccData.length) break\n out[w++] = 0; out[w++] = 0; out[w++] = 0; out[w++] = 1\n out.set(avccData.subarray(offset, offset + nalLen), w)\n w += nalLen\n offset += nalLen\n }\n return out\n}\n\n/**\n * Build an avcC record by parsing Annex-B data to extract SPS (NAL type 7) and PPS (NAL type 8).\n * Returns the avcC record, or null if SPS/PPS not found.\n */\nexport function extractCodecDescriptionFromAnnexB(data: Uint8Array): Uint8Array | null {\n const nalUnits: Array<{ type: number; data: Uint8Array }> = []\n let i = 0\n while (i < data.length - 4) {\n if (data[i] === 0 && data[i + 1] === 0) {\n let nalStart = 0\n if (data[i + 2] === 1) {\n nalStart = i + 3\n } else if (data[i + 2] === 0 && data[i + 3] === 1) {\n nalStart = i + 4\n }\n if (nalStart > 0 && nalStart < data.length) {\n let nalEnd = data.length\n for (let j = nalStart; j < data.length - 3; j++) {\n if (data[j] === 0 && data[j + 1] === 0 &&\n (data[j + 2] === 1 || (data[j + 2] === 0 && data[j + 3] === 1))) {\n nalEnd = j\n break\n }\n }\n const nalType = data[nalStart] & 0x1f\n nalUnits.push({ type: nalType, data: data.slice(nalStart, nalEnd) })\n i = nalEnd\n continue\n }\n }\n i++\n }\n\n const sps = nalUnits.find(n => n.type === 7)\n const pps = nalUnits.find(n => n.type === 8)\n if (!sps || !pps) return null\n\n const avcCLength = 6 + 2 + sps.data.length + 1 + 2 + pps.data.length\n const avcC = new Uint8Array(avcCLength)\n let offset = 0\n avcC[offset++] = 1\n avcC[offset++] = sps.data[1]\n avcC[offset++] = sps.data[2]\n avcC[offset++] = sps.data[3]\n avcC[offset++] = 0xff\n avcC[offset++] = 0xe1\n avcC[offset++] = (sps.data.length >> 8) & 0xff\n avcC[offset++] = sps.data.length & 0xff\n avcC.set(sps.data, offset); offset += sps.data.length\n avcC[offset++] = 1\n avcC[offset++] = (pps.data.length >> 8) & 0xff\n avcC[offset++] = pps.data.length & 0xff\n avcC.set(pps.data, offset)\n return avcC\n}\n\n/**\n * Derive codec string from avcC record (e.g. \"avc1.640033\").\n */\nexport function codecStringFromAvcC(avcC: Uint8Array): string {\n if (avcC.length < 4) return 'avc1.640033'\n return `avc1.${hex2(avcC[1])}${hex2(avcC[2])}${hex2(avcC[3])}`\n}\n\n/** VPS/SPS/PPS NAL units extracted from an HEVC keyframe (raw NAL bytes, no start code/length prefix). */\nexport interface HevcParameterSets {\n vps?: Uint8Array\n sps?: Uint8Array\n pps?: Uint8Array\n}\n\n/** True for HEVC/H.265 codec strings (hev1.* / hvc1.*). */\nexport function isHevcCodec(codec: string): boolean {\n return codec.startsWith('hev1') || codec.startsWith('hvc1')\n}\n\n/** HEVC NAL unit type from the first NAL header byte: (byte >> 1) & 0x3f. */\nfunction hevcNalType(nal: Uint8Array): number {\n return (nal[0] >> 1) & 0x3f\n}\n\n/**\n * Remove H.26x emulation-prevention bytes (0x03 after 0x00 0x00) from an RBSP so\n * fixed-position fields (e.g. HEVC profile_tier_level) can be read by byte offset.\n */\nexport function removeEmulationPrevention(rbsp: Uint8Array): Uint8Array {\n const out: number[] = []\n let zeros = 0\n for (let i = 0; i < rbsp.length; i++) {\n const b = rbsp[i]\n if (zeros >= 2 && b === 0x03 && i + 1 < rbsp.length && rbsp[i + 1] <= 0x03) {\n zeros = 0\n continue\n }\n out.push(b)\n zeros = b === 0 ? zeros + 1 : 0\n }\n return Uint8Array.from(out)\n}\n\n/**\n * Split an AVCC/hvcC bitstream (length-prefixed NAL units) into raw NAL byte slices.\n * `lengthSize` is the NAL length prefix width (4 for FFmpeg LOC / fMP4 sample data).\n */\nexport function splitAvccNalUnits(data: Uint8Array, lengthSize = 4): Uint8Array[] {\n const nals: Uint8Array[] = []\n let i = 0\n while (i + lengthSize <= data.length) {\n let len = 0\n for (let k = 0; k < lengthSize; k++) len = (len << 8) | data[i + k]\n i += lengthSize\n if (len <= 0 || i + len > data.length) break\n nals.push(data.subarray(i, i + len))\n i += len\n }\n return nals\n}\n\n/**\n * True when `data` is exactly one or more length-prefixed NAL units.\n *\n * This is intentionally stricter than \"starts with a plausible length\": a\n * H.264 AVCC access unit may begin with bytes `00 00 00 01` when the first\n * NAL is a one-byte AUD. That byte pattern is also an Annex-B start code, so\n * callers must prove the whole buffer is complete AVCC before falling back to\n * Annex-B detection/conversion.\n */\nexport function isCompleteAvccSample(data: Uint8Array, lengthSize = 4): boolean {\n let i = 0\n let count = 0\n while (i + lengthSize <= data.length) {\n let len = 0\n for (let k = 0; k < lengthSize; k++) len = (len << 8) | data[i + k]\n i += lengthSize\n if (len <= 0 || i + len > data.length) return false\n i += len\n count++\n }\n return count > 0 && i === data.length\n}\n\nexport type H264SampleFormat = 'avcc' | 'annexb' | 'raw-nal' | 'unknown'\nexport type H264NalUnitFormat = H264SampleFormat | 'partial-avcc'\n\nexport interface H264AvccSample {\n data: Uint8Array\n format: H264SampleFormat\n}\n\nexport interface H264NalUnitSample {\n nals: Uint8Array[]\n format: H264NalUnitFormat\n}\n\n/**\n * Normalize a H.264 access unit/sample to length-prefixed AVCC for fMP4 mdat\n * payloads. Already-AVCC samples are returned as-is. Annex-B and single raw\n * NAL samples are converted one-way to AVCC at the MSE/fMP4 boundary.\n */\nexport function normalizeH264SampleToAvcc(data: Uint8Array): H264AvccSample {\n if (isCompleteAvccSample(data)) return { data, format: 'avcc' }\n if (isAnnexB(data)) return { data: annexBToAvcc(data), format: 'annexb' }\n if (isLikelyRawH264NalUnit(data)) return { data: rawH264NalToAvcc(data), format: 'raw-nal' }\n return { data, format: 'unknown' }\n}\n\n/**\n * Split a H.264 access unit/sample into NAL units without changing its framing.\n * Use this for routing, keyframe gates, and diagnostics. Conversion to AVCC is\n * reserved for `normalizeH264SampleToAvcc` at the fMP4/MSE boundary.\n */\nexport function splitH264SampleNalUnits(\n data: Uint8Array,\n options: H264KeyframeDetectionOptions = {},\n): H264NalUnitSample {\n if (isCompleteAvccSample(data)) return { nals: splitAvccNalUnits(data), format: 'avcc' }\n if (isAnnexB(data)) return { nals: splitAnnexBNalUnits(data), format: 'annexb' }\n if (options.allowPartialAvcc === true) {\n const partial = splitPartialAvccNalUnits(data)\n if (partial.length > 0) return { nals: partial, format: 'partial-avcc' }\n }\n if (isLikelyRawH264NalUnit(data)) return { nals: [data], format: 'raw-nal' }\n const nals = splitAvccNalUnits(data)\n return { nals, format: nals.length > 0 ? 'avcc' : 'unknown' }\n}\n\n/**\n * Extract HEVC VPS (type 32) / SPS (33) / PPS (34) NAL units from a keyframe access\n * unit. Accepts either Annex-B (start-code delimited) or AVCC/hvcC (length-prefixed)\n * framing \u2014 FFmpeg LOC delivers the latter.\n */\nexport function extractHevcParameterSets(keyframe: Uint8Array): HevcParameterSets {\n const nals = isAnnexB(keyframe) ? splitAnnexBNalUnits(keyframe) : splitAvccNalUnits(keyframe)\n const out: HevcParameterSets = {}\n for (const nal of nals) {\n if (nal.length === 0) continue\n const t = hevcNalType(nal)\n if (t === 32 && !out.vps) out.vps = nal\n else if (t === 33 && !out.sps) out.sps = nal\n else if (t === 34 && !out.pps) out.pps = nal\n }\n return out\n}\n\n/**\n * Build a minimal hvcC (HEVCDecoderConfigurationRecord, ISO 14496-15 \u00A78.3.3.1) from\n * VPS/SPS/PPS NAL units. The general profile_tier_level (12 bytes) is copied from the\n * SPS (de-emulated); remaining fields use the common 4:2:0 / 8-bit / 4-byte-NAL-length\n * defaults. Suitable as the `description` for a WebCodecs hvc1 VideoDecoderConfig.\n *\n * WebCodecs REQUIRES a description for length-prefixed HEVC \u2014 unlike H.264, Chrome will\n * not self-configure HEVC from the bitstream (BLO-7764).\n */\nexport function generateHvcCFromParameterSets(sets: HevcParameterSets): Uint8Array | null {\n const { vps, sps, pps } = sets\n if (!sps || !pps) return null\n const spsRbsp = removeEmulationPrevention(sps)\n // general profile_tier_level is 12 bytes at RBSP offset 3:\n // 2-byte NAL header + 1 byte (sps_video_parameter_set_id u(4), sps_max_sub_layers_minus1\n // u(3), sps_temporal_id_nesting_flag u(1)), then general_profile_space..general_level_idc.\n const ptl = spsRbsp.subarray(3, 15)\n const arrays = [\n { type: 32, nal: vps },\n { type: 33, nal: sps },\n { type: 34, nal: pps },\n ].filter((a): a is { type: number; nal: Uint8Array } => a.nal !== undefined)\n\n let size = 23\n for (const a of arrays) size += 5 + a.nal.length\n const h = new Uint8Array(size)\n let o = 0\n h[o++] = 1 // configurationVersion\n for (let i = 0; i < 12; i++) h[o++] = ptl[i] ?? 0 // general profile_tier_level\n h[o++] = 0xf0; h[o++] = 0x00 // reserved(1111) + min_spatial_segmentation_idc(0)\n h[o++] = 0xfc // reserved(111111) + parallelismType(0)\n h[o++] = 0xfd // reserved(111111) + chromaFormat(1 = 4:2:0)\n h[o++] = 0xf8 // reserved(11111) + bitDepthLumaMinus8(0)\n h[o++] = 0xf8 // reserved(11111) + bitDepthChromaMinus8(0)\n h[o++] = 0x00; h[o++] = 0x00 // avgFrameRate(0 = unspecified)\n h[o++] = 0x0b // CFR(0) numTempLayers(1) nested(0) lengthSizeMinusOne(3)\n h[o++] = arrays.length // numOfArrays\n for (const a of arrays) {\n h[o++] = a.type & 0x3f // array_completeness(0) + NAL_unit_type\n h[o++] = 0; h[o++] = 1 // numNalus = 1\n h[o++] = (a.nal.length >> 8) & 0xff\n h[o++] = a.nal.length & 0xff\n h.set(a.nal, o); o += a.nal.length\n }\n return h.subarray(0, o)\n}\n\n/**\n * Build an hvcC `description` for a WebCodecs HEVC VideoDecoderConfig directly from a\n * keyframe access unit (Annex-B or length-prefixed). Returns null if VPS/SPS/PPS aren't\n * present in-band. HEVC analogue of {@link extractCodecDescriptionFromAnnexB}.\n */\nexport function extractHevcCodecDescription(keyframe: Uint8Array): Uint8Array | null {\n return generateHvcCFromParameterSets(extractHevcParameterSets(keyframe))\n}\n\n/**\n * Strip non-VCL NAL units (VPS/SPS/PPS/SEI/AUD, type >= 32) from an HEVC access unit,\n * returning only the VCL NAL units (type <= 31) as a 4-byte length-prefixed buffer.\n *\n * Required when decoding `hvc1` with an explicit hvcC `description`: WebCodecs rejects a\n * sample whose data still carries in-band parameter sets (\"Unable to determine size of\n * bitstream buffer\"). Accepts Annex-B or length-prefixed input. Returns the input\n * unchanged if it already contains only VCL NALs (cheap no-op for delta frames).\n */\nexport function hevcVclOnly(data: Uint8Array): Uint8Array {\n const nals = isAnnexB(data) ? splitAnnexBNalUnits(data) : splitAvccNalUnits(data)\n const vcl = nals.filter((n) => n.length > 0 && hevcNalType(n) <= 31)\n if (vcl.length === nals.length && !isAnnexB(data)) return data\n let size = 0\n for (const n of vcl) size += 4 + n.length\n const out = new Uint8Array(size)\n let o = 0\n for (const n of vcl) {\n out[o++] = (n.length >> 24) & 0xff\n out[o++] = (n.length >> 16) & 0xff\n out[o++] = (n.length >> 8) & 0xff\n out[o++] = n.length & 0xff\n out.set(n, o); o += n.length\n }\n return out\n}\n\n/**\n * Check if data starts with an Annex-B start code (00 00 01 or 00 00 00 01).\n */\nexport function isAnnexB(data: Uint8Array): boolean {\n if (data.length >= 4 && data[0] === 0 && data[1] === 0 &&\n (data[2] === 1 || (data[2] === 0 && data[3] === 1))) {\n return true\n }\n return false\n}\n\n/**\n * Find the byte offset of the first Annex-B start code in data.\n * Returns -1 if no start code found.\n */\nexport function findAnnexBStartCode(data: Uint8Array): number {\n for (let i = 0; i < data.length - 3; i++) {\n if (data[i] === 0 && data[i + 1] === 0) {\n if (data[i + 2] === 1) return i\n if (data[i + 2] === 0 && data[i + 3] === 1) return i\n }\n }\n return -1\n}\n\n/**\n * Split Annex-B bitstream into NAL units.\n * Returns array of NAL unit byte slices (without start codes).\n */\nexport function splitAnnexBNalUnits(data: Uint8Array): Uint8Array[] {\n const nalUnits: Uint8Array[] = []\n let i = 0\n while (i < data.length - 3) {\n if (data[i] === 0 && data[i + 1] === 0) {\n let scLen = 0\n if (data[i + 2] === 1) scLen = 3\n else if (data[i + 2] === 0 && i + 3 < data.length && data[i + 3] === 1) scLen = 4\n if (scLen > 0) {\n const nalStart = i + scLen\n let nalEnd = data.length\n for (let j = nalStart + 1; j < data.length - 2; j++) {\n if (data[j] === 0 && data[j + 1] === 0 &&\n (data[j + 2] === 1 || (data[j + 2] === 0 && j + 3 < data.length && data[j + 3] === 1))) {\n nalEnd = j\n break\n }\n }\n if (nalEnd > nalStart) nalUnits.push(data.subarray(nalStart, nalEnd))\n i = nalEnd\n continue\n }\n }\n i++\n }\n return nalUnits\n}\n\n/**\n * Convert Annex-B (start-code delimited) to AVCC (4-byte length prefixed).\n * Optionally prepends SPS/PPS NALs for keyframes.\n */\nexport function annexBToAvcc(data: Uint8Array, spsPps?: SpsPps): Uint8Array {\n const nalUnits = splitAnnexBNalUnits(data)\n if (nalUnits.length === 0) return data\n\n let extraSize = 0\n if (spsPps) {\n extraSize = 4 + spsPps.sps.length + 4 + spsPps.pps.length\n }\n const frameSize = nalUnits.reduce((sum, nal) => sum + 4 + nal.length, 0)\n const output = new Uint8Array(extraSize + frameSize)\n let w = 0\n\n if (spsPps) {\n w = writeNalLength(output, w, spsPps.sps.length)\n output.set(spsPps.sps, w); w += spsPps.sps.length\n w = writeNalLength(output, w, spsPps.pps.length)\n output.set(spsPps.pps, w); w += spsPps.pps.length\n }\n\n for (const nal of nalUnits) {\n w = writeNalLength(output, w, nal.length)\n output.set(nal, w); w += nal.length\n }\n return output\n}\n\nexport interface H264KeyframeDetectionOptions {\n /**\n * Allow classifying a length-prefixed NAL when the declared NAL length runs\n * beyond this buffer. MMTP routing can see only the first packet fragment of\n * a sample, where the NAL header is present but the full NAL is not.\n */\n allowPartialAvcc?: boolean\n}\n\n/**\n * Classify H.264 keyframe status by scanning NAL units. Returns undefined when\n * the payload is not H.264-classifiable. Handles Annex-B and AVCC formats.\n */\nexport function classifyH264Keyframe(\n data: Uint8Array,\n options: H264KeyframeDetectionOptions = {},\n): boolean | undefined {\n const nals = h264NalUnitsForKeyframeDetection(data, options)\n if (nals.length === 0) return undefined\n let sawIntraSlice = false\n let sawNonIntraVcl = false\n let sawNal = false\n for (const nal of nals) {\n sawNal = true\n const nalType = nal[0] !== undefined ? nal[0] & 0x1f : -1\n if (nalType === 5 || nalType === 7) return true\n if (nalType === 1) {\n if (isH264IntraSlice(nal)) sawIntraSlice = true\n else sawNonIntraVcl = true\n }\n }\n if (sawIntraSlice && !sawNonIntraVcl) return true\n return sawNal ? false : undefined\n}\n\n/**\n * Detect H.264 keyframe by scanning for IDR/SPS or intra non-IDR slices.\n * Handles both Annex-B and AVCC formats.\n */\nexport function detectH264Keyframe(\n data: Uint8Array,\n options: H264KeyframeDetectionOptions = {},\n): boolean {\n return classifyH264Keyframe(data, options) === true\n}\n\n/**\n * Convert MMTP timestamp (NTP short format) to monotonic microseconds.\n * Per ISO 23008-1 \u00A79.2.2 / RFC 5905: upper 16 bits = seconds (lower 16\n * of NTP seconds), lower 16 bits = fractional seconds.\n * Returns a monotonically increasing \u00B5s value within an ~18-hour window.\n */\nexport function mmtpTimestampToMicros(rawTs: bigint | number): number {\n const ts = Number(rawTs) >>> 0 // ensure unsigned 32-bit\n if (ts === 0) return 0\n const seconds = ts >>> 16\n const frac = ts & 0xFFFF\n return seconds * 1_000_000 + Math.floor(frac * 1_000_000 / 65536)\n}\n\n/** Validate the CMSF/MMTP catalog initData contract: complete top-level ftyp+moov. */\nexport function isFmp4InitSegment(data: Uint8Array): boolean {\n let offset = 0\n let sawFtyp = false\n let sawMoov = false\n\n while (offset + 8 <= data.byteLength) {\n const view = new DataView(data.buffer, data.byteOffset + offset, data.byteLength - offset)\n let size = view.getUint32(0, false)\n const type = String.fromCharCode(data[offset + 4]!, data[offset + 5]!, data[offset + 6]!, data[offset + 7]!)\n let headerSize = 8\n\n if (size === 1) {\n if (offset + 16 > data.byteLength) return false\n const largeSize = view.getBigUint64(8, false)\n if (largeSize > BigInt(Number.MAX_SAFE_INTEGER)) return false\n size = Number(largeSize)\n headerSize = 16\n } else if (size === 0) {\n size = data.byteLength - offset\n }\n\n if (size < headerSize || offset + size > data.byteLength) return false\n if (type === 'ftyp') sawFtyp = true\n if (type === 'moov') {\n if (!sawFtyp) return false\n sawMoov = true\n }\n offset += size\n }\n\n return offset === data.byteLength && sawFtyp && sawMoov\n}\n\n// \u2500\u2500\u2500 Internal Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction hasIsoBmffMagic(data: Uint8Array): boolean {\n for (let i = 0; i + 8 <= data.length && i < 32; i += 4) {\n const tag = String.fromCharCode(data[i + 4], data[i + 5], data[i + 6], data[i + 7])\n if (tag === 'ftyp' || tag === 'moov') return true\n }\n return false\n}\n\nfunction findTrackStsdBoxes(data: Uint8Array): Array<{ o: number; sz: number }> {\n const moov = findBox(data, 0, data.length, 'moov')\n if (!moov) return []\n\n const out: Array<{ o: number; sz: number }> = []\n for (const trak of findBoxes(data, moov.o + 8, moov.o + moov.sz, 'trak')) {\n const stsd = findNestedBox(data, trak.o + 8, trak.o + trak.sz, ['mdia', 'minf', 'stbl', 'stsd'])\n if (stsd) out.push(stsd)\n }\n return out\n}\n\nfunction findNestedBox(\n buf: Uint8Array,\n start: number,\n end: number,\n path: string[],\n): { o: number; sz: number } | undefined {\n let s = start\n let e = end\n let current: { o: number; sz: number } | undefined\n for (const type of path) {\n current = findBox(buf, s, e, type)\n if (!current) return undefined\n s = current.o + 8\n e = current.o + current.sz\n }\n return current\n}\n\nfunction findBox(buf: Uint8Array, start: number, end: number, type: string): { o: number; sz: number } | undefined {\n return findBoxes(buf, start, end, type)[0]\n}\n\nfunction findBoxes(buf: Uint8Array, start: number, end: number, type: string): Array<{ o: number; sz: number }> {\n const boxes: Array<{ o: number; sz: number }> = []\n let o = start\n while (o + 8 <= end) {\n let sz = (buf[o] << 24) | (buf[o + 1] << 16) | (buf[o + 2] << 8) | buf[o + 3]\n const t = String.fromCharCode(buf[o + 4], buf[o + 5], buf[o + 6], buf[o + 7])\n if (sz === 0) sz = end - o\n if (sz < 8 || o + sz > end) break\n if (t === type) boxes.push({ o, sz })\n o += sz\n }\n return boxes\n}\n\nfunction writeNalLength(buf: Uint8Array, offset: number, len: number): number {\n buf[offset] = (len >> 24) & 0xff\n buf[offset + 1] = (len >> 16) & 0xff\n buf[offset + 2] = (len >> 8) & 0xff\n buf[offset + 3] = len & 0xff\n return offset + 4\n}\n\nfunction h264NalUnitsForKeyframeDetection(\n data: Uint8Array,\n options: H264KeyframeDetectionOptions,\n): Uint8Array[] {\n return splitH264SampleNalUnits(data, options).nals\n}\n\nfunction splitPartialAvccNalUnits(data: Uint8Array, lengthSize = 4): Uint8Array[] {\n const nals: Uint8Array[] = []\n let i = 0\n while (i + lengthSize < data.length) {\n let len = 0\n for (let k = 0; k < lengthSize; k++) len = (len << 8) | data[i + k]\n i += lengthSize\n if (len <= 0 || i >= data.length) break\n const end = Math.min(i + len, data.length)\n nals.push(data.subarray(i, end))\n if (end < i + len) break\n i = end\n }\n return nals\n}\n\nfunction isLikelyRawH264NalUnit(data: Uint8Array): boolean {\n if (data.length === 0) return false\n const header = data[0]!\n if ((header & 0x80) !== 0) return false\n const nalType = header & 0x1f\n return nalType > 0 && nalType < 24\n}\n\nfunction rawH264NalToAvcc(data: Uint8Array): Uint8Array {\n const out = new Uint8Array(4 + data.length)\n new DataView(out.buffer, out.byteOffset, out.byteLength).setUint32(0, data.length)\n out.set(data, 4)\n return out\n}\n\nfunction isH264IntraSlice(nal: Uint8Array): boolean {\n const sliceType = readH264SliceType(nal)\n return sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9\n}\n\nfunction readH264SliceType(nal: Uint8Array): number | null {\n if (nal.length < 2 || (nal[0]! & 0x1f) !== 1) return null\n const rbsp = removeEmulationPrevention(nal.subarray(1))\n const state = { bitOffset: 0 }\n if (readUnsignedExpGolomb(rbsp, state) === null) return null\n return readUnsignedExpGolomb(rbsp, state)\n}\n\nfunction readUnsignedExpGolomb(data: Uint8Array, state: { bitOffset: number }): number | null {\n let leadingZeroBits = 0\n while (true) {\n const bit = readBit(data, state)\n if (bit === null) return null\n if (bit === 1) break\n leadingZeroBits++\n if (leadingZeroBits > 30) return null\n }\n\n let suffix = 0\n for (let i = 0; i < leadingZeroBits; i++) {\n const bit = readBit(data, state)\n if (bit === null) return null\n suffix = (suffix << 1) | bit\n }\n return (1 << leadingZeroBits) - 1 + suffix\n}\n\nfunction readBit(data: Uint8Array, state: { bitOffset: number }): 0 | 1 | null {\n if (state.bitOffset >= data.length * 8) return null\n const byte = data[state.bitOffset >> 3]!\n const bit = (byte >> (7 - (state.bitOffset & 7))) & 1\n state.bitOffset++\n return bit as 0 | 1\n}\n\nfunction hex2(n: number): string {\n return n.toString(16).padStart(2, '0')\n}\n\nfunction pad2(n: number): string {\n return String(n).padStart(2, '0')\n}\n\nfunction codecStringFromAv1C(av1C: Uint8Array): string {\n if (av1C.length < 4) return 'av01.0.01M.08'\n const profile = (av1C[1]! >>> 5) & 0x07\n const level = av1C[1]! & 0x1f\n const tier = (av1C[2]! & 0x80) !== 0 ? 'H' : 'M'\n let bitDepth = 8\n if ((av1C[2]! & 0x40) !== 0) {\n bitDepth = (av1C[2]! & 0x20) !== 0 ? 12 : 10\n }\n return `av01.${profile}.${pad2(level)}${tier}.${pad2(bitDepth)}`\n}\n\nfunction codecStringFromVpcC(vpcC: Uint8Array): string {\n if (vpcC.length < 3) return 'vp09.00.10.08'\n // ISO/IEC 14496-15 defines vpcC as a FullBox. Some tooling hands callers\n // the VPCodecConfigurationRecord after the 4-byte FullBox header; tolerate\n // both shapes because WebCodecs callers only need a stable RFC 6381 fallback.\n const offset = vpcC.length >= 7 && vpcC[0] <= 1 ? 4 : 0\n if (offset + 2 >= vpcC.length) return 'vp09.00.10.08'\n const profile = vpcC[offset]!\n const level = vpcC[offset + 1]!\n const bitDepth = (vpcC[offset + 2]! >>> 4) || 8\n return `vp09.${pad2(profile)}.${pad2(level)}.${pad2(bitDepth)}`\n}\n\n/**\n * Derive an RFC 6381 HEVC codec string (e.g. \"hvc1.1.6.L93.90\") from the\n * payload of an hvcC box (the HEVCDecoderConfigurationRecord, ISO 14496-15 \u00A78.3.3.1).\n * Only the general_* fields in the fixed 23-byte header are needed:\n * byte 1: general_profile_space(2) | general_tier_flag(1) | general_profile_idc(5)\n * bytes 2-5: general_profile_compatibility_flags (32 bits)\n * bytes 6-11: general_constraint_indicator_flags (48 bits)\n * byte 12: general_level_idc\n */\nfunction hevcCodecStringFromHvcC(c: Uint8Array): string {\n const profileSpace = (c[1] >> 6) & 0x3\n const tierFlag = (c[1] >> 5) & 0x1\n const profileIdc = c[1] & 0x1f\n // Compatibility flags are emitted reversed bit-order as hex, leading zeros trimmed.\n const compat = ((c[2] << 24) | (c[3] << 16) | (c[4] << 8) | c[5]) >>> 0\n let rev = 0\n let v = compat\n for (let i = 0; i < 32; i++) {\n rev = ((rev << 1) | (v & 1)) >>> 0\n v >>>= 1\n }\n const compatStr = rev.toString(16)\n // Constraint flags: dot-separated hex bytes, trailing zero bytes trimmed.\n const constraint = c.subarray(6, 12)\n let lastNonZero = -1\n for (let i = 0; i < constraint.length; i++) if (constraint[i] !== 0) lastNonZero = i\n const constraintParts: string[] = []\n for (let i = 0; i <= lastNonZero; i++) constraintParts.push(constraint[i].toString(16))\n const space = profileSpace === 0 ? '' : String.fromCharCode(64 + profileSpace) // 1\u2192'A', 2\u2192'B', 3\u2192'C'\n const tier = tierFlag === 0 ? 'L' : 'H'\n let s = `hvc1.${space}${profileIdc}.${compatStr}.${tier}${c[12]}`\n if (constraintParts.length > 0) s += '.' + constraintParts.join('.')\n return s\n}\n\n/** Exp-Golomb bitstream writer for SPS/PPS generation. */\nclass BitWriter {\n buf: number[] = []\n byte = 0\n bit = 7\n\n u(val: number, bits: number) {\n for (let i = bits - 1; i >= 0; i--) {\n this.byte |= ((val >> i) & 1) << this.bit\n if (--this.bit < 0) {\n this.buf.push(this.byte)\n this.byte = 0\n this.bit = 7\n }\n }\n }\n\n ue(val: number) {\n const v = val + 1\n const bits = Math.floor(Math.log2(v)) + 1\n this.u(0, bits - 1)\n this.u(v, bits)\n }\n\n se(val: number) {\n this.ue(val <= 0 ? -val * 2 : val * 2 - 1)\n }\n\n finish(): Uint8Array {\n if (this.bit < 7) {\n this.byte |= 1 << this.bit\n this.buf.push(this.byte)\n }\n return new Uint8Array(this.buf)\n }\n}\n\nfunction resolveResolution(\n explicitW: number | undefined,\n explicitH: number | undefined,\n level: number,\n): { width: number; height: number } {\n if (explicitW && explicitH) return { width: explicitW, height: explicitH }\n\n const levelResolutions: Record<number, [number, number]> = {\n 10: [176, 144], 11: [352, 288], 12: [352, 288], 13: [352, 288],\n 20: [352, 288], 21: [720, 576], 22: [720, 576],\n 30: [1280, 720], 31: [1280, 720], 32: [1280, 1024],\n 40: [1920, 1088], 41: [1920, 1088], 42: [2048, 1088],\n 50: [4096, 2160], 51: [4096, 2160], 52: [4096, 2160],\n }\n\n const [w, h] = levelResolutions[level] ?? [1920, 1088]\n return { width: explicitW ?? w, height: explicitH ?? h }\n}\n\nfunction buildMinimalSps(\n profile: number, constraint: number, level: number,\n width: number, height: number,\n): Uint8Array {\n const widthInMbs = Math.ceil(width / 16)\n const heightInMapUnits = Math.ceil(height / 16)\n\n const w = new BitWriter()\n w.u(0, 1); w.u(3, 2); w.u(7, 5) // NAL header: SPS\n w.u(profile, 8); w.u(constraint, 8); w.u(level, 8)\n w.ue(0) // seq_parameter_set_id\n\n if (profile === 100 || profile === 110 || profile === 122 || profile === 244 || profile === 44) {\n w.ue(1); w.ue(0); w.ue(0) // chroma + bit depth\n w.u(0, 1); w.u(0, 1) // transform bypass + scaling matrix\n }\n\n w.ue(0) // log2_max_frame_num_minus4\n w.ue(2) // pic_order_cnt_type=2\n w.ue(1) // max_num_ref_frames\n w.u(0, 1) // gaps_in_frame_num\n w.ue(widthInMbs - 1)\n w.ue(heightInMapUnits - 1)\n w.u(1, 1) // frame_mbs_only\n w.u(1, 1) // direct_8x8_inference\n\n const cropRight = widthInMbs * 16 - width\n const cropBottom = heightInMapUnits * 16 - height\n if (cropRight > 0 || cropBottom > 0) {\n w.u(1, 1)\n w.ue(0); w.ue(cropRight / 2); w.ue(0); w.ue(cropBottom / 2)\n } else {\n w.u(0, 1)\n }\n\n w.u(0, 1) // vui_parameters_present\n return w.finish()\n}\n\nfunction buildMinimalPps(profile: number): Uint8Array {\n const isHighProfile = profile === 100 || profile === 110 || profile === 122 || profile === 244 || profile === 44\n const w = new BitWriter()\n w.u(0, 1); w.u(3, 2); w.u(8, 5) // NAL header: PPS\n\n w.ue(0); w.ue(0) // pps_id, sps_id\n w.u(isHighProfile ? 1 : 0, 1) // entropy_coding_mode\n w.u(0, 1) // bottom_field_pic_order\n w.ue(0); w.ue(0); w.ue(0) // slice groups, ref_idx defaults\n w.u(0, 1); w.u(0, 2) // weighted_pred\n w.se(0); w.se(0); w.se(0) // qp offsets\n w.u(1, 1); w.u(0, 1); w.u(0, 1) // deblock, constrained_intra, redundant_pic_cnt\n\n if (isHighProfile) {\n w.u(1, 1); w.u(0, 1); w.se(0) // transform_8x8, scaling_matrix, chroma_qp_offset\n }\n\n return w.finish()\n}\n\n// \u2500\u2500\u2500 AAC / ADTS Utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** ISO 14496-3 sampling frequency index lookup. */\nconst ADTS_SAMPLE_RATES = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350] as const\n\n/**\n * Prepend a 7-byte ADTS header to a raw AAC access unit.\n *\n * WebCodecs AudioDecoder configured WITHOUT an AudioSpecificConfig `description`\n * expects ADTS-framed AAC. MMTP carries raw AAC (no ADTS sync), so this wrapper\n * must be applied before calling `AudioDecoder.decode()`.\n */\nexport function wrapAdtsFrame(raw: Uint8Array, sampleRate: number, channels: number): Uint8Array {\n const sri = ADTS_SAMPLE_RATES.indexOf(sampleRate as typeof ADTS_SAMPLE_RATES[number])\n const idx = sri >= 0 ? sri : 3 // default 48 kHz\n const len = 7 + raw.length\n const out = new Uint8Array(len)\n out[0] = 0xFF\n out[1] = 0xF1 // MPEG-4, Layer 0, no CRC\n out[2] = (1 << 6) | (idx << 2) | (channels >> 2) // profile=AAC-LC(1), freq, ch high\n out[3] = ((channels & 3) << 6) | ((len >> 11) & 3)\n out[4] = (len >> 3) & 0xFF\n out[5] = ((len & 7) << 5) | 0x1F\n out[6] = 0xFC\n out.set(raw, 7)\n return out\n}\n\n/**\n * Extract AAC AudioSpecificConfig (ASC) from an fMP4 init segment.\n *\n * Walks moov > trak > mdia > minf > stbl > stsd > mp4a > esds, then descends\n * the MPEG-4 descriptor chain (ES_Descriptor 0x03 > DecoderConfigDescriptor\n * 0x04 > DecoderSpecificInfo 0x05) to return the ASC payload.\n *\n * Sibling of extractAvcCFromInitSegment, used by the same BLO-4830 / CMSF \u00A73.1\n * path: when the catalog initData is the full ftyp+moov, WebCodecs' AudioDecoder\n * needs the raw ASC (~2 bytes for AAC-LC) as `description`, NOT the whole\n * segment. Without this extraction the configure() succeeds but every decode()\n * silently produces zero output (no error fires), exactly the symptom that\n * shows up as \"Audio continuity FAILED: energy unstable CV=1.00\" in the\n * 7-point E2E test (CV=1.00 is the meanEnergy=0 sentinel from audio-fft.mjs).\n *\n * Returns undefined when:\n * - data has no ftyp/moov magic in the first 32 bytes\n * - no mp4a sample entry exists in any trak's stbl\n * - the esds descriptor chain doesn't yield a DecoderSpecificInfo\n * - the ASC payload is shorter than 2 bytes (AOT + sampling-freq nibble)\n *\n * Walks every trak and returns the first AAC sample entry. This mirrors\n * extractAvcCFromInitSegment so multiplexed ftyp+moov init blobs work\n * regardless of track order.\n */\nexport function extractAacAscFromInitSegment(data: Uint8Array): AacAscInfo | undefined {\n if (!hasIsoBmffMagic(data)) return undefined\n\n for (const stsd of findTrackStsdBoxes(data)) {\n const info = extractAacAscFromStsd(data, stsd)\n if (info) return info\n }\n\n return undefined\n}\n\nfunction extractAacAscFromStsd(data: Uint8Array, stsd: { o: number; sz: number }): AacAscInfo | undefined {\n // stsd: 8 box header + 4 version+flags + 4 entry_count = 16 bytes before entries.\n const s = stsd.o + 16\n const e = stsd.o + stsd.sz\n // mp4a AudioSampleEntry minimum length: 8 box header + 28 fixed fields = 36 bytes\n // before any child boxes (esds lives here).\n const mp4a = findBox(data, s, e, 'mp4a')\n if (!mp4a || mp4a.sz < 36) return undefined\n const esds = findBox(data, mp4a.o + 36, mp4a.o + mp4a.sz, 'esds')\n // esds = 8 box header + 4 full-box version+flags = 12 bytes minimum before descriptors.\n if (!esds || esds.sz < 12) return undefined\n const esdsPayload = data.subarray(esds.o + 8, esds.o + esds.sz)\n const asc = extractAudioSpecificConfig(esdsPayload)\n if (!asc || asc.length < 2) return undefined\n // AudioObjectType = top 5 bits of ASC[0]. AAC-LC = 2, HE-AAC = 5, etc.\n const aot = asc[0] >> 3\n return { codec: `mp4a.40.${aot}`, description: asc }\n}\n\n/**\n * Walk an esds descriptor chain to find DecoderSpecificInfo (tag 0x05).\n * Step over fixed-size headers of container descriptors (0x03, 0x04) so the\n * scan continues into their children rather than skipping their full payload.\n *\n * Assumes the ES_Descriptor flags byte is zero (no streamDependence, URL, OCR\n * ES_ID fields). FFmpeg's mov/mp4 muxer emits exactly that for all standard\n * AAC tracks; the assumption is the same one extractAvcCFromInitSegment makes\n * about the avc1 sample entry's reserved fields.\n *\n * Input is the esds box payload AFTER the 8-byte box header; the first 4 bytes\n * (full-box version+flags) are skipped here.\n */\nfunction extractAudioSpecificConfig(esds: Uint8Array): Uint8Array | undefined {\n let offset = 4 // skip esds version+flags\n while (offset < esds.length) {\n const tag = esds[offset++]\n let size = 0\n for (let i = 0; i < 4 && offset < esds.length; i++) {\n const b = esds[offset++]\n size = (size << 7) | (b & 0x7f)\n if ((b & 0x80) === 0) break\n }\n if (tag === 0x05) {\n if (offset + size > esds.length) return undefined\n return esds.subarray(offset, offset + size)\n }\n if (tag === 0x03) {\n offset += 3 // ES_ID (2) + flags (1)\n } else if (tag === 0x04) {\n offset += 13 // OTI (1) + streamType (1) + bufferSizeDB (3) + maxBitrate (4) + avgBitrate (4)\n } else {\n offset += size\n }\n }\n return undefined\n}\n\n// =============================================================================\n// Inline Tests (vitest)\n// =============================================================================\n\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest\n\n describe('codec-utils', () => {\n describe('isAnnexB', () => {\n test('4-byte start code', () => {\n expect(isAnnexB(new Uint8Array([0, 0, 0, 1, 0x65]))).toBe(true)\n })\n test('3-byte start code', () => {\n expect(isAnnexB(new Uint8Array([0, 0, 1, 0x65]))).toBe(true)\n })\n test('rejects AVCC', () => {\n expect(isAnnexB(new Uint8Array([0, 0, 0, 10, 0x65]))).toBe(false)\n })\n })\n\n describe('findAnnexBStartCode', () => {\n test('at offset 0', () => {\n expect(findAnnexBStartCode(new Uint8Array([0, 0, 0, 1, 0x65]))).toBe(0)\n })\n test('at offset 5', () => {\n expect(findAnnexBStartCode(new Uint8Array([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0, 0, 1, 0x65]))).toBe(5)\n })\n test('returns -1 when none', () => {\n expect(findAnnexBStartCode(new Uint8Array([0xAA, 0xBB, 0xCC]))).toBe(-1)\n })\n })\n\n describe('splitAnnexBNalUnits', () => {\n test('splits two NALs', () => {\n const data = new Uint8Array([0, 0, 0, 1, 0x65, 0xAA, 0xBB, 0, 0, 0, 1, 0x41, 0xCC])\n const nals = splitAnnexBNalUnits(data)\n expect(nals.length).toBe(2)\n expect(nals[0]).toEqual(new Uint8Array([0x65, 0xAA, 0xBB]))\n expect(nals[1]).toEqual(new Uint8Array([0x41, 0xCC]))\n })\n test('handles 3-byte start codes', () => {\n const nals = splitAnnexBNalUnits(new Uint8Array([0, 0, 1, 0x67, 0x42, 0, 0, 1, 0x68, 0x01]))\n expect(nals.length).toBe(2)\n })\n })\n\n describe('annexBToAvcc', () => {\n test('converts single NAL', () => {\n const annexB = new Uint8Array([0, 0, 0, 1, 0x41, 0xAA, 0xBB])\n const avcc = annexBToAvcc(annexB)\n expect(avcc[3]).toBe(3) // NAL length\n expect(avcc[4]).toBe(0x41)\n })\n test('prepends SPS/PPS', () => {\n const annexB = new Uint8Array([0, 0, 0, 1, 0x65, 0x01])\n const avcc = annexBToAvcc(annexB, { sps: new Uint8Array([0x67, 0x42]), pps: new Uint8Array([0x68, 0x01]) })\n expect(avcc[3]).toBe(2) // SPS length\n expect(avcc[4]).toBe(0x67)\n })\n })\n\n describe('detectH264Keyframe', () => {\n test('IDR in Annex-B', () => {\n expect(detectH264Keyframe(new Uint8Array([0, 0, 0, 1, 0x65]))).toBe(true)\n })\n test('SPS in Annex-B', () => {\n expect(detectH264Keyframe(new Uint8Array([0, 0, 0, 1, 0x67]))).toBe(true)\n })\n test('IDR in AVCC', () => {\n expect(detectH264Keyframe(new Uint8Array([0, 0, 0, 5, 0x65, 1, 2, 3, 4]))).toBe(true)\n })\n test('IDR after AVCC AUD', () => {\n expect(detectH264Keyframe(new Uint8Array([\n 0, 0, 0, 1, 0x09,\n 0, 0, 0, 2, 0x65, 0xaa,\n ]))).toBe(true)\n })\n test('non-IDR AVC I-slice in AVCC', () => {\n expect(detectH264Keyframe(new Uint8Array([\n 0, 0, 0, 2, 0x41, 0x88,\n ]))).toBe(true)\n })\n test('raw H.264 IDR NAL', () => {\n expect(detectH264Keyframe(new Uint8Array([0x65, 0x88, 0x84]))).toBe(true)\n })\n test('raw H.264 non-IDR I-slice NAL', () => {\n expect(detectH264Keyframe(new Uint8Array([0x41, 0x88]))).toBe(true)\n })\n test('classifies partial length-prefixed IDR only when requested', () => {\n const partial = new Uint8Array([0, 0, 0x20, 0, 0x65])\n expect(classifyH264Keyframe(partial)).toBeUndefined()\n expect(classifyH264Keyframe(partial, { allowPartialAvcc: true })).toBe(true)\n })\n test('rejects P-frame', () => {\n expect(detectH264Keyframe(new Uint8Array([0, 0, 0, 1, 0x41]))).toBe(false)\n })\n test('rejects AVCC sample with only non-IDR slices', () => {\n expect(detectH264Keyframe(new Uint8Array([\n 0, 0, 0, 2, 0x41, 0xc0,\n 0, 0, 0, 2, 0x41, 0xc0,\n ]))).toBe(false)\n })\n })\n\n describe('avccToAnnexB', () => {\n test('converts with SPS/PPS on keyframe', () => {\n const avcc = new Uint8Array([0, 0, 0, 3, 0x65, 0xAA, 0xBB])\n const spsPps: SpsPps = { sps: new Uint8Array([0x67, 0x42]), pps: new Uint8Array([0x68, 0x01]) }\n const annexB = avccToAnnexB(avcc, true, spsPps)\n expect(annexB[3]).toBe(1) // start code\n expect(annexB[4]).toBe(0x67) // SPS\n })\n })\n\n describe('codecStringFromAvcC', () => {\n test('derives avc1.64002a', () => {\n expect(codecStringFromAvcC(new Uint8Array([1, 100, 0, 42]))).toBe('avc1.64002a')\n })\n })\n\n describe('extractAacAscFromInitSegment', () => {\n // Build a minimal valid ftyp+moov containing one mp4a sample entry whose\n // esds carries the supplied AudioSpecificConfig. The walker only needs\n // the box hierarchy moov > trak > mdia > minf > stbl > stsd > mp4a > esds;\n // mvhd/tkhd/mdhd/hdlr/smhd/dinf/stts/stsc/stsz/stco are spec-required for\n // a truly valid init but the extractor never reads them, so we omit them\n // to keep the fixture tight (~150 bytes vs ~500). FFmpeg's real output\n // includes them; the production path passes through `findBox` exactly\n // the same way.\n function buildMinimalAacInit(asc: Uint8Array): Uint8Array {\n const box = (type: string, payload: Uint8Array): Uint8Array => {\n const sz = 8 + payload.length\n const out = new Uint8Array(sz)\n out[0] = (sz >>> 24) & 0xff\n out[1] = (sz >>> 16) & 0xff\n out[2] = (sz >>> 8) & 0xff\n out[3] = sz & 0xff\n out[4] = type.charCodeAt(0); out[5] = type.charCodeAt(1)\n out[6] = type.charCodeAt(2); out[7] = type.charCodeAt(3)\n out.set(payload, 8)\n return out\n }\n const concat = (...arrs: Uint8Array[]): Uint8Array => {\n const total = arrs.reduce((n, a) => n + a.length, 0)\n const out = new Uint8Array(total)\n let off = 0\n for (const a of arrs) { out.set(a, off); off += a.length }\n return out\n }\n // ftyp: major_brand=iso5, minor=0x200, compat=iso5,iso6\n const ftyp = box('ftyp', new Uint8Array([\n 0x69, 0x73, 0x6f, 0x35, // 'iso5'\n 0x00, 0x00, 0x02, 0x00, // minor 0x200\n 0x69, 0x73, 0x6f, 0x35, // 'iso5'\n 0x69, 0x73, 0x6f, 0x36, // 'iso6'\n ]))\n\n // ESDescriptor (0x03) > DecoderConfigDescriptor (0x04) > DecoderSpecificInfo (0x05) > ASC.\n // Use 1-byte BER sizes (all payloads < 128).\n const dsi = new Uint8Array(2 + asc.length)\n dsi[0] = 0x05; dsi[1] = asc.length\n dsi.set(asc, 2)\n // DCD = 13 fixed bytes + DSI: OTI=0x40 (AAC), streamType=0x05<<2|0x01 (audio, upStream=0)\n const dcd = new Uint8Array(2 + 13 + dsi.length)\n dcd[0] = 0x04; dcd[1] = 13 + dsi.length\n dcd[2] = 0x40 // objectTypeIndication: Audio ISO/IEC 14496-3\n dcd[3] = (0x05 << 2) | 1 // streamType=AudioStream(5), upStream=0, reserved=1\n // bufferSizeDB(3) + maxBitrate(4) + avgBitrate(4) all zero is fine for the walker.\n dcd.set(dsi, 15)\n // ESDescriptor: ES_ID=0, flags=0, then DCD\n const esd = new Uint8Array(2 + 3 + dcd.length)\n esd[0] = 0x03; esd[1] = 3 + dcd.length\n // ES_ID(2) + flags(1) all zero\n esd.set(dcd, 5)\n // esds box = full-box (4-byte version+flags) + ES_Descriptor chain\n const esdsPayload = new Uint8Array(4 + esd.length)\n esdsPayload.set(esd, 4)\n const esds = box('esds', esdsPayload)\n\n // mp4a sample entry: 6 reserved + 2 dref_idx + 8 reserved + 2 channels + 2 samplesize +\n // 2 pre_defined + 2 reserved + 4 samplerate(48000<<16) = 28 bytes,\n // then esds child.\n const mp4aFixed = new Uint8Array(28)\n mp4aFixed[7] = 0x01 // data_reference_index = 1\n mp4aFixed[16] = 0x00; mp4aFixed[17] = 0x01 // channelcount = 1\n mp4aFixed[18] = 0x00; mp4aFixed[19] = 0x10 // samplesize = 16\n // samplerate at offset 24-27 (top 16 bits = sampleRate). 48000 = 0xBB80.\n mp4aFixed[24] = 0xBB; mp4aFixed[25] = 0x80\n const mp4a = box('mp4a', concat(mp4aFixed, esds))\n\n // stsd: 4 ver+flags + 4 entry_count(=1) + entries\n const stsdPayload = new Uint8Array(8 + mp4a.length)\n stsdPayload[7] = 0x01 // entry_count = 1\n stsdPayload.set(mp4a, 8)\n const stsd = box('stsd', stsdPayload)\n\n const stbl = box('stbl', stsd)\n const minf = box('minf', stbl)\n const mdia = box('mdia', minf)\n const trak = box('trak', mdia)\n const moov = box('moov', trak)\n\n return concat(ftyp, moov)\n }\n\n test('extracts AAC-LC mono 48k ASC and derives codec', () => {\n // AOT=2 (00010), samplingFrequencyIndex=3 (0011, 48000Hz), channelConfig=1 (0001),\n // GA: frameLengthFlag=0, dependsOnCoreCoder=0, extensionFlag=0 \u2192 0x11 0x88.\n const asc = new Uint8Array([0x11, 0x88])\n const init = buildMinimalAacInit(asc)\n const result = extractAacAscFromInitSegment(init)\n expect(result).toBeDefined()\n expect(result!.codec).toBe('mp4a.40.2')\n expect(Array.from(result!.description)).toEqual([0x11, 0x88])\n })\n\n test('derives AOT 5 (HE-AAC) from ASC[0] >> 3', () => {\n // AOT=5 (00101), rest don't matter for codec derivation.\n const asc = new Uint8Array([0x29, 0x88]) // 00101 001 1000 1000\n const init = buildMinimalAacInit(asc)\n expect(extractAacAscFromInitSegment(init)?.codec).toBe('mp4a.40.5')\n })\n\n test('rejects data without ftyp/moov magic', () => {\n expect(extractAacAscFromInitSegment(new Uint8Array(64))).toBeUndefined()\n })\n\n test('rejects ftyp+moov with no audio (no mp4a sample entry)', () => {\n // ftyp + moov with empty trak chain \u2014 no stsd, let alone mp4a.\n const ftyp = new Uint8Array([\n 0, 0, 0, 24, 0x66, 0x74, 0x79, 0x70,\n 0x69, 0x73, 0x6f, 0x35, 0, 0, 2, 0,\n 0x69, 0x73, 0x6f, 0x35, 0x69, 0x73, 0x6f, 0x36,\n ])\n const moov = new Uint8Array([0, 0, 0, 8, 0x6d, 0x6f, 0x6f, 0x76]) // empty moov\n const cat = new Uint8Array(ftyp.length + moov.length)\n cat.set(ftyp); cat.set(moov, ftyp.length)\n expect(extractAacAscFromInitSegment(cat)).toBeUndefined()\n })\n })\n\n describe('hevc', () => {\n // Minimal HEVC NAL units: header byte0 = (type << 1). VPS=32(0x40), SPS=33(0x42), PPS=34(0x44).\n const vps = new Uint8Array([0x40, 0x01, 0x0c, 0x01, 0xff, 0xff])\n const sps = new Uint8Array([0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xa0, 0x05, 0x02])\n const pps = new Uint8Array([0x44, 0x01, 0xc1, 0x72, 0xb4, 0x62])\n const idr = new Uint8Array([0x26, 0x01, 0xaf, 0x06]) // type 19 (IDR_W_RADL)\n const lp = (...nals: Uint8Array[]) => {\n const parts: number[] = []\n for (const n of nals) { parts.push((n.length >> 24) & 0xff, (n.length >> 16) & 0xff, (n.length >> 8) & 0xff, n.length & 0xff, ...n) }\n return Uint8Array.from(parts)\n }\n\n test('isHevcCodec', () => {\n expect(isHevcCodec('hev1.1.6.L93.B0')).toBe(true)\n expect(isHevcCodec('hvc1.1.6.L93.B0')).toBe(true)\n expect(isHevcCodec('avc1.640033')).toBe(false)\n })\n\n test('removeEmulationPrevention strips 0x03', () => {\n expect(Array.from(removeEmulationPrevention(new Uint8Array([0, 0, 0x03, 1])))).toEqual([0, 0, 1])\n expect(Array.from(removeEmulationPrevention(new Uint8Array([0xaa, 0xbb])))).toEqual([0xaa, 0xbb])\n })\n\n test('splitAvccNalUnits splits length-prefixed NALs', () => {\n const nals = splitAvccNalUnits(lp(vps, sps))\n expect(nals.length).toBe(2)\n expect(nals[0]).toEqual(vps)\n expect(nals[1]).toEqual(sps)\n })\n\n test('isCompleteAvccSample accepts complete length-prefixed NAL samples', () => {\n expect(isCompleteAvccSample(lp(new Uint8Array([0x09]), idr))).toBe(true)\n })\n\n test('isCompleteAvccSample rejects Annex-B start-code samples', () => {\n expect(isCompleteAvccSample(new Uint8Array([0, 0, 0, 1, 0x65, 0xaa]))).toBe(false)\n })\n\n test('isCompleteAvccSample rejects truncated length-prefixed samples', () => {\n expect(isCompleteAvccSample(new Uint8Array([0, 0, 0, 4, 0x65, 0xaa]))).toBe(false)\n })\n\n test('normalizeH264SampleToAvcc leaves complete AVCC samples unchanged', () => {\n const avcc = lp(new Uint8Array([0x09]), idr)\n const normalized = normalizeH264SampleToAvcc(avcc)\n expect(normalized.format).toBe('avcc')\n expect(normalized.data).toBe(avcc)\n })\n\n test('normalizeH264SampleToAvcc converts a single raw H.264 NAL to AVCC', () => {\n const raw = new Uint8Array([0x65, 0x88, 0x84])\n const normalized = normalizeH264SampleToAvcc(raw)\n expect(normalized.format).toBe('raw-nal')\n expect(normalized.data).toEqual(new Uint8Array([0, 0, 0, 3, 0x65, 0x88, 0x84]))\n })\n\n test('splitH264SampleNalUnits exposes Annex-B NALs without AVCC conversion', () => {\n const annexB = new Uint8Array([0, 0, 0, 1, 0x65, 0x88, 0x84])\n const sample = splitH264SampleNalUnits(annexB)\n expect(sample.format).toBe('annexb')\n expect(sample.nals).toHaveLength(1)\n expect(sample.nals[0]).toEqual(new Uint8Array([0x65, 0x88, 0x84]))\n })\n\n test('splitH264SampleNalUnits exposes single raw H.264 NALs without wrapping', () => {\n const raw = new Uint8Array([0x65, 0x88, 0x84])\n const sample = splitH264SampleNalUnits(raw)\n expect(sample.format).toBe('raw-nal')\n expect(sample.nals).toEqual([raw])\n })\n\n test('splitH264SampleNalUnits can expose partial AVCC NAL headers', () => {\n const partial = new Uint8Array([0, 0, 0, 5, 0x65, 0x88])\n const sample = splitH264SampleNalUnits(partial, { allowPartialAvcc: true })\n expect(sample.format).toBe('partial-avcc')\n expect(sample.nals).toHaveLength(1)\n expect(sample.nals[0]).toEqual(new Uint8Array([0x65, 0x88]))\n })\n\n test('extractHevcParameterSets finds VPS/SPS/PPS (length-prefixed)', () => {\n const sets = extractHevcParameterSets(lp(vps, sps, pps, idr))\n expect(sets.vps).toEqual(vps)\n expect(sets.sps).toEqual(sps)\n expect(sets.pps).toEqual(pps)\n })\n\n test('extractHevcParameterSets finds VPS/SPS/PPS (Annex-B)', () => {\n const sc = new Uint8Array([0, 0, 0, 1])\n const annexb = Uint8Array.from([...sc, ...vps, ...sc, ...sps, ...sc, ...pps, ...sc, ...idr])\n const sets = extractHevcParameterSets(annexb)\n expect(sets.vps).toEqual(vps)\n expect(sets.sps).toEqual(sps)\n expect(sets.pps).toEqual(pps)\n })\n\n test('generateHvcCFromParameterSets builds a valid hvcC', () => {\n const hvcc = generateHvcCFromParameterSets({ vps, sps, pps })!\n expect(hvcc).not.toBeNull()\n expect(hvcc[0]).toBe(1) // configurationVersion\n expect(hvcc[1]).toBe(sps[3]) // general profile_tier_level byte 0 copied from SPS[3]\n expect(hvcc[22]).toBe(3) // numOfArrays (VPS+SPS+PPS)\n // first array entry: NAL_unit_type 32 (VPS), numNalus 1\n expect(hvcc[23] & 0x3f).toBe(32)\n expect((hvcc[24] << 8) | hvcc[25]).toBe(1)\n })\n\n test('generateHvcCFromParameterSets returns null without SPS/PPS', () => {\n expect(generateHvcCFromParameterSets({ vps })).toBeNull()\n })\n\n test('extractHevcCodecDescription end-to-end from keyframe', () => {\n const desc = extractHevcCodecDescription(lp(vps, sps, pps, idr))\n expect(desc).not.toBeNull()\n expect(desc![0]).toBe(1)\n })\n\n test('hevcVclOnly strips parameter-set NALs, keeps VCL', () => {\n const stripped = hevcVclOnly(lp(vps, sps, pps, idr))\n const nals = splitAvccNalUnits(stripped)\n expect(nals.length).toBe(1) // only the IDR VCL NAL remains\n expect(nals[0]).toEqual(idr)\n })\n\n test('hevcVclOnly is a no-op for VCL-only length-prefixed input', () => {\n const vclOnly = lp(idr)\n expect(hevcVclOnly(vclOnly)).toBe(vclOnly)\n })\n })\n })\n}\n", "export type MfuReassemblyPolicy =\n | ReliableMoqReassemblyPolicy\n | { transport: 'datagram'; deadlineMs: number }\n\nexport interface ReliableMoqReassemblyPolicy {\n transport: 'reliable-moq'\n startsAtRandomAccessGroup?: true\n}\n\nexport type MmtpTrackType = 'video' | 'audio' | null\n\nexport interface ReliableMoqReassemblyOptions {\n /**\n * The transport starts at a complete independently decodable media group.\n * The parser still requires an observed RAP before decoder startup.\n */\n startsAtRandomAccessGroup?: boolean\n}\n\nfunction validateReliableMoqOptionShape(value: Record<string, unknown>): void {\n const unsupported = Object.keys(value).filter(\n key => key !== 'transport' && key !== 'startsAtRandomAccessGroup',\n )\n if (unsupported.length > 0) {\n if (unsupported.includes('maxRacingGroups')) {\n throw new Error(\n '[MFU reassembly] maxRacingGroups was removed; reliable MoQ completion is transport-owned',\n )\n }\n throw new Error(\n `[MFU reassembly] unsupported reliable MoQ option(s): ${unsupported.join(', ')}`,\n )\n }\n const startsAtRandomAccessGroup = value['startsAtRandomAccessGroup']\n if (\n typeof startsAtRandomAccessGroup !== 'boolean' &&\n startsAtRandomAccessGroup !== undefined\n ) {\n throw new Error('[MFU reassembly] startsAtRandomAccessGroup must be boolean')\n }\n}\n\nexport function reliableMoqMfuReassembly(\n options: ReliableMoqReassemblyOptions = {},\n): ReliableMoqReassemblyPolicy {\n if (\n arguments.length > 1 ||\n typeof options !== 'object' ||\n options === null ||\n Array.isArray(options)\n ) {\n throw new Error(\n '[MFU reassembly] the positional maxRacingGroups API was removed; pass a reliable MoQ options object',\n )\n }\n validateReliableMoqOptionShape(options as Record<string, unknown>)\n return options.startsAtRandomAccessGroup\n ? {\n transport: 'reliable-moq',\n startsAtRandomAccessGroup: true,\n }\n : { transport: 'reliable-moq' }\n}\n\nfunction assertValidDatagramDeadline(deadlineMs: unknown): asserts deadlineMs is number {\n if (typeof deadlineMs !== 'number' || !Number.isFinite(deadlineMs) || deadlineMs <= 0) {\n throw new Error('[MFU reassembly] datagram deadlineMs must be a finite number > 0')\n }\n}\n\nexport function datagramMfuReassembly(deadlineMs: number): MfuReassemblyPolicy {\n assertValidDatagramDeadline(deadlineMs)\n return { transport: 'datagram', deadlineMs }\n}\n\n/** Validate the complete runtime shape even when a caller bypasses the policy factories. */\nexport function assertValidMfuReassemblyPolicy(policy: MfuReassemblyPolicy): void {\n if (typeof policy !== 'object' || policy === null || Array.isArray(policy)) {\n throw new Error('[MFU reassembly] policy must be an object')\n }\n\n const value = policy as unknown as Record<string, unknown>\n if (value['transport'] === 'reliable-moq') {\n validateReliableMoqOptionShape(value)\n if (value['startsAtRandomAccessGroup'] === false) {\n throw new Error(\n '[MFU reassembly] startsAtRandomAccessGroup must be true when present in a policy',\n )\n }\n return\n }\n if (value['transport'] === 'datagram') {\n const unsupported = Object.keys(value).filter(\n key => key !== 'transport' && key !== 'deadlineMs',\n )\n if (unsupported.length > 0) {\n throw new Error(\n `[MFU reassembly] unsupported datagram option(s): ${unsupported.join(', ')}`,\n )\n }\n assertValidDatagramDeadline(value['deadlineMs'])\n return\n }\n throw new Error(\n `[MFU reassembly] unsupported transport: ${String(value['transport'])}`,\n )\n}\n\nexport function mfuReassemblyTimeoutMs(policy: MfuReassemblyPolicy): number | null {\n assertValidMfuReassemblyPolicy(policy)\n return policy.transport === 'reliable-moq' ? null : policy.deadlineMs\n}\n\n/** Resolve the parser reorder window without inferring reliable-stream completion. */\nexport function mmtpFrameReorderWindowFrames(\n policy: MfuReassemblyPolicy,\n configuredWindow = 0,\n): number {\n assertValidMfuReassemblyPolicy(policy)\n if (!Number.isFinite(configuredWindow) || configuredWindow < 0) {\n throw new Error('[MFU reassembly] configuredWindow must be a finite number >= 0')\n }\n\n const requested = Math.ceil(configuredWindow)\n if (policy.transport === 'reliable-moq') {\n if (requested > 0) {\n throw new Error(\n '[MFU reassembly] reliable MoQ paths do not accept a frame reorder window in the parser',\n )\n }\n return 0\n }\n return requested\n}\n", "/**\n * Strict ISO-BMFF timing extraction for the timed-MFU browser path.\n *\n * This intentionally implements only the current single-track MMT profile:\n * one media track in FT=0, and one matching traf/trun in each FT=1. It does\n * not infer timing from packet arrival, MMTP send timestamps, or cadence.\n */\n\nconst U64_MAX = 0xffff_ffff_ffff_ffffn\nconst I64_MIN = -0x8000_0000_0000_0000n\nconst I64_MAX = 0x7fff_ffff_ffff_ffffn\nconst MICROSECONDS_PER_SECOND = 1_000_000n\n\nconst TFHD_BASE_DATA_OFFSET_PRESENT = 0x000001\nconst TFHD_SAMPLE_DESCRIPTION_INDEX_PRESENT = 0x000002\nconst TFHD_DEFAULT_SAMPLE_DURATION_PRESENT = 0x000008\nconst TFHD_DEFAULT_SAMPLE_SIZE_PRESENT = 0x000010\nconst TFHD_DEFAULT_SAMPLE_FLAGS_PRESENT = 0x000020\nconst TFHD_DURATION_IS_EMPTY = 0x010000\nconst TFHD_DEFAULT_BASE_IS_MOOF = 0x020000\nconst TFHD_KNOWN_FLAGS =\n TFHD_BASE_DATA_OFFSET_PRESENT |\n TFHD_SAMPLE_DESCRIPTION_INDEX_PRESENT |\n TFHD_DEFAULT_SAMPLE_DURATION_PRESENT |\n TFHD_DEFAULT_SAMPLE_SIZE_PRESENT |\n TFHD_DEFAULT_SAMPLE_FLAGS_PRESENT |\n TFHD_DURATION_IS_EMPTY |\n TFHD_DEFAULT_BASE_IS_MOOF\n\nconst TRUN_DATA_OFFSET_PRESENT = 0x000001\nconst TRUN_FIRST_SAMPLE_FLAGS_PRESENT = 0x000004\nconst TRUN_SAMPLE_DURATION_PRESENT = 0x000100\nconst TRUN_SAMPLE_SIZE_PRESENT = 0x000200\nconst TRUN_SAMPLE_FLAGS_PRESENT = 0x000400\nconst TRUN_SAMPLE_CTS_OFFSET_PRESENT = 0x000800\nconst TRUN_KNOWN_FLAGS =\n TRUN_DATA_OFFSET_PRESENT |\n TRUN_FIRST_SAMPLE_FLAGS_PRESENT |\n TRUN_SAMPLE_DURATION_PRESENT |\n TRUN_SAMPLE_SIZE_PRESENT |\n TRUN_SAMPLE_FLAGS_PRESENT |\n TRUN_SAMPLE_CTS_OFFSET_PRESENT\n\nexport interface IsoBmffTrackTiming {\n trackId: number\n timescale: number\n defaultSampleDuration?: number\n defaultSampleSize?: number\n}\n\nexport interface IsoBmffSampleTiming {\n /** Exact decode time in mdhd timescale units. */\n decodeTime: bigint\n /** Exact presentation time in mdhd timescale units, including signed CTS. */\n presentationTime: bigint\n /** Exact authored duration in mdhd timescale units. */\n duration: number\n timescale: number\n /** Exact elementary-stream sample size declared by trun/tfhd/trex. */\n size: number\n /** Byte position of the sample relative to the beginning of the moof. */\n bytePosition: bigint\n}\n\nexport interface IsoBmffMovieFragmentTiming {\n movieFragmentSequenceNumber: number\n samples: readonly IsoBmffSampleTiming[]\n}\n\ninterface IsoBox {\n type: string\n start: number\n bodyStart: number\n end: number\n}\n\ninterface FullBox {\n version: number\n flags: number\n bodyStart: number\n}\n\ninterface ParsedTrack {\n trackId: number\n handlerType: string\n timescale: number\n hasEdits: boolean\n}\n\ninterface ParsedTfhd {\n trackId: number\n defaultSampleDuration?: number\n defaultSampleSize?: number\n}\n\ninterface MdatLayout {\n dataStart: bigint\n declaredEnd: bigint\n}\n\nfunction view(data: Uint8Array): DataView {\n return new DataView(data.buffer, data.byteOffset, data.byteLength)\n}\n\nfunction boxType(data: Uint8Array, offset: number): string {\n return String.fromCharCode(\n data[offset]!,\n data[offset + 1]!,\n data[offset + 2]!,\n data[offset + 3]!,\n )\n}\n\nfunction readU64(data: Uint8Array, offset: number): bigint | null {\n if (offset < 0 || offset + 8 > data.length) return null\n const dataView = view(data)\n return (BigInt(dataView.getUint32(offset, false)) << 32n) |\n BigInt(dataView.getUint32(offset + 4, false))\n}\n\nfunction parseBox(data: Uint8Array, start: number, limit: number): IsoBox | null {\n if (start < 0 || limit > data.length || start + 8 > limit) return null\n const dataView = view(data)\n const shortSize = dataView.getUint32(start, false)\n let headerSize = 8\n let size: number\n if (shortSize === 0) {\n size = limit - start\n } else if (shortSize === 1) {\n if (start + 16 > limit) return null\n const extendedSize = readU64(data, start + 8)\n if (extendedSize === null || extendedSize > BigInt(Number.MAX_SAFE_INTEGER)) return null\n headerSize = 16\n size = Number(extendedSize)\n } else {\n size = shortSize\n }\n if (size < headerSize || start + size > limit) return null\n return {\n type: boxType(data, start + 4),\n start,\n bodyStart: start + headerSize,\n end: start + size,\n }\n}\n\nfunction parseBoxes(data: Uint8Array, start: number, end: number): IsoBox[] | null {\n if (start < 0 || end < start || end > data.length) return null\n const boxes: IsoBox[] = []\n let offset = start\n while (offset < end) {\n const box = parseBox(data, offset, end)\n if (!box || box.end <= offset) return null\n boxes.push(box)\n offset = box.end\n }\n return offset === end ? boxes : null\n}\n\nfunction children(data: Uint8Array, parent: IsoBox): IsoBox[] | null {\n return parseBoxes(data, parent.bodyStart, parent.end)\n}\n\nfunction exactlyOne(boxes: readonly IsoBox[], type: string): IsoBox | null {\n const matches = boxes.filter(box => box.type === type)\n return matches.length === 1 ? matches[0]! : null\n}\n\nfunction parseFullBox(data: Uint8Array, box: IsoBox): FullBox | null {\n if (box.bodyStart + 4 > box.end) return null\n const versionAndFlags = view(data).getUint32(box.bodyStart, false)\n return {\n version: versionAndFlags >>> 24,\n flags: versionAndFlags & 0x00ff_ffff,\n bodyStart: box.bodyStart + 4,\n }\n}\n\nfunction parseTkhdTrackId(data: Uint8Array, box: IsoBox): number | null {\n const full = parseFullBox(data, box)\n if (!full || full.flags & ~0x00000f) return null\n const bodyLength = box.end - full.bodyStart\n const trackIdOffset = full.version === 0\n ? full.bodyStart + 8\n : full.version === 1\n ? full.bodyStart + 16\n : -1\n const expectedBodyLength = full.version === 0 ? 80 : full.version === 1 ? 92 : -1\n if (trackIdOffset < 0 || bodyLength !== expectedBodyLength) return null\n return view(data).getUint32(trackIdOffset, false)\n}\n\nfunction parseMdhdTimescale(data: Uint8Array, box: IsoBox): number | null {\n const full = parseFullBox(data, box)\n if (!full || full.flags !== 0) return null\n const bodyLength = box.end - full.bodyStart\n const timescaleOffset = full.version === 0\n ? full.bodyStart + 8\n : full.version === 1\n ? full.bodyStart + 16\n : -1\n const expectedBodyLength = full.version === 0 ? 20 : full.version === 1 ? 32 : -1\n if (timescaleOffset < 0 || bodyLength !== expectedBodyLength) return null\n return view(data).getUint32(timescaleOffset, false)\n}\n\nfunction parseHandlerType(data: Uint8Array, box: IsoBox): string | null {\n const full = parseFullBox(data, box)\n if (!full || full.version !== 0 || full.flags !== 0 || full.bodyStart + 20 > box.end) {\n return null\n }\n return boxType(data, full.bodyStart + 4)\n}\n\nfunction editListHasEntries(data: Uint8Array, box: IsoBox): boolean | null {\n const full = parseFullBox(data, box)\n if (!full || full.flags !== 0 || (full.version !== 0 && full.version !== 1)) return null\n if (full.bodyStart + 4 > box.end) return null\n const entryCount = view(data).getUint32(full.bodyStart, false)\n const entrySize = full.version === 0 ? 12 : 20\n const expectedEnd = full.bodyStart + 4 + entryCount * entrySize\n if (!Number.isSafeInteger(expectedEnd) || expectedEnd !== box.end) return null\n return entryCount !== 0\n}\n\nfunction parseTrack(data: Uint8Array, trak: IsoBox): ParsedTrack | null {\n const trakChildren = children(data, trak)\n if (!trakChildren) return null\n const tkhd = exactlyOne(trakChildren, 'tkhd')\n const mdia = exactlyOne(trakChildren, 'mdia')\n if (!tkhd || !mdia) return null\n const trackId = parseTkhdTrackId(data, tkhd)\n if (trackId === null || trackId === 0) return null\n\n const mdiaChildren = children(data, mdia)\n if (!mdiaChildren) return null\n const mdhd = exactlyOne(mdiaChildren, 'mdhd')\n const hdlr = exactlyOne(mdiaChildren, 'hdlr')\n if (!mdhd || !hdlr) return null\n const timescale = parseMdhdTimescale(data, mdhd)\n const handlerType = parseHandlerType(data, hdlr)\n if (timescale === null || timescale === 0 || handlerType === null) return null\n\n const edtsBoxes = trakChildren.filter(box => box.type === 'edts')\n if (edtsBoxes.length > 1) return null\n let hasEdits = false\n if (edtsBoxes.length === 1) {\n const edtsChildren = children(data, edtsBoxes[0]!)\n if (!edtsChildren) return null\n const editLists = edtsChildren.filter(box => box.type === 'elst')\n if (editLists.length > 1) return null\n if (editLists.length === 1) {\n const result = editListHasEntries(data, editLists[0]!)\n if (result === null) return null\n hasEdits = result\n }\n }\n\n return { trackId, handlerType, timescale, hasEdits }\n}\n\nfunction parseTrex(data: Uint8Array, box: IsoBox): IsoBmffTrackTiming | null {\n const full = parseFullBox(data, box)\n if (!full || full.version !== 0 || full.flags !== 0 || box.end - full.bodyStart !== 20) {\n return null\n }\n const dataView = view(data)\n const trackId = dataView.getUint32(full.bodyStart, false)\n const defaultSampleDuration = dataView.getUint32(full.bodyStart + 8, false)\n const defaultSampleSize = dataView.getUint32(full.bodyStart + 12, false)\n return {\n trackId,\n timescale: 0,\n ...(defaultSampleDuration === 0 ? {} : { defaultSampleDuration }),\n ...(defaultSampleSize === 0 ? {} : { defaultSampleSize }),\n }\n}\n\nexport function parseIsoBmffInitializationTiming(\n data: Uint8Array,\n): IsoBmffTrackTiming | null {\n const topLevel = parseBoxes(data, 0, data.length)\n if (!topLevel) return null\n const ftyp = exactlyOne(topLevel, 'ftyp')\n const moov = exactlyOne(topLevel, 'moov')\n if (!ftyp || !moov || ftyp.start > moov.start) return null\n if (topLevel.some(box => box.type === 'moof' || box.type === 'mdat')) return null\n\n const moovChildren = children(data, moov)\n if (!moovChildren) return null\n const parsedTracks: ParsedTrack[] = []\n for (const trak of moovChildren.filter(box => box.type === 'trak')) {\n const parsed = parseTrack(data, trak)\n if (!parsed) return null\n parsedTracks.push(parsed)\n }\n const mediaTracks = parsedTracks.filter(\n track => track.handlerType === 'vide' || track.handlerType === 'soun',\n )\n if (mediaTracks.length !== 1) return null\n const mediaTrack = mediaTracks[0]!\n if (mediaTrack.hasEdits) return null\n\n const mvex = exactlyOne(moovChildren, 'mvex')\n if (!mvex) return null\n const mvexChildren = children(data, mvex)\n if (!mvexChildren) return null\n const trexEntries: IsoBmffTrackTiming[] = []\n for (const trexBox of mvexChildren.filter(box => box.type === 'trex')) {\n const trex = parseTrex(data, trexBox)\n if (!trex) return null\n trexEntries.push(trex)\n }\n const matchingTrex = trexEntries.filter(trex => trex.trackId === mediaTrack.trackId)\n if (matchingTrex.length !== 1) return null\n const trex = matchingTrex[0]!\n return {\n trackId: mediaTrack.trackId,\n timescale: mediaTrack.timescale,\n ...(trex.defaultSampleDuration === undefined\n ? {}\n : { defaultSampleDuration: trex.defaultSampleDuration }),\n ...(trex.defaultSampleSize === undefined\n ? {}\n : { defaultSampleSize: trex.defaultSampleSize }),\n }\n}\n\nfunction parseMfhdSequence(data: Uint8Array, box: IsoBox): number | null {\n const full = parseFullBox(data, box)\n if (!full || full.version !== 0 || full.flags !== 0 || box.end - full.bodyStart !== 4) {\n return null\n }\n return view(data).getUint32(full.bodyStart, false)\n}\n\nfunction parseTfhd(data: Uint8Array, box: IsoBox): ParsedTfhd | null {\n const full = parseFullBox(data, box)\n if (!full || full.version !== 0 || (full.flags & ~TFHD_KNOWN_FLAGS) !== 0) return null\n if ((full.flags & TFHD_BASE_DATA_OFFSET_PRESENT) !== 0 ||\n (full.flags & TFHD_DEFAULT_BASE_IS_MOOF) === 0 ||\n (full.flags & TFHD_DURATION_IS_EMPTY) !== 0) {\n return null\n }\n const dataView = view(data)\n let offset = full.bodyStart\n if (offset + 4 > box.end) return null\n const trackId = dataView.getUint32(offset, false)\n offset += 4\n if ((full.flags & TFHD_SAMPLE_DESCRIPTION_INDEX_PRESENT) !== 0) {\n if (offset + 4 > box.end) return null\n offset += 4\n }\n let defaultSampleDuration: number | undefined\n if ((full.flags & TFHD_DEFAULT_SAMPLE_DURATION_PRESENT) !== 0) {\n if (offset + 4 > box.end) return null\n defaultSampleDuration = dataView.getUint32(offset, false)\n offset += 4\n }\n let defaultSampleSize: number | undefined\n if ((full.flags & TFHD_DEFAULT_SAMPLE_SIZE_PRESENT) !== 0) {\n if (offset + 4 > box.end) return null\n defaultSampleSize = dataView.getUint32(offset, false)\n offset += 4\n }\n if ((full.flags & TFHD_DEFAULT_SAMPLE_FLAGS_PRESENT) !== 0) {\n if (offset + 4 > box.end) return null\n offset += 4\n }\n if (offset !== box.end) return null\n return {\n trackId,\n ...(defaultSampleDuration === undefined ? {} : { defaultSampleDuration }),\n ...(defaultSampleSize === undefined ? {} : { defaultSampleSize }),\n }\n}\n\nfunction parseTfdt(data: Uint8Array, box: IsoBox): bigint | null {\n const full = parseFullBox(data, box)\n if (!full || full.flags !== 0) return null\n if (full.version === 0 && box.end - full.bodyStart === 4) {\n return BigInt(view(data).getUint32(full.bodyStart, false))\n }\n if (full.version === 1 && box.end - full.bodyStart === 8) {\n return readU64(data, full.bodyStart)\n }\n return null\n}\n\nfunction parseMdatLayout(data: Uint8Array, offset: number): MdatLayout | null {\n if (offset < 0 || offset + 8 > data.length || boxType(data, offset + 4) !== 'mdat') return null\n const dataView = view(data)\n const shortSize = dataView.getUint32(offset, false)\n let headerSize = 8\n let declaredSize: bigint\n if (shortSize === 0) {\n return null\n } else if (shortSize === 1) {\n const extended = readU64(data, offset + 8)\n if (extended === null) return null\n headerSize = 16\n declaredSize = extended\n } else {\n declaredSize = BigInt(shortSize)\n }\n if (declaredSize < BigInt(headerSize) || declaredSize < BigInt(data.length - offset)) {\n return null\n }\n const declaredEnd = BigInt(offset) + declaredSize\n if (declaredEnd > U64_MAX) return null\n return { dataStart: BigInt(offset + headerSize), declaredEnd }\n}\n\nfunction resolvedDefault(\n entryValue: number | undefined,\n tfhdValue: number | undefined,\n trexValue: number | undefined,\n): number | null {\n const value = entryValue ?? tfhdValue ?? trexValue\n return value === undefined || value === 0 ? null : value\n}\n\nfunction parseTrunSamples(\n data: Uint8Array,\n box: IsoBox,\n moofStart: number,\n baseDecodeTime: bigint,\n tfhd: ParsedTfhd,\n track: IsoBmffTrackTiming,\n mdat: MdatLayout,\n maxSamples: number,\n): IsoBmffSampleTiming[] | null {\n const full = parseFullBox(data, box)\n if (!full || (full.version !== 0 && full.version !== 1) ||\n (full.flags & ~TRUN_KNOWN_FLAGS) !== 0 ||\n (full.flags & TRUN_DATA_OFFSET_PRESENT) === 0 ||\n ((full.flags & TRUN_FIRST_SAMPLE_FLAGS_PRESENT) !== 0 &&\n (full.flags & TRUN_SAMPLE_FLAGS_PRESENT) !== 0)) {\n return null\n }\n const dataView = view(data)\n let offset = full.bodyStart\n if (offset + 8 > box.end) return null\n const sampleCount = dataView.getUint32(offset, false)\n offset += 4\n if (sampleCount === 0 || sampleCount > maxSamples) return null\n const relativeDataOffset = dataView.getInt32(offset, false)\n offset += 4\n if (relativeDataOffset < 0) return null\n const dataOffset = BigInt(relativeDataOffset)\n const absoluteDataOffset = BigInt(moofStart) + dataOffset\n if (absoluteDataOffset > BigInt(data.length) || absoluteDataOffset < mdat.dataStart) return null\n if ((full.flags & TRUN_FIRST_SAMPLE_FLAGS_PRESENT) !== 0) {\n if (offset + 4 > box.end) return null\n offset += 4\n }\n\n let decodeTime = baseDecodeTime\n let bytePosition = dataOffset\n const samples: IsoBmffSampleTiming[] = []\n for (let index = 0; index < sampleCount; index++) {\n let entryDuration: number | undefined\n if ((full.flags & TRUN_SAMPLE_DURATION_PRESENT) !== 0) {\n if (offset + 4 > box.end) return null\n entryDuration = dataView.getUint32(offset, false)\n offset += 4\n }\n let entrySize: number | undefined\n if ((full.flags & TRUN_SAMPLE_SIZE_PRESENT) !== 0) {\n if (offset + 4 > box.end) return null\n entrySize = dataView.getUint32(offset, false)\n offset += 4\n }\n if ((full.flags & TRUN_SAMPLE_FLAGS_PRESENT) !== 0) {\n if (offset + 4 > box.end) return null\n offset += 4\n }\n let compositionOffset = 0\n if ((full.flags & TRUN_SAMPLE_CTS_OFFSET_PRESENT) !== 0) {\n if (offset + 4 > box.end) return null\n compositionOffset = full.version === 1\n ? dataView.getInt32(offset, false)\n : dataView.getUint32(offset, false)\n offset += 4\n }\n if (offset > box.end) return null\n\n const duration = resolvedDefault(\n entryDuration,\n tfhd.defaultSampleDuration,\n track.defaultSampleDuration,\n )\n const size = resolvedDefault(entrySize, tfhd.defaultSampleSize, track.defaultSampleSize)\n if (duration === null || size === null) return null\n const sampleEnd = bytePosition + BigInt(size)\n const absoluteSampleEnd = BigInt(moofStart) + sampleEnd\n if (absoluteSampleEnd > mdat.declaredEnd || absoluteSampleEnd > U64_MAX) return null\n const presentationTime = decodeTime + BigInt(compositionOffset)\n if (presentationTime < I64_MIN || presentationTime > I64_MAX) return null\n samples.push({\n decodeTime,\n presentationTime,\n duration,\n timescale: track.timescale,\n size,\n bytePosition,\n })\n decodeTime += BigInt(duration)\n if (decodeTime > U64_MAX) return null\n bytePosition = sampleEnd\n }\n return offset === box.end ? samples : null\n}\n\nexport function parseIsoBmffMovieFragmentTiming(\n data: Uint8Array,\n track: IsoBmffTrackTiming,\n maxSamples: number,\n): IsoBmffMovieFragmentTiming | null {\n if (!Number.isInteger(maxSamples) || maxSamples <= 0) return null\n const first = parseBox(data, 0, data.length)\n if (!first) return null\n const moof = first.type === 'styp'\n ? parseBox(data, first.end, data.length)\n : first\n if (!moof || moof.type !== 'moof' || moof.end >= data.length) return null\n const moofChildren = children(data, moof)\n if (!moofChildren) return null\n const mfhd = exactlyOne(moofChildren, 'mfhd')\n const traf = exactlyOne(moofChildren, 'traf')\n if (!mfhd || !traf) return null\n const movieFragmentSequenceNumber = parseMfhdSequence(data, mfhd)\n if (movieFragmentSequenceNumber === null || movieFragmentSequenceNumber === 0) return null\n\n const trafChildren = children(data, traf)\n if (!trafChildren) return null\n const tfhdBox = exactlyOne(trafChildren, 'tfhd')\n const tfdtBox = exactlyOne(trafChildren, 'tfdt')\n const trunBox = exactlyOne(trafChildren, 'trun')\n if (!tfhdBox || !tfdtBox || !trunBox) return null\n const tfhd = parseTfhd(data, tfhdBox)\n const baseDecodeTime = parseTfdt(data, tfdtBox)\n if (!tfhd || tfhd.trackId !== track.trackId || baseDecodeTime === null) return null\n const mdat = parseMdatLayout(data, moof.end)\n if (!mdat) return null\n const samples = parseTrunSamples(\n data,\n trunBox,\n moof.start,\n baseDecodeTime,\n tfhd,\n track,\n mdat,\n maxSamples,\n )\n if (!samples) return null\n return { movieFragmentSequenceNumber, samples }\n}\n\nfunction sameTrack(a: IsoBmffTrackTiming, b: IsoBmffTrackTiming): boolean {\n return a.trackId === b.trackId &&\n a.timescale === b.timescale &&\n a.defaultSampleDuration === b.defaultSampleDuration &&\n a.defaultSampleSize === b.defaultSampleSize\n}\n\nfunction sameSample(a: IsoBmffSampleTiming, b: IsoBmffSampleTiming): boolean {\n return a.decodeTime === b.decodeTime &&\n a.presentationTime === b.presentationTime &&\n a.duration === b.duration &&\n a.timescale === b.timescale &&\n a.size === b.size &&\n a.bytePosition === b.bytePosition\n}\n\ntype PendingMovieFragment = Array<IsoBmffSampleTiming | null>\n\n/** Bounded per-track FT=0/FT=1 timing state. */\nexport class IsoBmffTimingResolver {\n #track: IsoBmffTrackTiming | null = null\n #fragments = new Map<string, PendingMovieFragment>()\n #pendingSamples = 0\n\n constructor(readonly maxPendingSamples: number) {\n if (!Number.isInteger(maxPendingSamples) || maxPendingSamples <= 0) {\n throw new Error('[IsoBmffTimingResolver] maxPendingSamples must be a positive integer')\n }\n }\n\n get pendingSampleCount(): number {\n return this.#pendingSamples\n }\n\n addInitialization(data: Uint8Array): boolean {\n const timing = parseIsoBmffInitializationTiming(data)\n if (!timing) return false\n if (this.#track) return sameTrack(this.#track, timing)\n this.#track = timing\n return true\n }\n\n addMovieFragment(\n mpuSequenceNumber: number,\n data: Uint8Array,\n additionalSampleLimit = this.maxPendingSamples,\n ): boolean {\n if (!Number.isInteger(additionalSampleLimit) || additionalSampleLimit < 0) return false\n if (!this.#track || !isU32(mpuSequenceNumber)) return false\n const parsed = parseIsoBmffMovieFragmentTiming(\n data,\n this.#track,\n this.maxPendingSamples,\n )\n if (!parsed) return false\n const key = fragmentKey(mpuSequenceNumber, parsed.movieFragmentSequenceNumber)\n const existing = this.#fragments.get(key)\n if (existing) {\n return existing.length === parsed.samples.length && existing.every(\n (sample, index) => sample !== null && sameSample(sample, parsed.samples[index]!),\n )\n }\n if (parsed.samples.length > additionalSampleLimit) return false\n if (this.#pendingSamples + parsed.samples.length > this.maxPendingSamples) return false\n this.#fragments.set(key, [...parsed.samples])\n this.#pendingSamples += parsed.samples.length\n return true\n }\n\n sampleTiming(\n mpuSequenceNumber: number,\n movieFragmentSequenceNumber: number,\n sampleNumber: number,\n ): IsoBmffSampleTiming | null {\n if (!isU32(mpuSequenceNumber) || !isU32(movieFragmentSequenceNumber) ||\n movieFragmentSequenceNumber === 0 || !isU32(sampleNumber) || sampleNumber === 0) {\n return null\n }\n const samples = this.#fragments.get(\n fragmentKey(mpuSequenceNumber, movieFragmentSequenceNumber),\n )\n return samples?.[sampleNumber - 1] ?? null\n }\n\n consumeSample(\n mpuSequenceNumber: number,\n movieFragmentSequenceNumber: number,\n sampleNumber: number,\n expected: IsoBmffSampleTiming,\n ): boolean {\n const key = fragmentKey(mpuSequenceNumber, movieFragmentSequenceNumber)\n const samples = this.#fragments.get(key)\n const index = sampleNumber - 1\n const sample = samples?.[index]\n if (!samples || !sample || !sameSample(sample, expected)) return false\n samples[index] = null\n this.#pendingSamples--\n if (samples.every(value => value === null)) this.#fragments.delete(key)\n return true\n }\n\n reset(): void {\n this.#track = null\n this.#fragments.clear()\n this.#pendingSamples = 0\n }\n}\n\nfunction fragmentKey(mpuSequenceNumber: number, movieFragmentSequenceNumber: number): string {\n return `${mpuSequenceNumber}:${movieFragmentSequenceNumber}`\n}\n\nfunction isU32(value: number): boolean {\n return Number.isInteger(value) && value >= 0 && value <= 0xffff_ffff\n}\n\n/** Convert exact media ticks to microseconds without first narrowing the ticks. */\nexport function mediaTicksToMicroseconds(ticks: bigint, timescale: number): number | null {\n if (!Number.isInteger(timescale) || timescale <= 0) return null\n const numerator = ticks * MICROSECONDS_PER_SECOND\n const scale = BigInt(timescale)\n const whole = numerator / scale\n const remainder = numerator % scale\n if (whole < BigInt(Number.MIN_SAFE_INTEGER) || whole > BigInt(Number.MAX_SAFE_INTEGER)) {\n return null\n }\n const result = Number(whole) + Number(remainder) / timescale\n return Number.isFinite(result) ? result : null\n}\n", "import {\n parseMMTPHeader,\n extractMFUPayload,\n extractFecPayloadId,\n hasSourceFecPayloadId,\n extractAltaTrailer,\n PACKET_TYPE_MPU,\n PACKET_TYPE_REPAIR,\n} from '@blockcast/mmt-base'\nimport {\n MFUReassembler,\n MfuReassemblyError,\n type MfuReassemblerBackend,\n type MmtpSourcePath,\n type MmtpDeliveryProvenance,\n type ReassembledMFU,\n} from './mfu-reassembler.js'\nimport {\n SampleCombiner,\n SampleCombineError,\n type CombinedSample,\n type SampleCombinerOptions,\n type SampleCombinerStats,\n} from './sample-combiner.js'\nimport { classifyH264Keyframe, mmtpTimestampToMicros } from './codec-utils.js'\nimport {\n mmtpFrameReorderWindowFrames,\n mfuReassemblyTimeoutMs,\n type MfuReassemblyPolicy,\n} from './mfu-reassembly-policy.js'\nimport {\n IsoBmffTimingResolver,\n mediaTicksToMicroseconds,\n type IsoBmffSampleTiming,\n} from './iso-bmff-timing.js'\nimport type { AuthoredTiming } from './authored-timing.js'\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface TrackInfo {\n type: 'video' | 'audio'\n codec: string\n /** Catalog/in-band frame cadence available to downstream media stages. */\n framerate?: number\n /** Catalog MMTP group duration available to downstream media stages. */\n groupDurationMs?: number\n}\n\nexport interface MmtpParserConfig {\n tracks?: Map<number, TrackInfo>\n reorderWindow?: number\n /** MFU reassembly timeout (ms). Derive from FEC interleaveDepthMs or frame duration.\n * Pass null for live clock-free operation; memory remains bounded by maxBuffered.\n * Defaults to 1000ms if not provided. */\n mfuTimeoutMs?: number | null\n /** Explicit transport policy. Reliable MoQ is clock-free; datagrams require\n * a catalog/in-band-derived deadline. Mutually exclusive with mfuTimeoutMs. */\n reassemblyPolicy?: MfuReassemblyPolicy\n /** Max concurrent active MFUs. A new first fragment is rejected at the bound. */\n maxBufferedMfus?: number\n /**\n * Max subsample data units held for one partitioned sample (moqcast #37).\n * A sample needs `ceil(sampleSize / (256 * maxPayload))` data units; at the\n * ~1300-byte payloads this producer emits, one data unit spans ~327 KB, so\n * the default admits a ~5 MB sample \u2014 beyond any 8K intra frame \u2014 while\n * still bounding the per-insert overlap scan. Raise it only alongside a\n * larger authored frame size, never to paper over a lost data unit.\n */\n maxSubsampleSegments?: number\n /** Alternate backend. The TypeScript and Rust/WASM implementations enforce\n * the same authored active-DU contract. */\n reassembler?: MfuReassemblerBackend\n /** Default track info for auto-discovered packetIds.\n * When the parser receives an MMTP packet with an unregistered packetId,\n * it creates a new track entry using this info. Required for correct\n * keyframe detection with HEVC/AV1/VP9 (without it, defaults to H.264). */\n defaultTrack?: TrackInfo\n}\n\n/** Structured result from parseHeader(). Used by MmtpRouter for two-phase parsing:\n * 1. parseHeader() \u2192 get packetId + fecPayloadId for FEC feeding\n * 2. feed() \u2192 MFU extraction, reassembly, keyframe detection, emit */\nexport interface PacketInfo {\n packetId: number\n packetType: number\n timestamp: bigint\n /** MMTP timestamp converted to monotonic microseconds for pacing/sync users. */\n timestampUs: number\n sequenceNumber: number\n rapFlag: boolean\n fecType: number\n /** FEC source symbol ID (from 4-byte FEC Payload ID at packet end). Null if no FEC. */\n fecPayloadId: { ssId: number } | null\n /** True if this is a repair packet (packetType=0x03). */\n isRepair: boolean\n}\n\nexport interface FrameMeta {\n /** Authored ISO-BMFF presentation time converted to microseconds. */\n timestamp: number\n /** Authored ISO-BMFF decode time converted to microseconds. */\n decodeTimestamp?: number\n /** Authored ISO-BMFF sample duration converted to microseconds. */\n duration?: number\n /** Exact authored decode time in mediaTimescale units. */\n decodeTime?: bigint\n /** Exact authored presentation time in mediaTimescale units. */\n presentationTime?: bigint\n /** Exact authored duration in mediaTimescale units. */\n durationTicks?: number\n /** mdhd media timescale for the exact timing fields. */\n mediaTimescale?: number\n /** Exact authored ISO-BMFF timing carried without narrowing to microseconds. */\n authoredTiming?: AuthoredTiming\n keyframe: boolean\n packetId: number\n trackType: 'video' | 'audio' | null\n packetSequenceNumber?: number\n /** Every authoritative MMTP source-packet sequence that formed this frame. */\n packetSequenceNumbers?: number[]\n /** Subset of packetSequenceNumbers reconstructed by FEC. */\n repairedPacketSequenceNumbers?: number[]\n /** Immutable catalog identity supplied by the owning ingress subscription. */\n catalogTrackName?: string\n /** Raw MMTP short-NTP timestamp retained for adapters that own the timeline. */\n mmtpTimestamp?: bigint\n mpuSequenceNumber?: number\n movieFragmentSequenceNumber?: number\n sampleNumber?: number\n fragmentCount?: number\n rapFlag?: boolean\n priority?: number\n recovered?: boolean\n /** Starts a new publisher/source epoch for ordering and timestamp state. */\n sourceDiscontinuity?: boolean\n /** Source of the accepted FI=1/FI=0 frame path. Absent for recovery. */\n source?: MmtpSourcePath\n /**\n * Strict whole-frame delivery provenance. Unlike `source`, which names the\n * head fragment's transport for routing, this is folded over every\n * contributing fragment (and, for FEC-recovered frames, over the transports\n * that supplied the block's symbols). Only 'multicast' is evidence of\n * multicast-exclusive delivery. Absent means no producer on this path\n * recorded provenance \u2014 consumers MUST treat that as unproven, never as\n * multicast.\n */\n deliveryProvenance?: MmtpDeliveryProvenance\n}\n\nexport interface MmtpReorderStats {\n droppedBeforeStartupKeyframe: number\n droppedIncompleteStartupInterval: number\n droppedStale: number\n forcedWindowFlushes: number\n droppedOnLiveDispose: number\n publisherResets: number\n droppedOnPublisherReset: number\n bufferedFrames: number\n}\n\nexport interface MmtpReorderFrameDiagnostics {\n timestampUs: number\n keyframe: boolean\n sequenceNumber: number\n packetSequenceNumber?: number\n movieFragmentSequenceNumber?: number\n sampleNumber?: number\n fragmentCount?: number\n}\n\nexport interface MmtpReorderStreamDiagnostics {\n packetId: number\n bufferedFrames: number\n lastEmitted: MmtpReorderFrameDiagnostics | null\n startupKeyframe: MmtpReorderFrameDiagnostics | null\n head: MmtpReorderFrameDiagnostics[]\n tail: MmtpReorderFrameDiagnostics[]\n keyframes: MmtpReorderFrameDiagnostics[]\n}\n\nexport type MmtpParserRecord =\n | {\n kind: 'repair' | 'non-media'\n packet: PacketInfo\n byteLength: number\n }\n | {\n kind: 'init' | 'fragment'\n packet: PacketInfo\n data: Uint8Array\n mpuSequenceNumber: number\n fragmentationIndicator: number\n fragmentCounter: number\n }\n | {\n kind: 'pending'\n packet: PacketInfo\n mpuSequenceNumber: number\n fragmentationIndicator: number\n fragmentCounter: number\n }\n | {\n kind: 'rejected'\n packet: PacketInfo\n mpuSequenceNumber: number\n fragmentationIndicator: number\n fragmentCounter: number\n error: {\n /**\n * Either a single data unit's own fragment chain was rejected, or\n * combining reassembled data units into a sample was (moqcast #37).\n * Both are fail-closed drops of the same packet, so they share this\n * record; the code says which class it came from.\n */\n code: MfuReassemblyError['code'] | SampleCombineError['code']\n message: string\n }\n }\n | {\n kind: 'frame'\n packet: PacketInfo\n data: Uint8Array\n meta: FrameMeta\n mpuSequenceNumber: number\n fragmentCount: number\n rapFlag: boolean\n priority?: number\n }\n\ntype FrameCallback = (data: Uint8Array, meta: FrameMeta) => void\ntype InitCallback = (data: Uint8Array, packetId: number, catalogTrackName?: string) => void\n\nexport function isMfuKeyframeMetadata(rapFlag: boolean, priority?: number): boolean {\n return rapFlag || (priority ?? 0) > 0x80\n}\n\n/** Per-packet detached ALTA authenticator trailer (08-07 Path 2).\n * - `auth`: the authenticator bytes (length-prefixed at packet end).\n * - `payloadEnd`: byte offset within the source packet where signed\n * payload ends \u2014 consumers reconstruct `payload = packet[0..payloadEnd]`\n * for verify_detached. */\nexport interface ParsedAltaTrailer {\n auth: Uint8Array\n payloadEnd: number\n}\n\n/** Source-symbol exposure for FEC consumers.\n *\n * Fires from {@link MmtpContainerParser.feed} once per FEC-protected source\n * packet \u2014 after parseHeader confirms fec_payload_id is present, before MFU\n * extraction.\n *\n * Arguments:\n * - `packetId` \u2013 MMTP header `packet_id` (track identifier)\n * - `ssId` \u2013 flat Source Symbol ID from the 4-byte fec_payload_id trailer\n * - `rawSymbol` \u2013 packet bytes minus the 4-byte fec_payload_id trailer.\n * NOT zero-padded to FEC symbol size \u2014 consumer pads if needed\n * (FEC symbol size is FEC-config, not parser-config).\n * - `alta` \u2013 detached ALTA authenticator if present, else undefined\n *\n * Designed so consumers (player, Shaka shim, upstream moqtail) can wire\n * source-symbol delivery to whatever FEC pipeline they own, without depending\n * on libmmt's MulticastManager/MmtpRouter/FECManager stack. */\ntype SourceSymbolCallback = (\n packetId: number,\n ssId: number,\n rawSymbol: Uint8Array,\n alta: ParsedAltaTrailer | undefined,\n) => void\n\nexport interface ParseHeaderOptions {\n /** Recovered source symbols already had the trailing Source FEC Payload ID stripped. */\n skipFecPayloadId?: boolean\n /** Mark frames emitted from this packet as FEC-recovered. */\n recovered?: boolean\n /** Exact catalog track bound to this packet by its ingress subscription. */\n catalogTrackName?: string\n /** Source transport for parser-owned frame attribution. */\n source?: MmtpSourcePath\n /**\n * Explicit strict provenance for the fragments this packet produces.\n * The router sets it for FEC-recovered packets, which carry no `source`\n * but whose FEC block's symbol provenance is known.\n */\n deliveryProvenance?: MmtpDeliveryProvenance\n}\n\n// \u2500\u2500 FrameSequencer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface PendingFrame {\n data: Uint8Array\n meta: FrameMeta\n seq: number\n}\n\ninterface SequencerStream {\n buf: PendingFrame[]\n lastEmitted: PendingFrame | null\n}\n\nfunction reorderFrameDiagnostics(frame: PendingFrame): MmtpReorderFrameDiagnostics {\n return {\n timestampUs: frame.meta.timestamp,\n keyframe: frame.meta.keyframe,\n sequenceNumber: frame.seq,\n ...(frame.meta.packetSequenceNumber === undefined\n ? {}\n : { packetSequenceNumber: frame.meta.packetSequenceNumber }),\n ...(frame.meta.movieFragmentSequenceNumber === undefined\n ? {}\n : { movieFragmentSequenceNumber: frame.meta.movieFragmentSequenceNumber }),\n ...(frame.meta.sampleNumber === undefined ? {} : { sampleNumber: frame.meta.sampleNumber }),\n ...(frame.meta.fragmentCount === undefined\n ? {}\n : { fragmentCount: frame.meta.fragmentCount }),\n }\n}\n\ntype SequencerStat = Exclude<keyof MmtpReorderStats, 'bufferedFrames'>\n\nfunction serialSequenceDelta(a: number, b: number): number {\n return (a - b) | 0\n}\n\nfunction compareFrameOrder(\n a: PendingFrame,\n b: PendingFrame,\n): number {\n if (a.meta.decodeTime !== undefined && b.meta.decodeTime !== undefined &&\n a.meta.mediaTimescale === b.meta.mediaTimescale) {\n if (a.meta.decodeTime < b.meta.decodeTime) return -1\n if (a.meta.decodeTime > b.meta.decodeTime) return 1\n } else {\n const decodeDelta = (a.meta.decodeTimestamp ?? a.meta.timestamp) -\n (b.meta.decodeTimestamp ?? b.meta.timestamp)\n if (decodeDelta !== 0) return decodeDelta\n }\n const movieDelta = serialSequenceDelta(\n a.meta.movieFragmentSequenceNumber ?? 0,\n b.meta.movieFragmentSequenceNumber ?? 0,\n )\n if (movieDelta !== 0) return movieDelta\n const sampleDelta = (a.meta.sampleNumber ?? 0) - (b.meta.sampleNumber ?? 0)\n return sampleDelta !== 0 ? sampleDelta : serialSequenceDelta(a.seq, b.seq)\n}\n\nclass FrameSequencer {\n #streams = new Map<number, SequencerStream>()\n #windowSize: number\n #emit: (data: Uint8Array, meta: FrameMeta) => void\n #recordStat: (stat: SequencerStat, count?: number) => void\n\n constructor(\n windowSize: number,\n emit: (data: Uint8Array, meta: FrameMeta) => void,\n recordStat: (stat: SequencerStat, count?: number) => void = () => {},\n ) {\n this.#windowSize = windowSize\n this.#emit = emit\n this.#recordStat = recordStat\n }\n\n push(data: Uint8Array, meta: FrameMeta, seq: number): void {\n if (this.#windowSize <= 0) {\n this.#emit(data, meta)\n return\n }\n const frame: PendingFrame = { data, meta: { ...meta }, seq }\n const stream = this.#streamFor(meta.packetId)\n if (meta.sourceDiscontinuity) {\n this.#recordStat('publisherResets')\n this.#recordStat('droppedOnPublisherReset', stream.buf.length)\n stream.buf = []\n stream.lastEmitted = null\n frame.meta.sourceDiscontinuity = true\n }\n if (this.#isStale(stream, frame)) {\n this.#recordStat('droppedStale')\n return\n }\n if (meta.keyframe && stream.lastEmitted === null) {\n // The first RAP establishes decoder sync. Discard any pre-RAP media and\n // emit it immediately so startup does not pay the reorder-window delay.\n this.#recordStat('droppedBeforeStartupKeyframe', stream.buf.length)\n stream.buf = []\n this.#emitFrame(stream, frame)\n return\n }\n let lo = 0, hi = stream.buf.length\n while (lo < hi) {\n const mid = (lo + hi) >>> 1\n if (compareFrameOrder(stream.buf[mid]!, frame) < 0) lo = mid + 1\n else hi = mid\n }\n stream.buf.splice(lo, 0, frame)\n while (stream.buf.length > this.#windowSize) this.#flushHead(stream)\n }\n\n flush(): void {\n for (const packetId of [...this.#streams.keys()].sort((a, b) => a - b)) {\n const stream = this.#streams.get(packetId)\n while (stream && stream.buf.length > 0) this.#flushHead(stream)\n }\n }\n\n get buffered(): number {\n let total = 0\n for (const stream of this.#streams.values()) total += stream.buf.length\n return total\n }\n\n get diagnostics(): Omit<MmtpReorderStreamDiagnostics, 'packetId'>[] {\n return [...this.#streams.values()].map(stream => ({\n bufferedFrames: stream.buf.length,\n lastEmitted: stream.lastEmitted ? reorderFrameDiagnostics(stream.lastEmitted) : null,\n startupKeyframe: null,\n head: stream.buf.slice(0, 4).map(reorderFrameDiagnostics),\n tail: stream.buf.slice(-4).map(reorderFrameDiagnostics),\n keyframes: stream.buf.filter(frame => frame.meta.keyframe).slice(0, 8)\n .map(reorderFrameDiagnostics),\n }))\n }\n\n discard(): void {\n for (const stream of this.#streams.values()) {\n this.#recordStat('droppedOnLiveDispose', stream.buf.length)\n stream.buf = []\n }\n this.#streams.clear()\n }\n\n #streamFor(packetId: number): SequencerStream {\n let stream = this.#streams.get(packetId)\n if (!stream) {\n stream = { buf: [], lastEmitted: null }\n this.#streams.set(packetId, stream)\n }\n return stream\n }\n\n #flushHead(stream: SequencerStream): boolean {\n const f = stream.buf.shift()\n if (!f) return false\n return this.#emitFrame(stream, f)\n }\n\n #isStale(stream: SequencerStream, frame: PendingFrame): boolean {\n return stream.lastEmitted !== null &&\n compareFrameOrder(frame, stream.lastEmitted) <= 0\n }\n\n #emitFrame(stream: SequencerStream, frame: PendingFrame): boolean {\n if (this.#isStale(stream, frame)) {\n this.#recordStat('droppedStale')\n return false\n }\n stream.lastEmitted = frame\n this.#emit(frame.data, frame.meta)\n return true\n }\n}\n\n// \u2500\u2500 fMP4 box detection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst FMPU_BOX_TYPES = new Set(['ftyp', 'moov', 'moof'])\n\nfunction isFmp4Box(data: Uint8Array): boolean {\n if (data.length < 8) return false\n const type = String.fromCharCode(data[4]!, data[5]!, data[6]!, data[7]!)\n return FMPU_BOX_TYPES.has(type)\n}\n\ninterface TimingStreamState {\n packetId: number\n resolver: IsoBmffTimingResolver\n}\n\n// \u2500\u2500 MmtpContainerParser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class MmtpContainerParser {\n #tracks = new Map<number, TrackInfo>()\n #defaultTrack: TrackInfo | null = null\n #reassembler: MfuReassemblerBackend\n /**\n * Combines subsample data units back into whole samples (moqcast #37), one\n * combiner per parser stream. Per-stream is required, not an optimization:\n * {@link SampleCombiner} identifies a sample by\n * `(catalogTrackName, mpu, movieFragment, sampleNumber)`, so two streams\n * that carry no catalog identity would collide on every sample number and\n * each would see the other's data units as duplicates of its own. The\n * parser already isolates timing and reordering by this same stream key.\n *\n * Inert until a producer partitions \u2014 which it does the moment a frame\n * exceeds one data unit's 256-payload capacity (~327 KB here, routinely\n * exceeded by 4K/8K intra frames).\n */\n #sampleCombiners = new Map<string, SampleCombiner>()\n #sampleCombinerOptions: SampleCombinerOptions\n /** Counters folded in from combiners dropped by a track reset, so the\n * totals below stay monotonic across a publisher change. */\n #retiredSampleCombinerStats: SampleCombinerStats = {\n combinedSamples: 0,\n passthroughSamples: 0,\n timedOutSamples: 0,\n evictedSamples: 0,\n }\n #timingStreams = new Map<string, TimingStreamState>()\n #maxPendingTimingSamples: number\n #pendingTimingSamples = 0\n #sequencers = new Map<string, { packetId: number; sequencer: FrameSequencer }>()\n #reorderWindow = 0\n #reassemblyPolicy: MfuReassemblyPolicy | null = null\n #frameCb: FrameCallback | null = null\n #initCb: InitCallback | null = null\n #sourceSymbolCb: SourceSymbolCallback | null = null\n #trackFrameCbs = new Map<number, FrameCallback>()\n #reorderStats: Omit<MmtpReorderStats, 'bufferedFrames'> = {\n droppedBeforeStartupKeyframe: 0,\n droppedIncompleteStartupInterval: 0,\n droppedStale: 0,\n forcedWindowFlushes: 0,\n droppedOnLiveDispose: 0,\n publisherResets: 0,\n droppedOnPublisherReset: 0,\n }\n /** Streams (keyed by physical parser stream, value is packetId) that have\n * observed their first RAP under a reliable-moq policy. Reliable MoQ\n * resolves to a zero parser reorder window (transport ordering is\n * protocol-owned), so #sequencerFor returns null and its own startup gate\n * never runs; this map preserves an order-independent \"discard delta\n * frames before the first RAP\" gate for that path without reintroducing\n * reordering into the parser. */\n #reliableMoqStartupGate = new Map<string, number>()\n #disposed = false\n\n #streamKey(packetId: number, catalogTrackName?: string): string {\n return JSON.stringify([packetId, catalogTrackName ?? null])\n }\n\n #sampleCombinerFor(streamKey: string): SampleCombiner {\n let combiner = this.#sampleCombiners.get(streamKey)\n if (combiner === undefined) {\n combiner = new SampleCombiner(this.#sampleCombinerOptions)\n this.#sampleCombiners.set(streamKey, combiner)\n }\n return combiner\n }\n\n /** Drop one stream's combiner, folding its counters into the retained\n * totals so a reset cannot make the exposed stats run backwards. */\n #dropSampleCombiner(streamKey: string): void {\n const combiner = this.#sampleCombiners.get(streamKey)\n if (combiner === undefined) return\n const stats = combiner.stats\n this.#retiredSampleCombinerStats.combinedSamples += stats.combinedSamples\n this.#retiredSampleCombinerStats.passthroughSamples += stats.passthroughSamples\n this.#retiredSampleCombinerStats.timedOutSamples += stats.timedOutSamples\n this.#retiredSampleCombinerStats.evictedSamples += stats.evictedSamples\n this.#sampleCombiners.delete(streamKey)\n }\n\n constructor(config?: MmtpParserConfig) {\n if (config?.reassemblyPolicy && config.mfuTimeoutMs !== undefined) {\n throw new Error('[MmtpContainerParser] use reassemblyPolicy or mfuTimeoutMs, not both')\n }\n const reassemblyPolicy = config?.reassemblyPolicy ?? null\n const requestedReorderWindow = config?.reorderWindow ?? 0\n if (!Number.isFinite(requestedReorderWindow) || requestedReorderWindow < 0) {\n throw new Error('[MmtpContainerParser] reorderWindow must be a finite number >= 0')\n }\n const normalizedReorderWindow = Math.ceil(requestedReorderWindow)\n const requestedMfuTimeout = reassemblyPolicy\n ? mfuReassemblyTimeoutMs(reassemblyPolicy)\n : config?.mfuTimeoutMs\n if (reassemblyPolicy) {\n mmtpFrameReorderWindowFrames(reassemblyPolicy, normalizedReorderWindow)\n }\n if (\n requestedMfuTimeout !== undefined &&\n requestedMfuTimeout !== null &&\n requestedMfuTimeout <= 0\n ) {\n throw new Error('[MmtpContainerParser] mfuTimeoutMs must be > 0')\n }\n const maxPendingTimingSamples = config?.maxBufferedMfus ?? 100\n if (!Number.isInteger(maxPendingTimingSamples) || maxPendingTimingSamples <= 0) {\n throw new Error('[MmtpContainerParser] maxBufferedMfus must be a positive integer')\n }\n this.#maxPendingTimingSamples = maxPendingTimingSamples\n\n const maxSubsampleSegments = config?.maxSubsampleSegments ?? 16\n if (!Number.isInteger(maxSubsampleSegments) || maxSubsampleSegments <= 0) {\n throw new Error('[MmtpContainerParser] maxSubsampleSegments must be a positive integer')\n }\n\n // Everything above only reads `config` \u2014 the full policy/window\n // combination is validated before this point, so it is now safe to\n // mutate this instance or an injected, caller-owned reassembler.\n this.#reassemblyPolicy = reassemblyPolicy\n if (config?.reassembler) {\n this.#reassembler = config.reassembler\n // An injected backend owns its existing transport policy unless this\n // parser was given an explicit policy/legacy timeout override.\n if (requestedMfuTimeout !== undefined) {\n this.#reassembler.timeoutMs = requestedMfuTimeout\n }\n } else {\n this.#reassembler = new MFUReassembler({\n timeoutMs: requestedMfuTimeout === undefined ? 1000 : requestedMfuTimeout,\n ...(config?.maxBufferedMfus === undefined ? {} : { maxBuffered: config.maxBufferedMfus }),\n })\n }\n this.#reorderWindow = normalizedReorderWindow\n this.#sampleCombinerOptions = {\n maxBuffered: maxPendingTimingSamples,\n // The parser resolves every timed sample's authored size from FT=1\n // before its data units reach the combiner, so \"no size yet\" always\n // means the size has not arrived -- never that the host declines to\n // supply one. Waiting is therefore correct: treating an offset-zero\n // data unit as a whole sample in that window would truncate a\n // partitioned sample instead of completing it.\n requireAuthoredSize: true,\n maxSegmentsPerSample: maxSubsampleSegments,\n }\n this.#defaultTrack = config?.defaultTrack ?? null\n if (this.#defaultTrack) this.#validateReassemblyPolicy()\n if (config?.tracks) {\n for (const [id, info] of config.tracks) {\n this.#validateReassemblyPolicy()\n this.#tracks.set(id, info)\n }\n }\n }\n\n /** The MFU reassembler that buffers fragmented MFUs fed via feed().\n * Exposed so a co-operating FEC-recovery layer (MmtpRouter) feeds recovered\n * fragments into the SAME reassembler: a frame split between source-received\n * and FEC-recovered fragments must share one buffer to complete (BLO-8151).\n * Before this was shared, recovered video symbols reported \"0 emitted,\n * pending-reassembly=N\" because they landed in a separate instance. */\n get reassembler(): MfuReassemblerBackend {\n return this.#reassembler\n }\n\n /**\n * Subsample-combining counters (moqcast #37). `combinedSamples` counts\n * samples reassembled from two or more data units and `passthroughSamples`\n * those that arrived whole; the two are deliberately separate, so a\n * producer that silently stopped partitioning cannot hide behind a single\n * \"samples delivered\" total. This is the typed acceptance signal for\n * large-frame playback \u2014 never parse the console for it.\n */\n get sampleCombinerStats(): Readonly<SampleCombinerStats> {\n const total = { ...this.#retiredSampleCombinerStats }\n for (const combiner of this.#sampleCombiners.values()) {\n const stats = combiner.stats\n total.combinedSamples += stats.combinedSamples\n total.passthroughSamples += stats.passthroughSamples\n total.timedOutSamples += stats.timedOutSamples\n total.evictedSamples += stats.evictedSamples\n }\n return total\n }\n\n get reorderStats(): Readonly<MmtpReorderStats> {\n let bufferedFrames = 0\n for (const { sequencer } of this.#sequencers.values()) bufferedFrames += sequencer.buffered\n return { ...this.#reorderStats, bufferedFrames }\n }\n\n get reorderDiagnostics(): ReadonlyArray<MmtpReorderStreamDiagnostics> {\n const streams: MmtpReorderStreamDiagnostics[] = []\n for (const { packetId, sequencer } of this.#sequencers.values()) {\n for (const diagnostics of sequencer.diagnostics) streams.push({ packetId, ...diagnostics })\n }\n return streams\n }\n\n /**\n * Phase 1 of two-phase parsing. Returns structured header info for FEC feeding.\n * Call this before feed() when you need to extract FEC payload ID and feed\n * symbols to FECManager before MFU extraction.\n * Returns null for malformed packets.\n */\n parseHeader(packet: Uint8Array, options?: ParseHeaderOptions): PacketInfo | null {\n try {\n const header = parseMMTPHeader(packet)\n const isRepair = header.packetType === PACKET_TYPE_REPAIR\n const fecPayloadId =\n !options?.skipFecPayloadId &&\n !isRepair && hasSourceFecPayloadId(packet)\n ? extractFecPayloadId(packet)\n : null\n return {\n packetId: header.packetId,\n packetType: header.packetType,\n timestamp: header.timestamp,\n timestampUs: mmtpTimestampToMicros(header.timestamp),\n sequenceNumber: header.sequenceNumber,\n rapFlag: header.rapFlag,\n fecType: header.fecType,\n fecPayloadId,\n isRepair,\n }\n } catch {\n return null\n }\n }\n\n /** Feed a complete MMTP packet. For two-phase use, call parseHeader() first. */\n feed(packet: Uint8Array, options?: ParseHeaderOptions): MmtpParserRecord | null {\n if (this.#disposed) return null\n\n const info = this.parseHeader(packet, options)\n if (!info) return null\n\n if (info.packetType !== PACKET_TYPE_MPU) {\n return {\n kind: info.isRepair ? 'repair' : 'non-media',\n packet: info,\n byteLength: packet.byteLength,\n }\n }\n\n // \u2500\u2500 FEC source-symbol exposure \u2500\u2500\n // Fire onSourceSymbol BEFORE MFU extraction so the consumer-side FEC\n // pipeline (e.g. FecWorkerClient.feedSource) starts as early as possible.\n // Source-only: parseHeader already gates fecPayloadId on !isRepair.\n if (info.fecPayloadId !== null && this.#sourceSymbolCb) {\n // Strip the 4-byte fec_payload_id trailer per ISO 23008-1 \u00A7C.5.2.\n // Symbol-size zero-padding is the consumer's responsibility \u2014 FEC\n // symbol size is a FEC-config concern, not a parser concern.\n const rawSymbol = packet.subarray(0, packet.length - 4)\n const altaTrailer = extractAltaTrailer(packet)\n const alta = altaTrailer\n ? { auth: altaTrailer.auth, payloadEnd: altaTrailer.signedEnd }\n : undefined\n try {\n this.#sourceSymbolCb(info.packetId, info.fecPayloadId.ssId, rawSymbol, alta)\n } catch {\n // Source-symbol consumer threw \u2014 never block MFU extraction on\n // FEC-pipeline errors. The frame path stays viable; the consumer\n // is responsible for its own error surfacing.\n }\n }\n\n const extraction = extractMFUPayload(packet, {\n skipFecId: options?.skipFecPayloadId,\n })\n if (!extraction) return null\n\n const { mpu, fragmentType, data, mfuDuHeader } = extraction\n if (mpu.timedFlag !== 1) return null\n const streamKey = this.#streamKey(info.packetId, options?.catalogTrackName)\n\n if (fragmentType === 0) {\n if (mpu.fragmentationIndicator !== 0 || mpu.fragmentCounter !== 0) return null\n const resolver = this.#timingResolver(streamKey, info.packetId, true)\n if (!resolver?.addInitialization(data)) return null\n this.#initCb?.(data, info.packetId, options?.catalogTrackName)\n return {\n kind: 'init',\n packet: info,\n data,\n mpuSequenceNumber: mpu.mpuSequenceNumber,\n fragmentationIndicator: mpu.fragmentationIndicator,\n fragmentCounter: mpu.fragmentCounter,\n }\n }\n\n if (fragmentType === 1) {\n if (mpu.fragmentationIndicator !== 0 || mpu.fragmentCounter !== 0) return null\n const resolver = this.#timingResolver(streamKey, info.packetId, false)\n if (!resolver) return null\n const pendingBefore = resolver.pendingSampleCount\n const remaining = this.#maxPendingTimingSamples - this.#pendingTimingSamples\n if (!resolver.addMovieFragment(mpu.mpuSequenceNumber, data, remaining)) return null\n this.#pendingTimingSamples += resolver.pendingSampleCount - pendingBefore\n return {\n kind: 'fragment',\n packet: info,\n data,\n mpuSequenceNumber: mpu.mpuSequenceNumber,\n fragmentationIndicator: mpu.fragmentationIndicator,\n fragmentCounter: mpu.fragmentCounter,\n }\n }\n if (fragmentType !== 2) return null\n\n const resolver = this.#timingResolver(streamKey, info.packetId, false)\n if (!resolver) return null\n if (!Number.isSafeInteger(data.byteLength) || data.byteLength <= 0) return null\n if (mpu.fragmentationIndicator === 0 || mpu.fragmentationIndicator === 1) {\n if (!mfuDuHeader || mfuDuHeader.movieFragmentSequenceNumber === 0 ||\n mfuDuHeader.sampleNumber === 0) {\n return null\n }\n const headTiming = resolver.sampleTiming(\n mpu.mpuSequenceNumber,\n mfuDuHeader.movieFragmentSequenceNumber,\n mfuDuHeader.sampleNumber,\n )\n if (!headTiming) return null\n // A data unit's authored base offset is its position within the sample\n // (moqcast #37): 0 for a whole-sample DU, nonzero for one subsample DU\n // among siblings. Sizes below are therefore relative to that base, not\n // to the sample's start -- comparing a subsample DU against the whole\n // sample's size is what dropped every partitioned 4K/8K frame.\n const offset = mfuDuHeader.offset\n if (!Number.isSafeInteger(offset) || offset < 0 || offset >= headTiming.size) return null\n const remaining = headTiming.size - offset\n // FI=0 carries its data unit whole, in a single payload. Only a\n // partitioned sample's FINAL data unit can be shorter than a full data\n // unit -- every earlier one spans exactly 256 payloads and so is always\n // fragmented -- which makes a whole-carried DU exactly the bytes left\n // from its base. At offset 0 this is the pre-amendment check unchanged.\n if (mpu.fragmentationIndicator === 0 && data.byteLength !== remaining) return null\n if (mpu.fragmentationIndicator === 1 && data.byteLength >= remaining) return null\n\n // Publish the authored size before this data unit can complete, so the\n // combiner never has to guess whether an offset-zero DU is a whole\n // sample. Registering can itself complete a sample whose data units all\n // arrived while the size was still unknown; that sample is delivered\n // through routeFrame like any other, and this packet's own fragment\n // continues below.\n const readyOnRegister = this.#sampleCombinerFor(streamKey).registerAuthoredSize(\n options?.catalogTrackName,\n mpu.mpuSequenceNumber,\n mfuDuHeader.movieFragmentSequenceNumber,\n mfuDuHeader.sampleNumber,\n headTiming.size,\n )\n if (readyOnRegister) {\n this.#emitCombinedSample(readyOnRegister, info, resolver, options?.recovered === true)\n }\n }\n\n let assembled: ReassembledMFU | null\n try {\n assembled = this.#reassembler.addFragment({\n fragmentationIndicator: mpu.fragmentationIndicator,\n mpuSequenceNumber: mpu.mpuSequenceNumber,\n fragmentCounter: mpu.fragmentCounter,\n data,\n timestamp: info.timestamp,\n rapFlag: info.rapFlag,\n priority: mfuDuHeader?.priority,\n sampleNumber: mfuDuHeader?.sampleNumber,\n movieFragmentSequenceNumber: mfuDuHeader?.movieFragmentSequenceNumber,\n sampleOffset: mfuDuHeader?.offset,\n packetSequenceNumber: info.sequenceNumber,\n recovered: options?.recovered === true,\n source: options?.source,\n deliveryProvenance: options?.deliveryProvenance,\n catalogTrackName: options?.catalogTrackName,\n packetId: info.packetId,\n })\n } catch (error) {\n if (!(error instanceof MfuReassemblyError)) throw error\n console.warn(\n `[MmtpContainerParser] rejected MFU fragment: code=${error.code} ` +\n `mpu=${mpu.mpuSequenceNumber} fi=${mpu.fragmentationIndicator} ` +\n `counter=${mpu.fragmentCounter}`,\n )\n return {\n kind: 'rejected',\n packet: info,\n mpuSequenceNumber: mpu.mpuSequenceNumber,\n fragmentationIndicator: mpu.fragmentationIndicator,\n fragmentCounter: mpu.fragmentCounter,\n error: { code: error.code, message: error.message },\n }\n }\n\n if (!assembled) {\n return {\n kind: 'pending',\n packet: info,\n mpuSequenceNumber: mpu.mpuSequenceNumber,\n fragmentationIndicator: mpu.fragmentationIndicator,\n fragmentCounter: mpu.fragmentCounter,\n }\n }\n\n const movieFragmentSequenceNumber = assembled.movieFragmentSequenceNumber\n const sampleNumber = assembled.sampleNumber\n if (movieFragmentSequenceNumber === undefined || sampleNumber === undefined) return null\n // Resolve authored timing BEFORE the combiner sees this data unit. An\n // assembled data unit whose sample identity has no authored timing is not\n // a sample this stream declared, so it must be dropped outright -- letting\n // it buffer would occupy a combiner slot and could evict a legitimate\n // partitioned sample waiting on a sibling.\n if (!resolver.sampleTiming(\n assembled.mpuSequenceNumber,\n movieFragmentSequenceNumber,\n sampleNumber,\n )) return null\n if (assembled.mpuSequenceNumber !== mpu.mpuSequenceNumber) return null\n\n // One reassembled data unit is not necessarily one whole sample. A\n // partitioned sample completes only once every sibling data unit has\n // arrived and they are byte-adjacent from zero to the authored size; an\n // unpartitioned sample passes straight through with no buffering.\n let combined: CombinedSample | null\n try {\n combined = this.#sampleCombinerFor(streamKey).addMfu(assembled)\n } catch (error) {\n if (!(error instanceof SampleCombineError)) throw error\n console.warn(\n `[MmtpContainerParser] rejected subsample data unit: code=${error.code} ` +\n `mpu=${assembled.mpuSequenceNumber} sample=${sampleNumber} ` +\n `offset=${assembled.sampleOffset ?? 0}`,\n )\n return {\n kind: 'rejected',\n packet: info,\n mpuSequenceNumber: mpu.mpuSequenceNumber,\n fragmentationIndicator: mpu.fragmentationIndicator,\n fragmentCounter: mpu.fragmentCounter,\n error: { code: error.code, message: error.message },\n }\n }\n if (!combined) {\n return {\n kind: 'pending',\n packet: info,\n mpuSequenceNumber: mpu.mpuSequenceNumber,\n fragmentationIndicator: mpu.fragmentationIndicator,\n fragmentCounter: mpu.fragmentCounter,\n }\n }\n\n return this.#emitCombinedSample(combined, info, resolver, options?.recovered === true)\n }\n\n /**\n * Deliver one combined sample: resolve its authored timing, build frame\n * metadata, retire the timing entry, and route it. Shared by the ordinary\n * completion path and by the rarer completion that falls out of registering\n * an authored size for data units that arrived before it.\n */\n #emitCombinedSample(\n combined: CombinedSample,\n info: PacketInfo,\n resolver: IsoBmffTimingResolver,\n recovered: boolean,\n ): MmtpParserRecord | null {\n const timing = resolver.sampleTiming(\n combined.mpuSequenceNumber,\n combined.movieFragmentSequenceNumber,\n combined.sampleNumber,\n )\n if (!timing) return null\n // The combiner already completes against the registered authored size;\n // re-checking here keeps the unpartitioned passthrough path fail-closed\n // on the same invariant rather than trusting it by construction.\n if (combined.data.byteLength !== timing.size) return null\n\n const meta = this.#buildFrameMeta(\n combined,\n info.packetId,\n info.sequenceNumber,\n timing,\n recovered,\n )\n if (!meta) return null\n if (!resolver.consumeSample(\n combined.mpuSequenceNumber,\n combined.movieFragmentSequenceNumber,\n combined.sampleNumber,\n timing,\n )) return null\n this.#pendingTimingSamples--\n this.routeFrame(combined.data, meta)\n return {\n kind: 'frame',\n packet: info,\n data: combined.data,\n meta,\n mpuSequenceNumber: combined.mpuSequenceNumber,\n fragmentCount: combined.fragmentCount,\n rapFlag: combined.rapFlag,\n ...(combined.priority === undefined ? {} : { priority: combined.priority }),\n }\n }\n\n onInit(cb: InitCallback): void {\n this.#initCb = cb\n }\n\n onFrame(cb: FrameCallback): void {\n this.#frameCb = cb\n }\n\n /** Register a per-packet FEC source-symbol callback. Fires for each MMTP\n * source MPU packet that carries a Source FEC Payload ID (ISO 23008-1 \u00A7C.5.2).\n *\n * Consumer responsibilities:\n * - Zero-pad `rawSymbol` to the FEC `symbolSize` if shorter (FEC config is\n * out-of-band \u2014 typically from the CMSF catalog's `fec.symbolSize`).\n * - Decide oversized handling (rawSymbol.length > symbolSize is not FEC-\n * decodable; consumer typically skips that block's source-feed).\n * - Look up the right FEC consumer (e.g. FecWorkerClient) by packetId.\n *\n * Designed for spec-clean reuse: Shaka, upstream moqtail, or any consumer\n * that uses MmtpContainerParser can wire FEC source delivery without\n * pulling in MulticastManager/MmtpRouter/FECManager. */\n onSourceSymbol(cb: SourceSymbolCallback): void {\n this.#sourceSymbolCb = cb\n }\n\n onTrackFrame(packetId: number, cb: FrameCallback): void {\n this.#trackFrameCbs.set(packetId, cb)\n }\n\n setTrack(packetId: number, info: TrackInfo): void {\n this.#validateReassemblyPolicy()\n for (const [key, entry] of this.#sequencers) {\n if (entry.packetId !== packetId) continue\n entry.sequencer.flush()\n this.#sequencers.delete(key)\n }\n for (const [key, state] of this.#timingStreams) {\n if (state.packetId === packetId) this.#dropTimingStream(key)\n }\n for (const key of [...this.#sampleCombiners.keys()]) {\n if ((JSON.parse(key) as [number, string | null])[0] === packetId) {\n this.#dropSampleCombiner(key)\n }\n }\n for (const [key, gatedPacketId] of this.#reliableMoqStartupGate) {\n if (gatedPacketId === packetId) this.#reliableMoqStartupGate.delete(key)\n }\n this.#tracks.set(packetId, info)\n }\n\n /** Drop one physical stream's ordering and MFU state for retained replay. */\n resetTrack(packetId: number, catalogTrackName: string): void {\n if (!catalogTrackName) {\n throw new Error('[MmtpContainerParser] catalogTrackName is required for track reset')\n }\n for (const [key, entry] of this.#sequencers) {\n if (key !== this.#streamKey(packetId, catalogTrackName)) continue\n entry.sequencer.discard()\n this.#sequencers.delete(key)\n }\n const streamKey = this.#streamKey(packetId, catalogTrackName)\n this.#dropTimingStream(streamKey)\n this.#reliableMoqStartupGate.delete(streamKey)\n this.#reassembler.resetStream(catalogTrackName)\n // Drop half-combined samples too: a partitioned sample whose siblings\n // straddle the reset would otherwise complete against a stale authored\n // size and hand the decoder bytes from two different publisher epochs.\n this.#dropSampleCombiner(streamKey)\n }\n\n setMfuTimeoutMs(ms: number | null): void {\n if (ms !== null && ms <= 0) throw new Error('[MmtpContainerParser] mfuTimeoutMs must be > 0')\n this.#reassembler.timeoutMs = ms\n }\n\n setReassemblyPolicy(policy: MfuReassemblyPolicy): void {\n const timeoutMs = mfuReassemblyTimeoutMs(policy)\n this.#validateReassemblyPolicy(policy)\n this.#flushSequencers()\n this.#reassemblyPolicy = policy\n this.#reliableMoqStartupGate.clear()\n this.setMfuTimeoutMs(timeoutMs)\n }\n\n setReorderWindow(windowSize: number): void {\n if (!Number.isFinite(windowSize) || windowSize < 0) {\n throw new Error('[MmtpContainerParser] reorderWindow must be a finite number >= 0')\n }\n const nextWindow = Math.ceil(windowSize)\n this.#validateReassemblyPolicy(this.#reassemblyPolicy, nextWindow)\n this.#flushSequencers()\n this.#reorderWindow = nextWindow\n if (this.#reorderWindow <= 0) this.#sequencers.clear()\n }\n\n /** Route an already-assembled frame through the same reorder/callback path\n * used by source packets. FEC recovery uses this to merge recovered frames\n * with direct source frames before the decoder sees them. */\n routeFrame(data: Uint8Array, meta: FrameMeta): void {\n const seq = meta.packetSequenceNumber\n const sequencer = this.#sequencerFor(meta.packetId, meta.trackType, meta.catalogTrackName)\n if (sequencer && seq !== undefined && Number.isFinite(seq)) {\n sequencer.push(data, meta, seq)\n return\n }\n if (this.#reassemblyPolicy?.transport === 'reliable-moq' &&\n meta.trackType === 'video' &&\n !this.#passReliableMoqStartupGate(meta)) {\n return\n }\n this.#emitFrame(data, meta)\n }\n\n /**\n * Claim and return the authored timing for a recovered sample. Recovery does\n * not pass through the ordinary `feed()` completion path, so it must retire\n * the same bounded resolver entry once the router accepts the recovered\n * sample. A missing entry is a fail-closed signal: callers must not replace\n * it with an MMTP send timestamp or cadence guess.\n */\n consumeAuthoredTimingFor(\n packetId: number,\n mpuSequenceNumber: number,\n movieFragmentSequenceNumber: number | undefined,\n sampleNumber: number | undefined,\n catalogTrackName?: string,\n ): AuthoredTiming | null {\n if (movieFragmentSequenceNumber === undefined || sampleNumber === undefined) return null\n const resolver = this.#timingResolver(\n this.#streamKey(packetId, catalogTrackName),\n packetId,\n false,\n )\n const timing = resolver?.sampleTiming(\n mpuSequenceNumber,\n movieFragmentSequenceNumber,\n sampleNumber,\n )\n if (!timing || !resolver || !resolver.consumeSample(\n mpuSequenceNumber,\n movieFragmentSequenceNumber,\n sampleNumber,\n timing,\n )) return null\n this.#pendingTimingSamples--\n if (this.#pendingTimingSamples < 0) {\n throw new Error('[MmtpContainerParser] pending timing sample accounting underflow')\n }\n return {\n decodeTime: timing.decodeTime,\n presentationTime: timing.presentationTime,\n durationTicks: timing.duration,\n mediaTimescale: timing.timescale,\n }\n }\n\n /** Order-independent reliable-moq startup gate: discard delta frames for a\n * stream until its first RAP is observed, without buffering/reordering. */\n #passReliableMoqStartupGate(meta: FrameMeta): boolean {\n const streamKey = this.#streamKey(meta.packetId, meta.catalogTrackName)\n if (meta.sourceDiscontinuity) this.#reliableMoqStartupGate.delete(streamKey)\n if (this.#reliableMoqStartupGate.has(streamKey)) return true\n if (!meta.keyframe) {\n this.#reorderStats.droppedBeforeStartupKeyframe++\n return false\n }\n this.#reliableMoqStartupGate.set(streamKey, meta.packetId)\n return true\n }\n\n /** Emit all ordered frames currently buffered by the parser. Finite-stream\n * consumers may call this before dispose(); live cancellation should not. */\n flush(): void {\n if (this.#disposed) return\n this.#flushSequencers()\n }\n\n dispose(): void {\n this.#disposed = true\n for (const { sequencer } of this.#sequencers.values()) sequencer.discard()\n this.#sequencers.clear()\n this.#timingStreams.clear()\n this.#pendingTimingSamples = 0\n this.#reliableMoqStartupGate.clear()\n this.#reassembler.reset()\n this.#frameCb = null\n this.#initCb = null\n this.#trackFrameCbs.clear()\n }\n\n // \u2500\u2500 Private \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #timingResolver(\n streamKey: string,\n packetId: number,\n create: boolean,\n ): IsoBmffTimingResolver | null {\n const existing = this.#timingStreams.get(streamKey)\n if (existing) return existing.resolver\n if (!create) return null\n const resolver = new IsoBmffTimingResolver(this.#maxPendingTimingSamples)\n this.#timingStreams.set(streamKey, { packetId, resolver })\n return resolver\n }\n\n #dropTimingStream(streamKey: string): void {\n const state = this.#timingStreams.get(streamKey)\n if (!state) return\n this.#timingStreams.delete(streamKey)\n this.#pendingTimingSamples -= state.resolver.pendingSampleCount\n if (this.#pendingTimingSamples < 0) {\n throw new Error('[MmtpContainerParser] pending timing sample accounting underflow')\n }\n }\n\n #validateReassemblyPolicy(\n policy: MfuReassemblyPolicy | null = this.#reassemblyPolicy,\n reorderWindow = this.#reorderWindow,\n ): void {\n if (!policy) return\n mmtpFrameReorderWindowFrames(policy, reorderWindow)\n }\n\n #buildFrameMeta(\n assembled: CombinedSample,\n packetId: number,\n seq: number,\n timing: IsoBmffSampleTiming,\n recovered = false,\n ): FrameMeta | null {\n const { data, timestamp: mmtpTimestamp, rapFlag, priority } = assembled\n\n if (isFmp4Box(data)) return null\n const presentationTimestamp = mediaTicksToMicroseconds(\n timing.presentationTime,\n timing.timescale,\n )\n const decodeTimestamp = mediaTicksToMicroseconds(timing.decodeTime, timing.timescale)\n const duration = mediaTicksToMicroseconds(BigInt(timing.duration), timing.timescale)\n if (presentationTimestamp === null || decodeTimestamp === null || duration === null ||\n duration <= 0) {\n return null\n }\n\n let track = this.#tracks.get(packetId)\n if (!track && this.#defaultTrack) {\n track = this.#defaultTrack\n this.#tracks.set(packetId, track)\n }\n const codec = track?.codec ?? ''\n\n const keyframe = MmtpContainerParser.isKeyframe(data, isMfuKeyframeMetadata(rapFlag, priority), codec)\n\n const meta: FrameMeta = {\n timestamp: presentationTimestamp,\n decodeTimestamp,\n duration,\n decodeTime: timing.decodeTime,\n presentationTime: timing.presentationTime,\n durationTicks: timing.duration,\n mediaTimescale: timing.timescale,\n authoredTiming: {\n decodeTime: timing.decodeTime,\n presentationTime: timing.presentationTime,\n durationTicks: timing.duration,\n mediaTimescale: timing.timescale,\n },\n keyframe,\n packetId,\n trackType: track?.type ?? null,\n packetSequenceNumber: seq,\n ...(assembled.packetSequenceNumbers === undefined\n ? {}\n : { packetSequenceNumbers: assembled.packetSequenceNumbers }),\n ...(assembled.repairedPacketSequenceNumbers === undefined\n ? {}\n : { repairedPacketSequenceNumbers: assembled.repairedPacketSequenceNumbers }),\n ...(assembled.catalogTrackName === undefined\n ? {}\n : { catalogTrackName: assembled.catalogTrackName }),\n mmtpTimestamp,\n mpuSequenceNumber: assembled.mpuSequenceNumber,\n ...(assembled.movieFragmentSequenceNumber === undefined\n ? {}\n : { movieFragmentSequenceNumber: assembled.movieFragmentSequenceNumber }),\n ...(assembled.sampleNumber === undefined ? {} : { sampleNumber: assembled.sampleNumber }),\n fragmentCount: assembled.fragmentCount,\n rapFlag,\n ...(priority === undefined ? {} : { priority }),\n ...(assembled.source === undefined ? {} : { source: assembled.source }),\n deliveryProvenance: assembled.deliveryProvenance,\n }\n if (recovered || (assembled.repairedPacketSequenceNumbers?.length ?? 0) > 0) {\n meta.recovered = true\n }\n\n return meta\n }\n\n #sequencerFor(\n packetId: number,\n _trackType: FrameMeta['trackType'],\n catalogTrackName?: string,\n ): FrameSequencer | null {\n const windowSize = this.#reassemblyPolicy\n ? mmtpFrameReorderWindowFrames(this.#reassemblyPolicy, this.#reorderWindow)\n : this.#reorderWindow\n if (windowSize <= 0) return null\n const streamKey = this.#streamKey(packetId, catalogTrackName)\n let sequencer = this.#sequencers.get(streamKey)?.sequencer\n if (!sequencer) {\n sequencer = new FrameSequencer(windowSize, (data, meta) => {\n this.#emitFrame(data, meta)\n }, (stat, count = 1) => {\n this.#reorderStats[stat] += count\n })\n this.#sequencers.set(streamKey, { packetId, sequencer })\n }\n return sequencer\n }\n\n #flushSequencers(): void {\n for (const { sequencer } of this.#sequencers.values()) sequencer.flush()\n this.#sequencers.clear()\n }\n\n /** Authored presentation timestamp of the last emitted frame, in microseconds. */\n lastFrameTimestamp: number | undefined = undefined\n\n #emitFrame(data: Uint8Array, meta: FrameMeta): void {\n this.lastFrameTimestamp = meta.timestamp\n const trackCb = this.#trackFrameCbs.get(meta.packetId)\n trackCb?.(data, meta)\n this.#frameCb?.(data, meta)\n }\n\n // \u2500\u2500 Static utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n static isKeyframe(data: Uint8Array, rapFlag: boolean, codec = ''): boolean {\n const payloadKeyframe = MmtpContainerParser.#scanForKeyframe(data, codec)\n if (payloadKeyframe !== undefined) return payloadKeyframe\n return rapFlag\n }\n\n static #scanForKeyframe(data: Uint8Array, codec: string): boolean | undefined {\n const c = codec.toLowerCase()\n if (data.length === 0) return undefined\n\n if (c.startsWith('av01')) {\n return scanAv1ObusForKeyframe(data)\n }\n\n if (c.startsWith('vp09') || c.startsWith('vp8')) {\n return (data[0]! & 0x04) === 0\n }\n\n const isHevc = c.startsWith('hev1') || c.startsWith('hvc1')\n if (isHevc) {\n if (data.length < 5) return undefined\n if (startsWithAnnexB(data)) {\n return MmtpContainerParser.#scanAnnexBForKeyframe(data, true)\n }\n return MmtpContainerParser.#scanLengthPrefixedHevcForKeyframe(data)\n }\n\n if (c === '' || c.startsWith('avc')) {\n return classifyH264Keyframe(data, { allowPartialAvcc: true })\n }\n\n return undefined\n }\n\n static #scanLengthPrefixedHevcForKeyframe(data: Uint8Array): boolean | undefined {\n let sawNal = false\n let offset = 0\n while (offset + 4 < data.length) {\n const nalLen =\n (data[offset]! << 24) |\n (data[offset + 1]! << 16) |\n (data[offset + 2]! << 8) |\n data[offset + 3]!\n offset += 4\n if (nalLen <= 0) return sawNal ? false : undefined\n // The router's sync probe may see only the first fragment of a large\n // length-prefixed NAL. The length can exceed this packet, but the NAL\n // header is still enough to classify IRAP/IDR and open the sync gate.\n if (offset >= data.length) return sawNal ? false : undefined\n sawNal = true\n const hevcType = (data[offset]! >> 1) & 0x3f\n if (hevcType >= 16 && hevcType <= 21) return true\n if (offset + nalLen > data.length) break\n offset += nalLen\n }\n return sawNal ? false : undefined\n }\n\n static #scanAnnexBForKeyframe(data: Uint8Array, isHevc: boolean): boolean | undefined {\n let offset = 0\n let sawNal = false\n while (offset < data.length) {\n const start = findAnnexBStart(data, offset)\n if (!start) return sawNal ? false : undefined\n const headerOffset = start.offset + start.length\n if (headerOffset >= data.length) return sawNal ? false : undefined\n sawNal = true\n if (isHevc) {\n if (headerOffset + 1 >= data.length) return sawNal ? false : undefined\n const hevcType = (data[headerOffset]! >> 1) & 0x3f\n if (hevcType >= 16 && hevcType <= 21) return true\n } else {\n const nalType = data[headerOffset]! & 0x1f\n if (nalType === 5) return true\n }\n offset = headerOffset + 1\n }\n return sawNal ? false : undefined\n }\n}\n\nfunction scanAv1ObusForKeyframe(data: Uint8Array): boolean | undefined {\n let offset = 0\n let sawSequenceHeader = false\n let sawFrame = false\n\n while (offset < data.length) {\n const obu = readAv1Obu(data, offset)\n if (!obu) return sawFrame ? false : undefined\n offset = obu.nextOffset\n\n if (obu.type === 1) {\n sawSequenceHeader = true\n continue\n }\n if (obu.type !== 3 && obu.type !== 6) continue\n\n sawFrame = true\n if (!sawSequenceHeader) {\n continue\n }\n\n const keyframe = readAv1FrameHeaderKeyframe(data.subarray(obu.payloadOffset, obu.payloadEnd))\n if (keyframe !== undefined) return keyframe\n }\n\n return sawFrame ? false : undefined\n}\n\nfunction readAv1Obu(\n data: Uint8Array,\n offset: number,\n): { type: number; payloadOffset: number; payloadEnd: number; nextOffset: number } | null {\n if (offset >= data.length) return null\n const header = data[offset]!\n if ((header & 0x80) !== 0 || (header & 0x01) !== 0) return null\n\n const type = (header >> 3) & 0x0f\n const extensionFlag = (header & 0x04) !== 0\n const hasSizeField = (header & 0x02) !== 0\n let cursor = offset + 1\n if (extensionFlag) cursor += 1\n if (cursor > data.length) return null\n\n let payloadSize = data.length - cursor\n if (hasSizeField) {\n const leb = readLeb128(data, cursor)\n if (!leb) return null\n payloadSize = leb.value\n cursor = leb.nextOffset\n }\n\n const payloadEnd = cursor + payloadSize\n if (payloadEnd > data.length) return null\n return { type, payloadOffset: cursor, payloadEnd, nextOffset: payloadEnd }\n}\n\nfunction readLeb128(data: Uint8Array, offset: number): { value: number; nextOffset: number } | null {\n let value = 0\n for (let i = 0; i < 8; i++) {\n if (offset + i >= data.length) return null\n const byte = data[offset + i]!\n value += (byte & 0x7f) * (2 ** (i * 7))\n if ((byte & 0x80) === 0) return { value, nextOffset: offset + i + 1 }\n }\n return null\n}\n\nfunction readAv1FrameHeaderKeyframe(payload: Uint8Array): boolean | undefined {\n if (payload.length === 0) return undefined\n const first = payload[0]!\n const showExistingFrame = (first & 0x80) !== 0\n if (showExistingFrame) return false\n const frameType = (first >> 5) & 0x03\n return frameType === 0\n}\n\nfunction startsWithAnnexB(data: Uint8Array): boolean {\n return (\n (data.length >= 4 && data[0] === 0 && data[1] === 0 && data[2] === 1) ||\n (data.length >= 5 && data[0] === 0 && data[1] === 0 && data[2] === 0 && data[3] === 1)\n )\n}\n\nfunction findAnnexBStart(data: Uint8Array, offset: number): { offset: number; length: 3 | 4 } | null {\n for (let i = offset; i + 3 <= data.length; i++) {\n if (data[i] !== 0 || data[i + 1] !== 0) continue\n if (data[i + 2] === 1) return { offset: i, length: 3 }\n if (i + 3 < data.length && data[i + 2] === 0 && data[i + 3] === 1) {\n return { offset: i, length: 4 }\n }\n }\n return null\n}\n", "import type {\n MFUFragment,\n MfuReassemblerBackend,\n PendingMfuDebug,\n ReassembledMFU,\n ReassemblerStats,\n} from './mfu-reassembler.js'\nimport {\n isMfuReassemblyErrorCode,\n MfuReassemblyError,\n} from './mfu-reassembler.js'\n\nexport interface MmtWasmFragment {\n with_sample_identity(movieFragmentSequence: number, sampleNumber: number, offset: number): void\n set_item_id(itemId: number): void\n set_packet_delivery?(packetSequenceNumber: number, recovered: boolean): void\n set_priority(priority: number): void\n set_attribution(attribution: number): void\n set_stream_identity(streamIdentity: number): void\n}\n\nexport interface MmtWasmReassembledMfu {\n readonly mpu_sequence_number: number\n readonly timestamp: number\n readonly fragment_count: number\n readonly rap_flag: boolean\n readonly priority?: number\n readonly sample_number?: number\n readonly movie_fragment_sequence_number?: number\n readonly packet_sequence_numbers?: Uint32Array | number[]\n readonly repaired_packet_sequence_numbers?: Uint32Array | number[]\n readonly attribution?: number\n readonly stream_identity?: number\n readonly data: Uint8Array\n free(): void\n}\n\nexport interface MmtWasmStats {\n readonly total_fragments: bigint | number\n readonly reassembled_mfus: bigint | number\n readonly timed_out_mfus: bigint | number\n readonly evicted_memory_limit: bigint | number\n readonly out_of_order_fragments: bigint | number\n readonly duplicate_fragments: bigint | number\n free?: () => void\n}\n\nexport interface MmtWasmReassembler {\n add_fragment(now: number, fragment: MmtWasmFragment): MmtWasmReassembledMfu | undefined\n cleanup_timeouts(now: number): void\n set_timeout(timeoutMs: number): void\n set_clock_free(): void\n next_timeout_at(): number | undefined\n flush(): void\n reset_stream(streamIdentity: number): void\n reset(): void\n stats(): MmtWasmStats\n readonly buffered_count: number\n readonly pending_fragment_count: number\n}\n\nexport interface MmtWasmBindings {\n MfuFragmentJs: new (\n mpuSequenceNumber: number,\n fragmentationIndicator: number,\n fragmentCounter: number,\n data: Uint8Array,\n timestamp: number,\n rapFlag: boolean,\n ) => MmtWasmFragment\n MmtReassembler: {\n new (timeoutMs: number, maxBuffered: number): MmtWasmReassembler\n clock_free(maxBuffered: number): MmtWasmReassembler\n }\n}\n\nexport interface WasmMfuReassemblerOptions {\n bindings: MmtWasmBindings\n timeoutMs: number | null\n maxBuffered?: number\n now?: () => number\n}\n\nfunction asNumber(value: bigint | number): number {\n return typeof value === 'bigint' ? Number(value) : value\n}\n\nfunction timestampU32(timestamp: bigint): number {\n return Number(BigInt.asUintN(32, timestamp))\n}\n\n/** Thin host adapter over mmt-core's Rust/WASM IFC reassembler. */\nexport class WasmMfuReassembler implements MfuReassemblerBackend {\n readonly #bindings: MmtWasmBindings\n readonly #core: MmtWasmReassembler\n readonly #now: () => number\n #timeoutMs: number | null\n #cleanupTimer: ReturnType<typeof setTimeout> | null = null\n #nextStreamIdentity = 1\n #streamIdentityByKey = new Map<string, number>()\n #streamNameByIdentity = new Map<number, string>()\n #coreTotalFragments = 0\n #rejectedBeforeCore = 0\n #rejectedFragments = 0\n\n readonly stats: ReassemblerStats = {\n totalFragments: 0,\n reassembledMFUs: 0,\n rejectedFragments: 0,\n timedOutMFUs: 0,\n evictedMemoryLimit: 0,\n outOfOrderFragments: 0,\n }\n\n onDeferredAssembly?: (result: ReassembledMFU) => void\n\n constructor(options: WasmMfuReassemblerOptions) {\n const maxBuffered = options.maxBuffered ?? 100\n if (!Number.isInteger(maxBuffered) || maxBuffered <= 0) {\n throw new Error('[WasmMfuReassembler] maxBuffered must be a positive integer')\n }\n this.#bindings = options.bindings\n this.#timeoutMs = options.timeoutMs\n this.#now = options.now ?? (() => globalThis.performance?.now() ?? Date.now())\n this.#core =\n options.timeoutMs === null\n ? options.bindings.MmtReassembler.clock_free(maxBuffered)\n : new options.bindings.MmtReassembler(options.timeoutMs, maxBuffered)\n }\n\n get timeoutMs(): number | null {\n return this.#timeoutMs\n }\n\n set timeoutMs(timeoutMs: number | null) {\n if (timeoutMs !== null && (!Number.isFinite(timeoutMs) || timeoutMs <= 0)) {\n throw new Error('[WasmMfuReassembler] timeoutMs must be a finite number > 0')\n }\n this.#timeoutMs = timeoutMs\n if (timeoutMs === null) this.#core.set_clock_free()\n else this.#core.set_timeout(Math.ceil(timeoutMs))\n this.#scheduleCleanup()\n }\n\n addFragment(fragment: MFUFragment): ReassembledMFU | null {\n const wasmFragment = new this.#bindings.MfuFragmentJs(\n fragment.mpuSequenceNumber,\n fragment.fragmentationIndicator,\n fragment.fragmentCounter,\n fragment.data,\n timestampU32(fragment.timestamp),\n fragment.rapFlag,\n )\n if (\n fragment.movieFragmentSequenceNumber !== undefined &&\n fragment.sampleNumber !== undefined &&\n fragment.sampleNumber > 0 &&\n fragment.sampleOffset !== undefined\n ) {\n wasmFragment.with_sample_identity(\n fragment.movieFragmentSequenceNumber,\n fragment.sampleNumber,\n fragment.sampleOffset,\n )\n }\n if (fragment.itemId !== undefined) wasmFragment.set_item_id(fragment.itemId)\n if (fragment.packetSequenceNumber !== undefined) {\n wasmFragment.set_packet_delivery?.(\n fragment.packetSequenceNumber,\n fragment.recovered === true,\n )\n }\n if (fragment.priority !== undefined) wasmFragment.set_priority(fragment.priority)\n if (fragment.source !== undefined) {\n wasmFragment.set_attribution(fragment.source === 'multicast' ? 1 : 2)\n }\n const streamIdentity = this.#streamIdentityFor(fragment)\n if (streamIdentity !== undefined) {\n wasmFragment.set_stream_identity(streamIdentity)\n }\n\n let output: MmtWasmReassembledMfu | undefined\n const coreTotalBefore = this.#coreTotalFragments\n try {\n output = this.#core.add_fragment(this.#now(), wasmFragment)\n } catch (error) {\n const rejection = this.#asReassemblyError(error)\n if (rejection === null) throw error\n this.#refreshStats()\n if (this.#coreTotalFragments === coreTotalBefore) this.#rejectedBeforeCore++\n this.#rejectedFragments++\n this.stats.totalFragments = this.#coreTotalFragments + this.#rejectedBeforeCore\n this.stats.rejectedFragments = this.#rejectedFragments\n this.#scheduleCleanup()\n throw rejection\n }\n this.#refreshStats()\n this.#scheduleCleanup()\n if (!output) return null\n\n try {\n const catalogTrackName = output.stream_identity === undefined\n ? undefined\n : this.#streamNameByIdentity.get(output.stream_identity)\n const packetSequenceNumbers = output.packet_sequence_numbers === undefined\n ? undefined\n : Array.from(output.packet_sequence_numbers)\n const repairedPacketSequenceNumbers =\n output.repaired_packet_sequence_numbers === undefined\n ? undefined\n : Array.from(output.repaired_packet_sequence_numbers)\n return {\n mpuSequenceNumber: output.mpu_sequence_number,\n ...(packetSequenceNumbers?.[0] === undefined\n ? {}\n : { packetSequenceNumber: packetSequenceNumbers[0] }),\n ...(packetSequenceNumbers === undefined ? {} : { packetSequenceNumbers }),\n ...(repairedPacketSequenceNumbers === undefined\n ? {}\n : { repairedPacketSequenceNumbers }),\n data: output.data,\n timestamp: BigInt(output.timestamp),\n fragmentCount: output.fragment_count,\n rapFlag: output.rap_flag,\n ...(output.priority === undefined ? {} : { priority: output.priority }),\n ...(output.sample_number === undefined ? {} : { sampleNumber: output.sample_number }),\n ...(output.movie_fragment_sequence_number === undefined\n ? {}\n : {\n movieFragmentSequenceNumber: output.movie_fragment_sequence_number,\n }),\n ...(output.attribution === 1\n ? { source: 'multicast' as const }\n : output.attribution === 2\n ? { source: 'moq' as const }\n : {}),\n // The Rust core folds `attribution` over every contributing fragment\n // and reports None unless they were unanimous, so a tag here is\n // already whole-frame evidence. A missing tag means \"not unanimous or\n // never recorded\" \u2014 both unproven, never multicast.\n deliveryProvenance:\n output.attribution === 1\n ? 'multicast'\n : output.attribution === 2\n ? 'mixed'\n : 'unknown',\n ...(catalogTrackName === undefined ? {} : { catalogTrackName }),\n }\n } finally {\n output.free()\n }\n }\n\n flush(): void {\n this.#clearCleanupTimer()\n this.#core.flush()\n }\n\n resetStream(catalogTrackName: string): void {\n const streamIdentity = this.#streamIdentityByKey.get(`catalog:${catalogTrackName}`)\n if (streamIdentity === undefined) return\n this.#clearCleanupTimer()\n this.#core.reset_stream(streamIdentity)\n this.#refreshStats()\n this.#scheduleCleanup()\n }\n\n reset(): void {\n this.#clearCleanupTimer()\n this.#core.reset()\n this.#nextStreamIdentity = 1\n this.#streamIdentityByKey.clear()\n this.#streamNameByIdentity.clear()\n this.#coreTotalFragments = 0\n this.#rejectedBeforeCore = 0\n this.#rejectedFragments = 0\n this.#refreshStats()\n }\n\n get pendingCount(): number {\n return this.#core.buffered_count\n }\n\n getStatus(): {\n bufferedMFUs: number\n pendingFragments: number\n pendingSamples: PendingMfuDebug[]\n stats: ReassemblerStats\n } {\n this.#refreshStats()\n return {\n bufferedMFUs: this.#core.buffered_count,\n pendingFragments: this.#core.pending_fragment_count,\n // Detailed fragment coordinates remain internal to the Rust core. Counts\n // and health statistics stay available to MmtpRouter diagnostics.\n pendingSamples: [],\n stats: { ...this.stats },\n }\n }\n\n #refreshStats(): void {\n const stats = this.#core.stats()\n this.#coreTotalFragments = asNumber(stats.total_fragments)\n this.stats.totalFragments = this.#coreTotalFragments + this.#rejectedBeforeCore\n this.stats.reassembledMFUs = asNumber(stats.reassembled_mfus)\n this.stats.rejectedFragments = this.#rejectedFragments\n this.stats.timedOutMFUs = asNumber(stats.timed_out_mfus)\n this.stats.evictedMemoryLimit = asNumber(stats.evicted_memory_limit)\n this.stats.outOfOrderFragments = asNumber(stats.out_of_order_fragments)\n stats.free?.()\n }\n\n #streamIdentityFor(fragment: MFUFragment): number | undefined {\n const key = fragment.catalogTrackName !== undefined\n ? `catalog:${fragment.catalogTrackName}`\n : fragment.packetId !== undefined\n ? `packet:${fragment.packetId}`\n : undefined\n if (key === undefined) return undefined\n const existing = this.#streamIdentityByKey.get(key)\n if (existing !== undefined) return existing\n const identity = this.#nextStreamIdentity++\n this.#streamIdentityByKey.set(key, identity)\n if (fragment.catalogTrackName !== undefined) {\n this.#streamNameByIdentity.set(identity, fragment.catalogTrackName)\n }\n return identity\n }\n\n #asReassemblyError(error: unknown): MfuReassemblyError | null {\n if ((typeof error !== 'object' && typeof error !== 'function') || error === null) return null\n const code = Reflect.get(error, 'code')\n if (!isMfuReassemblyErrorCode(code)) return null\n const message = Reflect.get(error, 'message')\n return new MfuReassemblyError(\n code,\n typeof message === 'string' ? message : `MFU reassembly rejected: ${code}`,\n )\n }\n\n #scheduleCleanup(): void {\n this.#clearCleanupTimer()\n if (this.#timeoutMs === null) return\n const next = this.#core.next_timeout_at()\n if (next === undefined) return\n const delay = Math.max(0, Math.ceil(next - this.#now()))\n this.#cleanupTimer = setTimeout(() => {\n this.#cleanupTimer = null\n this.#core.cleanup_timeouts(this.#now())\n this.#refreshStats()\n this.#scheduleCleanup()\n }, delay)\n }\n\n #clearCleanupTimer(): void {\n if (this.#cleanupTimer === null) return\n clearTimeout(this.#cleanupTimer)\n this.#cleanupTimer = null\n }\n}\n\nexport function resolveGlobalMmtWasmBindings(): MmtWasmBindings {\n const globals = globalThis as typeof globalThis & {\n __blockcastMmtReassemblerWasmBindgen?: MmtWasmBindings\n __MmtWasmBindings?: MmtWasmBindings\n }\n const bindings = globals.__MmtWasmBindings ?? globals.__blockcastMmtReassemblerWasmBindgen\n if (!bindings?.MmtReassembler || !bindings.MfuFragmentJs) {\n throw new Error('[WasmMfuReassembler] initialized mmt-wasm bindings are unavailable')\n }\n return bindings\n}\n", "import { MmtpContainerParser, type MmtpParserConfig } from './mmtp-container-parser.js'\nimport { WasmMfuReassembler, resolveGlobalMmtWasmBindings, type MmtWasmBindings } from './wasm-mfu-reassembler.js'\nimport { mfuReassemblyTimeoutMs, type MfuReassemblyPolicy } from './mfu-reassembly-policy.js'\n\nexport type WasmMmtpParserConfig = Omit<MmtpParserConfig, 'mfuTimeoutMs' | 'reassembler' | 'reassemblyPolicy'> & {\n reassemblyPolicy: MfuReassemblyPolicy\n wasmBindings?: MmtWasmBindings\n}\n\n/** Construct the common MMTP parser over the shared Rust/WASM IFC core. */\nexport function createWasmMmtpContainerParser(config: WasmMmtpParserConfig): MmtpContainerParser {\n const timeoutMs = mfuReassemblyTimeoutMs(config.reassemblyPolicy)\n const reassembler = new WasmMfuReassembler({\n bindings: config.wasmBindings ?? resolveGlobalMmtWasmBindings(),\n timeoutMs,\n ...(config.maxBufferedMfus === undefined ? {} : { maxBuffered: config.maxBufferedMfus }),\n })\n return new MmtpContainerParser({\n ...config,\n reassemblyPolicy: config.reassemblyPolicy,\n reassembler,\n })\n}\n", "/**\n * `multicast.auth` v2 \u2014 catalog representation for per-track source-auth\n * scopes and manifest tracks (BLO-16700 decision).\n *\n * Reconciles two previously-accepted, mutually incompatible contracts:\n * - BLO-16481 (S0): every publisher session/track/source-symbol-format\n * needs its own fresh, unpredictable 32-byte `auth_scope`, bound into\n * the signed per-group Merkle root (see `sourceAuthSignaturePreimage`\n * in ./source-auth.ts).\n * - BLO-16485 (S3 draft): a singular `multicast.auth` block with one\n * `manifestTrack` string and no `authScope` field at all \u2014 unable to\n * describe two protected tracks (e.g. audio + video) in one session.\n *\n * `multicast.auth` v2 keeps one shared signing identity (scheme, hash,\n * sig, publicKey, keyId, previousKey, compaction, enforcement) but moves\n * `manifestTrack` into a `tracks[]` array, one entry per protected media\n * track, each carrying its own `manifestTrack` name, `authScope`, and\n * `sourceSymbolFormat`. This is additive over the S3 draft shape (every\n * top-level field the draft specified still exists at the top level) \u2014\n * only `manifestTrack` moves from top-level into each track entry.\n *\n * `manifestTrack` is carried as an opaque string field, deliberately NOT\n * run through `parseTrackRole`/`VALID_ROLE_SUFFIXES` in ./carp-catalog.ts.\n * `carp-catalog.ts` only recognises `base`/`delta`/`repair` role suffixes\n * and throws on anything else (including a hypothetical `manifest` role);\n * resolving BLO-16485's \"manifest-track name collision\" MANDATORY item by\n * adding a role would force every catalog consumer to learn a fourth role\n * and would break `validateSwitchingSet`'s base/delta/repair completeness\n * check. Carrying it as a typed field here avoids both.\n */\n\nexport type MulticastAuthScheme = \"bc-provenance\";\nexport type MulticastAuthHash = \"blake3\";\nexport type MulticastAuthSig = \"ed25519\";\nexport type MulticastAuthCompaction = \"merkle\" | \"none\";\nexport type MulticastAuthEnforcement = \"shadow\" | \"enforce\";\nexport type MulticastAuthMode = \"off\" | MulticastAuthEnforcement;\n\nconst RAW_ED25519_KEY_LENGTH = 32;\nconst SOURCE_AUTH_SCOPE_LENGTH = 32;\n\nconst BASE64URL_ALPHABET =\n\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_\";\n\n/** Encode raw bytes as unpadded base64url \u2014 the one accepted encoding for\n * `authScope`/`publicKey`/`previousKey` (BLO-16483's operator quickstart). */\nexport function encodeBase64Url(bytes: Uint8Array): string {\n\tlet output = \"\";\n\tfor (let i = 0; i < bytes.length; i += 3) {\n\t\tconst b0 = bytes[i]!;\n\t\tconst b1 = bytes[i + 1];\n\t\tconst b2 = bytes[i + 2];\n\t\toutput += BASE64URL_ALPHABET[b0 >> 2];\n\t\toutput += BASE64URL_ALPHABET[((b0 & 0x03) << 4) | (b1 === undefined ? 0 : b1 >> 4)];\n\t\tif (b1 === undefined) break;\n\t\toutput += BASE64URL_ALPHABET[((b1 & 0x0f) << 2) | (b2 === undefined ? 0 : b2 >> 6)];\n\t\tif (b2 === undefined) break;\n\t\toutput += BASE64URL_ALPHABET[b2 & 0x3f];\n\t}\n\treturn output;\n}\n\nconst BASE64URL_DECODE_TABLE = (() => {\n\tconst table = new Int8Array(128).fill(-1);\n\tfor (let i = 0; i < BASE64URL_ALPHABET.length; i++) {\n\t\ttable[BASE64URL_ALPHABET.charCodeAt(i)] = i;\n\t}\n\treturn table;\n})();\n\n/** Decode unpadded base64url text to raw bytes. Throws on any padding\n * (`=`), standard-alphabet (`+`/`/`), or otherwise invalid character. */\nexport function decodeBase64Url(text: string): Uint8Array {\n\tif (text.length % 4 === 1) {\n\t\tthrow new Error(`[multicast-auth-catalog] invalid unpadded base64url length for \"${text}\"`);\n\t}\n\tconst bytes: number[] = [];\n\tlet buffer = 0;\n\tlet bits = 0;\n\tfor (let i = 0; i < text.length; i++) {\n\t\tconst code = text.charCodeAt(i);\n\t\tconst value = code < 128 ? BASE64URL_DECODE_TABLE[code] : -1;\n\t\tif (value === undefined || value < 0) {\n\t\t\tthrow new Error(`[multicast-auth-catalog] invalid base64url character in \"${text}\"`);\n\t\t}\n\t\tbuffer = (buffer << 6) | value;\n\t\tbits += 6;\n\t\tif (bits >= 8) {\n\t\t\tbits -= 8;\n\t\t\tbytes.push((buffer >> bits) & 0xff);\n\t\t}\n\t}\n\tconst decoded = Uint8Array.from(bytes);\n\tif (encodeBase64Url(decoded) !== text) {\n\t\tthrow new Error(`[multicast-auth-catalog] non-canonical base64url encoding \"${text}\"`);\n\t}\n\treturn decoded;\n}\n\n/** Decode + length-validate an `authScope` field. Throws unless it decodes\n * to exactly `SOURCE_AUTH_SCOPE_LENGTH` (32) raw bytes. */\nexport function decodeAuthScope(authScope: string): Uint8Array {\n\tconst bytes = decodeBase64Url(authScope);\n\tif (bytes.byteLength !== SOURCE_AUTH_SCOPE_LENGTH) {\n\t\tthrow new Error(\n\t\t\t`[multicast-auth-catalog] authScope must decode to ${SOURCE_AUTH_SCOPE_LENGTH} raw bytes, got ${bytes.byteLength}`,\n\t\t);\n\t}\n\treturn bytes;\n}\n\n/** Decode a catalog key in the only accepted representation: exactly 32 raw\n * ed25519 bytes encoded as canonical, unpadded base64url. */\nexport function decodeEd25519PublicKey(publicKey: string): Uint8Array {\n\tconst bytes = decodeBase64Url(publicKey);\n\tif (bytes.byteLength !== RAW_ED25519_KEY_LENGTH) {\n\t\tthrow new Error(\n\t\t\t`[multicast-auth-catalog] public key must decode to ${RAW_ED25519_KEY_LENGTH} raw bytes, got ${bytes.byteLength}`,\n\t\t);\n\t}\n\treturn bytes;\n}\n\n/**\n * One protected media track's manifest + scope binding.\n *\n * - `mediaTrack`: the actual media track name (e.g. `\"video/base\"`).\n * - `manifestTrack`: the sibling track carrying this track's signed\n * manifest objects (see ./source-auth.ts `SourceAuthObjectEntry`/\n * `SourceAuthGroupClose`). Opaque string \u2014 not role-parsed.\n * - `authScope`: this track's unique 32-byte scope, raw bytes as unpadded\n * base64url. BLO-16481 requires a scope fresh per (publisher session,\n * track, source-symbol format) \u2014 a track publishing under two source-\n * symbol formats in the same session MUST appear as two entries here,\n * each with its own scope.\n * - `sourceSymbolFormat`: names the deployed source-symbol profile this\n * track's authenticated bytes are derived from (e.g.\n * `\"full-mmtp-packet\"` or `\"fec-padded-recovery\"`, the two formats\n * BLO-16481's S0 fixture covers).\n */\nexport interface MulticastAuthTrackConfig {\n\tmediaTrack: string;\n\tmanifestTrack: string;\n\tauthScope: string;\n\tsourceSymbolFormat: string;\n}\n\n/**\n * `multicast.auth` v2 \u2014 supersedes the BLO-16485 draft's singular\n * `manifestTrack`/no-`authScope` shape (BLO-16700 decision).\n */\nexport interface MulticastAuthConfig {\n\tscheme: MulticastAuthScheme;\n\thash: MulticastAuthHash;\n\tsig: MulticastAuthSig;\n\t/** Raw 32-byte ed25519 public key, unpadded base64url. */\n\tpublicKey: string;\n\tkeyId: string;\n\t/** Raw 32-byte ed25519 public key, unpadded base64url. Accepted\n\t * alongside `publicKey` during a key-rotation overlap window. */\n\tpreviousKey?: string;\n\tcompaction: MulticastAuthCompaction;\n\t/** Player-config-wins default; catalog value only selects the default\n\t * when the player hasn't pinned one (S3 enforcement precedence). */\n\tenforcement?: MulticastAuthEnforcement;\n\ttracks: MulticastAuthTrackConfig[];\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.length > 0;\n}\n\nfunction isValidAuthScopeField(value: unknown): value is string {\n\tif (!isNonEmptyString(value)) return false;\n\ttry {\n\t\tdecodeAuthScope(value);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction isValidPublicKeyField(value: unknown): value is string {\n\tif (!isNonEmptyString(value)) return false;\n\ttry {\n\t\tdecodeEd25519PublicKey(value);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction hasOnlyKeys(object: Record<string, unknown>, allowed: readonly string[]): boolean {\n\tconst allowedKeys = new Set(allowed);\n\treturn Object.keys(object).every((key) => allowedKeys.has(key));\n}\n\nexport function isMulticastAuthTrackConfig(obj: unknown): obj is MulticastAuthTrackConfig {\n\tif (typeof obj !== \"object\" || obj === null) return false;\n\tconst o = obj as Record<string, unknown>;\n\treturn (\n\t\thasOnlyKeys(o, [\"mediaTrack\", \"manifestTrack\", \"authScope\", \"sourceSymbolFormat\"]) &&\n\t\tisNonEmptyString(o[\"mediaTrack\"]) &&\n\t\tisNonEmptyString(o[\"manifestTrack\"]) &&\n\t\to[\"mediaTrack\"] !== o[\"manifestTrack\"] &&\n\t\tisValidAuthScopeField(o[\"authScope\"]) &&\n\t\tisNonEmptyString(o[\"sourceSymbolFormat\"])\n\t);\n}\n\nconst VALID_COMPACTION = new Set<string>([\"merkle\", \"none\"]);\nconst VALID_ENFORCEMENT = new Set<string>([\"shadow\", \"enforce\"]);\n\n/** Semantic uniqueness rule shared by runtime parsing and the published\n * catalog schema's `uniqueMulticastAuthTrackBindings` keyword. */\nexport function hasUniqueMulticastAuthTrackBindings(tracks: readonly unknown[]): boolean {\n\tconst bindings = tracks.flatMap((track) => {\n\t\tif (typeof track !== \"object\" || track === null) return [];\n\t\tconst value = track as Record<string, unknown>;\n\t\tif (typeof value[\"mediaTrack\"] !== \"string\" || typeof value[\"sourceSymbolFormat\"] !== \"string\") {\n\t\t\treturn [];\n\t\t}\n\t\treturn [JSON.stringify([value[\"mediaTrack\"], value[\"sourceSymbolFormat\"]])];\n\t});\n\treturn new Set(bindings).size === bindings.length;\n}\n\nexport function isMulticastAuthConfig(obj: unknown): obj is MulticastAuthConfig {\n\tif (typeof obj !== \"object\" || obj === null) return false;\n\tconst o = obj as Record<string, unknown>;\n\n\tif (o[\"scheme\"] !== \"bc-provenance\") return false;\n\tif (o[\"hash\"] !== \"blake3\") return false;\n\tif (o[\"sig\"] !== \"ed25519\") return false;\n\tif (!hasOnlyKeys(o, [\"scheme\", \"hash\", \"sig\", \"publicKey\", \"keyId\", \"previousKey\", \"compaction\", \"enforcement\", \"tracks\"])) return false;\n\tif (!isValidPublicKeyField(o[\"publicKey\"])) return false;\n\tif (!isNonEmptyString(o[\"keyId\"])) return false;\n\tif (o[\"previousKey\"] !== undefined && !isValidPublicKeyField(o[\"previousKey\"])) return false;\n\tif (o[\"previousKey\"] === o[\"publicKey\"]) return false;\n\tif (typeof o[\"compaction\"] !== \"string\" || !VALID_COMPACTION.has(o[\"compaction\"])) return false;\n\tif (o[\"enforcement\"] !== undefined) {\n\t\tif (typeof o[\"enforcement\"] !== \"string\" || !VALID_ENFORCEMENT.has(o[\"enforcement\"])) return false;\n\t}\n\n\tif (!Array.isArray(o[\"tracks\"]) || o[\"tracks\"].length === 0) return false;\n\tconst tracks = o[\"tracks\"] as unknown[];\n\tif (!tracks.every((t) => isMulticastAuthTrackConfig(t))) return false;\n\tconst typedTracks = tracks as MulticastAuthTrackConfig[];\n\n\t// BLO-16481: a fresh scope per track \u2014 catalog-declared scopes must be\n\t// pairwise distinct within one auth block.\n\tconst scopes = typedTracks.map((t) => t.authScope);\n\tif (new Set(scopes).size !== scopes.length) return false;\n\tif (!hasUniqueMulticastAuthTrackBindings(typedTracks)) return false;\n\n\t// Each entry must point at its own manifest track.\n\tconst manifestTracks = typedTracks.map((t) => t.manifestTrack);\n\tif (new Set(manifestTracks).size !== manifestTracks.length) return false;\n\n\treturn true;\n}\n\nexport interface ResolvedMulticastAuthConfig {\n\tkeyId: string;\n\t/** Current key first, followed by the overlap key when advertised. */\n\tacceptedPublicKeys: Uint8Array[];\n\tmode: MulticastAuthMode;\n\tcompaction: MulticastAuthCompaction;\n\ttracks: Array<Omit<MulticastAuthTrackConfig, \"authScope\"> & { authScope: Uint8Array }>;\n}\n\n/** Player configuration is authoritative, including an explicit `off`.\n * Catalog enforcement is only a default; an auth block without it defaults\n * to shadow, while a catalog without auth defaults to off. */\nexport function resolveMulticastAuthMode(\n\tplayerMode: MulticastAuthMode | undefined,\n\tauth: MulticastAuthConfig | undefined,\n): MulticastAuthMode {\n\tif (playerMode !== undefined) return playerMode;\n\tif (auth === undefined) return \"off\";\n\treturn auth.enforcement ?? \"shadow\";\n}\n\n/** Parse and resolve the catalog auth block into verifier-ready raw keys and\n * scopes. Invalid blocks and dangling media/manifest track references fail\n * closed instead of silently falling back to unauthenticated playback. */\nexport function resolveMulticastAuthCatalog(\n\tcatalog: unknown,\n\tplayerMode?: MulticastAuthMode,\n): ResolvedMulticastAuthConfig | undefined {\n\tif (typeof catalog !== \"object\" || catalog === null || Array.isArray(catalog)) {\n\t\tthrow new Error(\"[multicast-auth-catalog] catalog must be an object\");\n\t}\n\tconst root = catalog as Record<string, unknown>;\n\tconst rawAuth = root[\"multicast.auth\"];\n\tif (rawAuth === undefined) {\n\t\tif (playerMode === \"enforce\") {\n\t\t\tthrow new Error(\"[multicast-auth-catalog] player enforce mode requires multicast.auth\");\n\t\t}\n\t\treturn undefined;\n\t}\n\tif (!isMulticastAuthConfig(rawAuth)) {\n\t\tthrow new Error(\"[multicast-auth-catalog] invalid multicast.auth v2 block\");\n\t}\n\n\tconst rawTracks = root[\"tracks\"];\n\tif (!Array.isArray(rawTracks)) {\n\t\tthrow new Error(\"[multicast-auth-catalog] catalog tracks must be an array\");\n\t}\n\tconst catalogTrackNames = new Set(\n\t\trawTracks.flatMap((track) =>\n\t\t\ttypeof track === \"object\" && track !== null &&\n\t\t\ttypeof (track as Record<string, unknown>)[\"name\"] === \"string\"\n\t\t\t\t? [(track as Record<string, unknown>)[\"name\"] as string]\n\t\t\t\t: []\n\t\t),\n\t);\n\tfor (const track of rawAuth.tracks) {\n\t\tif (!catalogTrackNames.has(track.mediaTrack)) {\n\t\t\tthrow new Error(`[multicast-auth-catalog] unknown mediaTrack \"${track.mediaTrack}\"`);\n\t\t}\n\t\tif (!catalogTrackNames.has(track.manifestTrack)) {\n\t\t\tthrow new Error(`[multicast-auth-catalog] unknown manifestTrack \"${track.manifestTrack}\"`);\n\t\t}\n\t}\n\n\treturn {\n\t\tkeyId: rawAuth.keyId,\n\t\tacceptedPublicKeys: [\n\t\t\tdecodeEd25519PublicKey(rawAuth.publicKey),\n\t\t\t...(rawAuth.previousKey === undefined ? [] : [decodeEd25519PublicKey(rawAuth.previousKey)]),\n\t\t],\n\t\tmode: resolveMulticastAuthMode(playerMode, rawAuth),\n\t\tcompaction: rawAuth.compaction,\n\t\ttracks: rawAuth.tracks.map((track) => ({\n\t\t\t...track,\n\t\t\tauthScope: decodeAuthScope(track.authScope),\n\t\t})),\n\t};\n}\n", "/**\n * CARP Catalog Types \u2014 FEC and Multicast catalog extensions.\n *\n * Per draft-law-ramadan-moq-carp-reliability \u00A73 (FEC) and \u00A74 (Multicast).\n * Plain TypeScript interfaces + type guards \u2014 no Zod dependency.\n *\n * These are the canonical type definitions. Upstream Zod schemas\n * should derive from these via z.infer<> to avoid duplication.\n */\n\nimport { resolveMulticastAuthCatalog, type MulticastAuthConfig } from \"./multicast-auth-catalog.js\";\n\n// \u2500\u2500 Track Role (Phase 14, D-02..D-05) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Track role derived from the last slash-segment of the track name.\n *\n * Convention: `{content}/base`, `{content}/delta`, `{content}/repair`.\n * Single-track (no slash) legacy streams use `\"single\"`.\n *\n * D-01: No `trackRole` / `role` / `kind` field in the catalog.\n * D-02: Role is expressed via track name suffix only.\n * D-03: Unknown suffixes throw at parse time (error on bad init).\n * D-04: Legacy single-track streams (no slash suffix) return `\"single\"`.\n * D-05: Single role per track \u2014 no multi-role arrays.\n */\nexport type TrackRole = \"base\" | \"delta\" | \"repair\" | \"single\";\n\nconst VALID_ROLE_SUFFIXES = new Set<string>([\"base\", \"delta\", \"repair\"]);\n\n/**\n * Derive the role of a track from its name.\n *\n * - Names with no `/` \u2192 `\"single\"` (legacy single-track streams, D-04).\n * - Names ending with `/base`, `/delta`, or `/repair` \u2192 that role (D-02).\n * - Empty name \u2192 throws (error on bad init).\n * - Trailing slash (empty last segment) \u2192 throws.\n * - Non-ASCII or control characters anywhere in the name \u2192 throws (T-14-01 fuzz hardening).\n * - Unknown last segment \u2192 throws.\n *\n * @throws {Error} On empty name, non-ASCII/control chars, empty suffix, or unknown suffix.\n */\nexport function parseTrackRole(trackName: string): TrackRole {\n\tif (trackName === \"\") {\n\t\tthrow new Error(\"[carp-catalog] empty track name\");\n\t}\n\n\t// T-14-01 fuzz hardening: reject non-ASCII and control characters.\n\t// This prevents catalog injection attacks where a publisher sends a crafted\n\t// track name that bypasses role checks by embedding unusual code points.\n\tfor (let i = 0; i < trackName.length; i++) {\n\t\tconst cp = trackName.charCodeAt(i);\n\t\t// Reject control characters (0x00-0x1F, 0x7F) and non-ASCII (>0x7E)\n\t\tif (cp <= 0x1f || cp === 0x7f || cp > 0x7e) {\n\t\t\tthrow new Error(\n\t\t\t\t`[carp-catalog] track name contains non-ASCII or control character (code point 0x${cp.toString(16)}) in \"${trackName}\"`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst lastSlash = trackName.lastIndexOf(\"/\");\n\tif (lastSlash === -1) {\n\t\t// No slash \u2014 legacy single-track stream (D-04)\n\t\treturn \"single\";\n\t}\n\n\tconst suffix = trackName.slice(lastSlash + 1);\n\tif (suffix === \"\") {\n\t\tthrow new Error(\n\t\t\t`[carp-catalog] empty role suffix in track name \"${trackName}\"; track names must not end with \"/\"`,\n\t\t);\n\t}\n\n\tif (!VALID_ROLE_SUFFIXES.has(suffix)) {\n\t\tthrow new Error(\n\t\t\t`[carp-catalog] unknown role suffix \"${suffix}\" in track name \"${trackName}\"; expected one of: base, delta, repair`,\n\t\t);\n\t}\n\n\treturn suffix as TrackRole;\n}\n\n/**\n * Non-throwing switching-set detector (BLO-8158).\n *\n * Returns `true` iff at least one track name carries a media role suffix\n * (`base` or `delta`) \u2014 i.e. the set looks like a base/delta/repair switching\n * set. A `/repair` track alone is ordinary FEC topology and is not sufficient\n * evidence of a switching set. Unlike `parseTrackRole`, this NEVER throws:\n * names without a `/`, and names with an unrecognised suffix (e.g. an ABR\n * resolution ladder like `video/1080p`, `video/720p`, `video/8k`), simply do\n * not count as a role.\n *\n * Use this for DETECTION (\"is this a switching set?\"). Once a switching set is\n * confirmed, `parseTrackRole` / `validateSwitchingSet` still strictly gate the\n * actual wiring. ABR ladders yield `false` here and fall through to the\n * ABR/single path instead of throwing.\n */\nexport function hasSwitchingSetRole(names: string[]): boolean {\n\treturn names.some((name) => {\n\t\tconst lastSlash = name.lastIndexOf(\"/\");\n\t\tif (lastSlash === -1) return false;\n\t\tconst suffix = name.slice(lastSlash + 1);\n\t\treturn suffix === \"base\" || suffix === \"delta\";\n\t});\n}\n\n/**\n * Validate that a set of track names forms a complete switching set.\n *\n * - Empty or single-track sets (all parsing to `\"single\"`) \u2192 `{ ok: true }`.\n * - Multi-track sets (any name has a role suffix) MUST include all three\n * roles (`base`, `delta`, `repair`). Missing roles are listed.\n *\n * Propagates throws from `parseTrackRole` (non-ASCII, unknown suffix, etc.).\n *\n * D-04: Legacy single-track streams pass without enforcement.\n * D-04: Once any suffix appears, the set is multi-track and must be complete.\n */\nexport function validateSwitchingSet(\n\ttrackNames: string[],\n): { ok: true } | { ok: false; missing: TrackRole[] } {\n\tif (trackNames.length === 0) return { ok: true };\n\n\tconst roles = trackNames.map(parseTrackRole);\n\n\t// If every role is \"single\", this is a legacy single-track stream \u2014 pass.\n\tif (roles.every((r) => r === \"single\")) {\n\t\treturn { ok: true };\n\t}\n\n\t// Multi-track: at least one name has a role suffix.\n\t// The set MUST contain all three required roles.\n\t// Explicit Set<TrackRole> so the TrackRole-typed `required.filter`\n\t// callback can call .has(r) without a narrow-mismatch complaint.\n\tconst presentRoles: Set<TrackRole> = new Set(roles.filter((r) => r !== \"single\"));\n\tconst required: TrackRole[] = [\"base\", \"delta\", \"repair\"];\n\tconst missing = required.filter((r) => !presentRoles.has(r));\n\n\tif (missing.length > 0) {\n\t\treturn { ok: false, missing };\n\t}\n\treturn { ok: true };\n}\n\n// \u2500\u2500 FEC Catalog Extension (CARP \u00A73.2) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type FecAlgorithm = \"none\" | \"raptorq\" | \"reed-solomon\";\n\nexport interface FecCatalogConfig {\n\t/** FEC algorithm identifier (REQUIRED per \u00A74.1, values per \u00A73.1). */\n\talgorithm: FecAlgorithm;\n\t/** K \u2014 source symbols per block (REQUIRED). */\n\tsourceSymbols: number;\n\t/** P \u2014 repair symbols per block (REQUIRED). */\n\trepairSymbols: number;\n\t/** T \u2014 bytes per symbol, 8-byte aligned (REQUIRED). */\n\tsymbolSize: number;\n\t/** FEC block span in MILLISECONDS (OPTIONAL, default 0 = single-group blocks).\n\t * D is the positive round-half-up value of interleaveDepthMs / GOP_duration_ms.\n\t * BLO-14526: renamed from the legacy `interleaveDepth` count-era key \u2014 no fallback read. */\n\tinterleaveDepthMs?: number;\n\t/** Declared jitter/reorder allowance in MILLISECONDS.\n\t * Added to interleaveDepthMs to form a block's deadline; never multiplied\n\t * by it. Jitter is a property of the network path and the block span is a\n\t * property of the encoder, so a multiplicative \"safety factor\" couples two\n\t * independent quantities and grants different slack per track for the same\n\t * network. Consumed identically by FECManager, FEC workers and player\n\t * policies so one signaled value governs end to end. */\n\treorderToleranceMs?: number;\n\t/** Track name for repair symbols (REQUIRED per \u00A76.1). */\n\trepairTrack: string;\n\t/** FEC block mode: \"interleaved\" (default) or \"object\" (per-frame). */\n\t// extensions feature \u2014 see moqcast-draft docs/fec-extensions-material.md, not in public -00\n\tmode?: \"interleaved\" | \"object\";\n\t/** UEP (Unequal Error Protection) \u2014 extensions feature, see moqcast-draft docs/fec-extensions-material.md, not in public -00. When present, repair count\n\t * varies per frame type. repairSymbols becomes the base (P-frame) count.\n\t * MUST be omitted on multi-track base/delta streams (D-08). */\n\tuep?: {\n\t\t/** Keyframe repair ratio: P = ceil(K * keyRatio). Default 0.5. */\n\t\tkeyRatio: number;\n\t\t/** Delta frame repair ratio: P = ceil(K * deltaRatio). Default 0.25. */\n\t\tdeltaRatio: number;\n\t};\n\t/**\n\t * Base-only fallback window in FEC blocks (D-11, Phase 14).\n\t *\n\t * When the delta track's FEC block failure rate exceeds the derived threshold\n\t * over this many consecutive blocks, MediaRouter falls back to base-only mode.\n\t * Derivation: framerate * fallback_window_seconds. If absent, construction\n\t * of the multi-track subscriber MUST throw (error on bad init).\n\t *\n\t * Present only on the base track's fec config (not the delta or repair track).\n\t */\n\tdeltaFailWindowBlocks?: number;\n\t/**\n\t * Delta re-subscribe probe interval in milliseconds (D-13, Phase 14).\n\t *\n\t * After a base-only fallback, wait this long before re-subscribing to the\n\t * delta track to check if conditions have improved.\n\t * Derivation: computeFecDeliveryWindowMs(...) \u2014 the single FEC recovery-window\n\t * source of truth (draft-ramadan-moq-fec \u00A79). Never a fixed interleave multiple.\n\t *\n\t * Present only on the base track's fec config (not the delta or repair track).\n\t */\n\tdeltaProbeIntervalMs?: number;\n\t/**\n\t * Jitter + one-way-delay + reorder budget in MILLISECONDS (draft \u00A79).\n\t *\n\t * The single catalog source for the ADDITIVE margin that the FEC\n\t * recovery/loss window adds on top of max(interleave span, source+repair horizon,\n\t * block serialization) \u2014 see computeFecDeliveryWindowMs. It is a margin, not\n\t * a multiplier. OPTIONAL: when absent, the derivation falls back to the\n\t * un-rounded interleave window as the reorder-budget bound (margin-policy).\n\t */\n\tjitterBufferMs?: number;\n}\n\nexport function isFecCatalogConfig(obj: unknown): obj is FecCatalogConfig {\n\tif (typeof obj !== \"object\" || obj === null) return false;\n\tconst o = obj as Record<string, unknown>;\n\tconst algorithm = o[\"algorithm\"];\n\tconst symbolSize = o[\"symbolSize\"];\n\treturn (\n\t\ttypeof algorithm === \"string\" &&\n\t\t(algorithm === \"none\" || algorithm === \"raptorq\" || algorithm === \"reed-solomon\") &&\n\t\ttypeof o[\"sourceSymbols\"] === \"number\" && o[\"sourceSymbols\"] >= 1 &&\n\t\ttypeof o[\"repairSymbols\"] === \"number\" && o[\"repairSymbols\"] >= 1 &&\n\t\ttypeof symbolSize === \"number\" && symbolSize >= 1 &&\n\t\t(algorithm !== \"raptorq\" || symbolSize % 8 === 0) &&\n\t\ttypeof o[\"repairTrack\"] === \"string\" && (o[\"repairTrack\"] as string).length > 0\n\t);\n}\n\n// \u2500\u2500 Multicast Catalog Extension (CARP \u00A74.1-4.4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type MulticastProtocol = \"ssm\" | \"asm\" | \"amt\" | \"atsc3\";\n\n/**\n * Per-track endpoint membership, per draft-ramadan-moq-multicast-00 \u00A74.1.\n *\n * `packetId` is the MMTP packet_id used for packet-level demux on the\n * multicast wire. New emitters MUST use this object form; the legacy\n * `string` form is accepted by parsers for one release for backward\n * compatibility (BLO-3323 migration).\n */\nexport interface MulticastTrackObject {\n\tname: string;\n\tpacketId: number;\n}\n\n/** Track entry in a multicast endpoint \u2014 accepts both legacy and v2 shape. */\nexport type MulticastTrack = string | MulticastTrackObject;\n\nexport interface MulticastEndpoint {\n\t/** Transport protocol. Defaults to SSM when sourceAddress is present. */\n\tprotocol?: MulticastProtocol;\n\t/** SSM source IP address (REQUIRED for SSM). */\n\tsourceAddress?: string;\n\t/** Multicast group address (REQUIRED). */\n\tgroupAddress: string;\n\t/** UDP port number (REQUIRED). */\n\tport: number;\n\t/**\n\t * Tracks available on this endpoint (REQUIRED).\n\t *\n\t * Accepts both legacy `string` (track name only) and v2 object form\n\t * (`{ name, packetId }`) for backward compatibility. New emitters\n\t * MUST use the object form (BLO-3323 / draft \u00A74.1). Consumers can\n\t * type-narrow with `typeof t === \"string\"` to handle both.\n\t */\n\ttracks: MulticastTrack[];\n\t/** AMT relay hostname (REQUIRED for AMT). */\n\trelayAddress?: string;\n\t/**\n\t * Aggregate bandwidth of this endpoint in bits per second.\n\t * RECOMMENDED per draft \u00A74.1 \u2014 enables capacity-aware joins.\n\t */\n\tbandwidth?: number;\n}\n\nexport type AmtDiscovery = \"driad\" | \"manual\";\n\nexport interface MulticastCatalogConfig {\n\t/** Enable/disable multicast (OPTIONAL, default true). */\n\tenabled?: boolean;\n\t/** Multicast endpoints (REQUIRED). */\n\tendpoints: MulticastEndpoint[];\n\t/** AMT fallback configuration (OPTIONAL). */\n\tamtFallback?: {\n\t\tdiscovery: AmtDiscovery;\n\t\trelayDns?: string;\n\t};\n\t/**\n\t * Monotonic catalog version. Publishers MUST bump on any\n\t * `endpoints[]` mutation (BLO-3323 catalog freshness model).\n\t */\n\tversion?: number;\n\t/**\n\t * Unix-ms timestamp after which subscribers SHOULD refetch the\n\t * catalog. Refetch-on-multicast-receive-timeout short-circuits this.\n\t */\n\tvalidUntil?: number;\n}\n\nexport function isMulticastTrackObject(obj: unknown): obj is MulticastTrackObject {\n\tif (typeof obj !== \"object\" || obj === null) return false;\n\tconst o = obj as Record<string, unknown>;\n\treturn typeof o[\"name\"] === \"string\" && typeof o[\"packetId\"] === \"number\";\n}\n\n/**\n * Wire-shape predicate: returns `true` when `obj` matches the\n * MulticastEndpoint JSON shape strictly enough to be safely cast.\n *\n * Intentionally less strict than `multicastFromConfig`'s\n * `validateEndpoint` (in `multicast-input.ts`):\n *\n * - `tracks: []` is accepted here (Array.isArray check only) but\n * rejected by `validateEndpoint` as `empty_tracks`.\n * - SSM-specific group-range and source-required checks are not\n * enforced here.\n * - Bandwidth/AmtFallback/version are not type-checked.\n *\n * That asymmetry is deliberate: this predicate guards JSON parsed off\n * the wire (already-published catalogs that downstream may have\n * trimmed), while `validateEndpoint` guards publisher input *before*\n * a catalog is composed. Subscribers are tolerant; publishers are\n * strict \u2014 the catalog format never re-validates upstream invariants.\n */\nexport function isMulticastEndpoint(obj: unknown): obj is MulticastEndpoint {\n\tif (typeof obj !== \"object\" || obj === null) return false;\n\tconst o = obj as Record<string, unknown>;\n\tconst protocol = o[\"protocol\"] ??\n\t\t(typeof o[\"sourceAddress\"] === \"string\" && o[\"sourceAddress\"].length > 0 ? \"ssm\" : undefined);\n\treturn (\n\t\ttypeof protocol === \"string\" &&\n\t\t(protocol === \"ssm\" || protocol === \"asm\" || protocol === \"amt\" || protocol === \"atsc3\") &&\n\t\ttypeof o[\"groupAddress\"] === \"string\" && (o[\"groupAddress\"] as string).length > 0 &&\n\t\ttypeof o[\"port\"] === \"number\" && (o[\"port\"] as number) > 0 && (o[\"port\"] as number) <= 65535 &&\n\t\tArray.isArray(o[\"tracks\"]) &&\n\t\t(o[\"tracks\"] as unknown[]).every((t: unknown) => typeof t === \"string\" || isMulticastTrackObject(t))\n\t);\n}\n\nexport function isMulticastCatalogConfig(obj: unknown): obj is MulticastCatalogConfig {\n\tif (typeof obj !== \"object\" || obj === null) return false;\n\tconst o = obj as Record<string, unknown>;\n\treturn (\n\t\tArray.isArray(o[\"endpoints\"]) &&\n\t\t(o[\"endpoints\"] as unknown[]).every((ep: unknown) => isMulticastEndpoint(ep))\n\t);\n}\n\n// \u2500\u2500 Track Timing (mmt-00 \u00A74.4.4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Per-track group-duration signaling.\n *\n * The catalog publishes either `groupDurationMs` (integer ms) or the exact\n * `groupDurationTicks` value used by `groupIdForTicks` in align.ts. The tick\n * form is required for cases where milliseconds cannot represent the cadence\n * exactly:\n *\n * - Per-frame group durations at non-integer-ms cadences\n * (1/30 s = 33.333\u2026 ms; 1/60 s = 16.666\u2026 ms).\n * - Audio sample-rate timescales not divisible by 1000 Hz\n * (e.g. 44 100 Hz \u00D7 333 ms = 14 685.3 ticks).\n *\n * If both fields are present, `groupDurationTicks` wins (matches the\n * spec, mmt-00 \u00A74.4.4).\n *\n * @see draft-ramadan-moq-mmt-00 \u00A74.4.4\n * @see ./align.ts groupIdForTicks\n */\nexport interface TrackTimingConfig {\n\t/** Group duration in milliseconds (positive integer). Required unless an\n\t * exact groupDurationTicks value is supplied. */\n\tgroupDurationMs?: number;\n\t/** Integer-tick override (OPTIONAL, positive integer). Wins over the\n\t * ms field when both are present. Required when\n\t * `(groupDurationMs * timescale) % 1000 != 0`. */\n\tgroupDurationTicks?: number;\n}\n\nexport function isTrackTimingConfig(obj: unknown): obj is TrackTimingConfig {\n\tif (typeof obj !== \"object\" || obj === null) return false;\n\tconst o = obj as Record<string, unknown>;\n\tconst ms = o[\"groupDurationMs\"];\n\tconst ticks = o[\"groupDurationTicks\"];\n\tif (ms === undefined && ticks === undefined) return false;\n\tif (ms !== undefined && (typeof ms !== \"number\" || !Number.isInteger(ms) || ms <= 0)) return false;\n\tif (\"groupDurationTicks\" in o) {\n\t\tif (ticks === undefined) return ms !== undefined;\n\t\tif (typeof ticks !== \"number\" || !Number.isInteger(ticks) || ticks <= 0) return false;\n\t}\n\treturn true;\n}\n\n/** Resolve catalog group timing to an operational wall-clock duration.\n *\n * `groupDurationTicks` wins when both wire fields are present, matching\n * mmt-00 \u00A74.4.4. The result may be fractional because exact frame cadences\n * such as 33_333 ticks at 1 MHz cannot be represented by the wire catalog's\n * integer `groupDurationMs` field.\n */\nexport function resolveGroupDurationMs(\n\ttiming: TrackTimingConfig,\n\ttimescale: number,\n): number {\n\tif (!Number.isSafeInteger(timescale) || timescale <= 0) {\n\t\tthrow new Error(\n\t\t\t`[carp-catalog] resolveGroupDurationMs: timescale must be a positive safe integer Hz, got ${timescale}`,\n\t\t);\n\t}\n\tif (!isTrackTimingConfig(timing)) {\n\t\tthrow new Error(\n\t\t\t`[carp-catalog] resolveGroupDurationMs: invalid TrackTimingConfig: ${JSON.stringify(timing)}`,\n\t\t);\n\t}\n\tif (timing.groupDurationTicks === undefined) {\n\t\treturn timing.groupDurationMs!;\n\t}\n\n\tconst durationMs = (timing.groupDurationTicks / timescale) * 1000;\n\tif (!Number.isFinite(durationMs) || durationMs <= 0 || durationMs > Number.MAX_SAFE_INTEGER) {\n\t\tthrow new Error(\n\t\t\t`[carp-catalog] resolveGroupDurationMs: groupDurationTicks=${timing.groupDurationTicks} ` +\n\t\t\t\t`at timescale=${timescale} cannot be represented as a positive safe millisecond duration`,\n\t\t);\n\t}\n\treturn durationMs;\n}\n\nexport type CmsfCatalog = {\n\tversion: number;\n\ttracks: Record<string, unknown>[];\n\tcommonTrackFields?: Record<string, unknown>;\n\tmulticast?: Record<string, unknown>;\n\t\"multicast.auth\"?: MulticastAuthConfig;\n\t[key: string]: unknown;\n};\n\nexport type CmsfCatalogErrorCode =\n\t| \"catalog_object\"\n\t| \"catalog_version\"\n\t| \"catalog_tracks\"\n\t| \"track_object\"\n\t| \"track_name\"\n\t| \"track_packaging\"\n\t| \"track_is_live\"\n\t| \"track_codec\"\n\t| \"track_mmtp_mode\"\n\t| \"track_timescale\"\n\t| \"track_group_duration_ms\"\n\t| \"track_group_duration_ticks\"\n\t| \"track_group_duration_exact\"\n\t| \"track_keyframe_interval\"\n\t| \"track_fec\"\n\t| \"track_repair_track\"\n\t| \"track_switching_set\"\n\t| \"multicast_auth\"\n\t| \"multicast_track\"\n\t| \"multicast_packet_id\";\n\nexport class CmsfCatalogValidationError extends Error {\n\tconstructor(\n\t\tpublic readonly code: CmsfCatalogErrorCode,\n\t\tpublic readonly path: string,\n\t\tmessage: string,\n\t) {\n\t\tsuper(`[cmsf:${code}] ${path}: ${message}`);\n\t\tthis.name = \"CmsfCatalogValidationError\";\n\t}\n}\n\nfunction catalogError(code: CmsfCatalogErrorCode, path: string, message: string): never {\n\tthrow new CmsfCatalogValidationError(code, path, message);\n}\n\n/** Validate the common CMSF shape and the MMTP required-field profile. */\nexport function validateCmsfMmtpCatalog(value: unknown): CmsfCatalog {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\tcatalogError(\"catalog_object\", \"$\", \"catalog must be an object\");\n\t}\n\tconst catalog = value as Record<string, unknown>;\n\t// IETF-draft catalogs (cast `ladder_catalog.rs`, moq-server\n\t// `catalog-synthesizer.ts`, consumed by the hang player) carry a string\n\t// version tag such as \"draft-ietf-moq-catalogformat-01\" instead of the CMSF\n\t// `version: 1` integer. Nothing keys behavior off the catalog version, so\n\t// normalize the tag to a number rather than rejecting the whole catalog \u2014\n\t// mirrors the relay (dual-stack-relay `bridge/catalog.rs`\n\t// `deserialize_optional_u32_lenient`, #825) and moqtail-ts\n\t// `normalizeCatalogVersion`.\n\tconst rawVersion = catalog[\"version\"];\n\tconst normalizedVersion =\n\t\ttypeof rawVersion === \"string\"\n\t\t\t? Number.isFinite(Number(rawVersion))\n\t\t\t\t? Number(rawVersion)\n\t\t\t\t: rawVersion.startsWith(\"draft-ietf-moq-catalogformat\")\n\t\t\t\t\t? 1\n\t\t\t\t\t: NaN\n\t\t\t: rawVersion;\n\tif (!Number.isInteger(normalizedVersion) || (normalizedVersion as number) <= 0) {\n\t\tcatalogError(\"catalog_version\", \"$.version\", \"version must be a positive integer or a recognized format tag\");\n\t}\n\tcatalog[\"version\"] = normalizedVersion;\n\tif (!Array.isArray(catalog[\"tracks\"])) {\n\t\tcatalogError(\"catalog_tracks\", \"$.tracks\", \"tracks must be an array\");\n\t}\n\n\tconst common = typeof catalog[\"commonTrackFields\"] === \"object\" &&\n\t\tcatalog[\"commonTrackFields\"] !== null && !Array.isArray(catalog[\"commonTrackFields\"])\n\t\t? catalog[\"commonTrackFields\"] as Record<string, unknown>\n\t\t: {};\n\tconst tracks = catalog[\"tracks\"] as unknown[];\n\tconst trackRecords: Record<string, unknown>[] = [];\n\tconst effective = (track: Record<string, unknown>, field: string): unknown => track[field] ?? common[field];\n\tconst positiveInteger = (input: unknown): input is number => Number.isSafeInteger(input) && (input as number) > 0;\n\tconst positiveNumber = (input: unknown): input is number =>\n\t\ttypeof input === \"number\" && Number.isFinite(input) && input > 0;\n\n\tfor (let index = 0; index < tracks.length; index++) {\n\t\tconst raw = tracks[index];\n\t\tconst path = `$.tracks[${index}]`;\n\t\tif (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n\t\t\tcatalogError(\"track_object\", path, \"track must be an object\");\n\t\t}\n\t\tconst track = raw as Record<string, unknown>;\n\t\tconst name = track[\"name\"];\n\t\tif (typeof name !== \"string\" || name.length === 0) {\n\t\t\tcatalogError(\"track_name\", `${path}.name`, \"name must be a non-empty string\");\n\t\t}\n\t\ttrackRecords.push(track);\n\n\t\tconst packaging = effective(track, \"packaging\");\n\t\tif (typeof packaging !== \"string\" || packaging.length === 0) {\n\t\t\tcatalogError(\"track_packaging\", `${path}.packaging`, \"packaging must be a non-empty string\");\n\t\t}\n\t\tconst trackHasIsLive = Object.prototype.hasOwnProperty.call(track, \"isLive\");\n\t\tconst hasIsLive = trackHasIsLive || Object.prototype.hasOwnProperty.call(common, \"isLive\");\n\t\tconst isLive = trackHasIsLive ? track[\"isLive\"] : common[\"isLive\"];\n\t\tif (hasIsLive && typeof isLive !== \"boolean\") {\n\t\t\tcatalogError(\"track_is_live\", `${path}.isLive`, \"isLive must be a boolean\");\n\t\t}\n\t\ttrack[\"isLive\"] = isLive ?? true;\n\t\tconst selectionValue = effective(track, \"selectionParams\");\n\t\tconst selection = typeof selectionValue === \"object\" && selectionValue !== null && !Array.isArray(selectionValue)\n\t\t\t? selectionValue as Record<string, unknown>\n\t\t\t: undefined;\n\t\tconst codec = selection?.[\"codec\"] ?? effective(track, \"codec\");\n\t\tif (packaging !== \"timeline\" && packaging !== \"mediatimeline\" && packaging !== \"eventtimeline\" && packaging !== \"fec-repair\" &&\n\t\t\t(typeof codec !== \"string\" || codec.length === 0)) {\n\t\t\tcatalogError(\"track_codec\", `${path}.codec`, `codec is required for packaging=${packaging}`);\n\t\t}\n\n\t\tconst timescale = effective(track, \"timescale\");\n\t\tconst groupDurationMs = effective(track, \"groupDurationMs\");\n\t\tconst groupDurationTicks = effective(track, \"groupDurationTicks\");\n\t\tconst keyframeIntervalMs = effective(track, \"keyframeIntervalMs\");\n\t\tconst keyframeIntervalTicks = effective(track, \"keyframeIntervalTicks\");\n\t\tif (groupDurationMs !== undefined && !positiveInteger(groupDurationMs)) {\n\t\t\tcatalogError(\"track_group_duration_ms\", `${path}.groupDurationMs`, \"must be a positive integer\");\n\t\t}\n\t\tif (groupDurationTicks !== undefined && !positiveInteger(groupDurationTicks)) {\n\t\t\tcatalogError(\"track_group_duration_ticks\", `${path}.groupDurationTicks`, \"must be a positive integer\");\n\t\t}\n\t\tif ((keyframeIntervalMs !== undefined && !positiveNumber(keyframeIntervalMs)) ||\n\t\t\t(keyframeIntervalTicks !== undefined && !positiveInteger(keyframeIntervalTicks))) {\n\t\t\tcatalogError(\"track_keyframe_interval\", path, \"keyframe interval fields must be positive numbers\");\n\t\t}\n\t\tif (packaging === \"mmtp\") {\n\t\t\tconst mmtpMode = effective(track, \"mmtpMode\");\n\t\t\tif (mmtpMode !== \"mpu\" && mmtpMode !== \"mfu\") {\n\t\t\t\tcatalogError(\"track_mmtp_mode\", `${path}.mmtpMode`, \"must be mpu or mfu\");\n\t\t\t}\n\t\t\tif (!positiveInteger(timescale)) {\n\t\t\t\tcatalogError(\"track_timescale\", `${path}.timescale`, \"must be a positive integer\");\n\t\t\t}\n\t\t\tif (groupDurationMs === undefined && groupDurationTicks === undefined) {\n\t\t\t\tcatalogError(\n\t\t\t\t\t\"track_group_duration_ms\",\n\t\t\t\t\tpath,\n\t\t\t\t\t\"groupDurationMs or groupDurationTicks must be a positive integer\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (groupDurationTicks === undefined &&\n\t\t\t\t(BigInt(groupDurationMs as number) * BigInt(timescale)) % 1000n !== 0n) {\n\t\t\t\tcatalogError(\"track_group_duration_exact\", `${path}.groupDurationMs`, \"does not resolve to an exact integer tick count\");\n\t\t\t}\n\t\t}\n\n\t\tif (track[\"fec\"] !== undefined) {\n\t\t\tconst fec = track[\"fec\"];\n\t\t\tif (typeof fec !== \"object\" || fec === null || Array.isArray(fec)) {\n\t\t\t\tcatalogError(\"track_fec\", `${path}.fec`, \"FEC must be an object\");\n\t\t\t}\n\t\t\tconst config = fec as Record<string, unknown>;\n\t\t\tconst algorithm = config[\"algorithm\"];\n\t\t\tif (algorithm !== \"none\" && algorithm !== \"raptorq\" && algorithm !== \"reed-solomon\") {\n\t\t\t\tcatalogError(\"track_fec\", `${path}.fec.algorithm`, \"algorithm is not supported\");\n\t\t\t}\n\t\t\tif (\"interleaveDepth\" in config || \"interleaveMs\" in config) {\n\t\t\t\tcatalogError(\"track_fec\", `${path}.fec`, \"interleaveDepthMs is the only supported interleave field\");\n\t\t\t}\n\t\t\tif (config[\"interleaveDepthMs\"] !== undefined && !positiveInteger(config[\"interleaveDepthMs\"])) {\n\t\t\t\tcatalogError(\"track_fec\", `${path}.fec.interleaveDepthMs`, \"must be a positive integer\");\n\t\t\t}\n\t\t\tif (algorithm !== \"none\") {\n\t\t\t\tfor (const field of [\"sourceSymbols\", \"repairSymbols\", \"symbolSize\"] as const) {\n\t\t\t\t\tif (!positiveInteger(config[field])) {\n\t\t\t\t\t\tcatalogError(\"track_fec\", `${path}.fec.${field}`, \"must be a positive integer\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (typeof config[\"repairTrack\"] !== \"string\" || config[\"repairTrack\"].length === 0) {\n\t\t\t\t\tcatalogError(\"track_fec\", `${path}.fec.repairTrack`, \"must be a non-empty string\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (let index = 0; index < trackRecords.length; index++) {\n\t\tconst track = trackRecords[index]!;\n\t\tconst fec = track[\"fec\"] as Record<string, unknown> | undefined;\n\t\tif (!fec || fec[\"algorithm\"] === \"none\") continue;\n\t\tconst repairTrack = fec[\"repairTrack\"] as string;\n\t\tconst target = trackRecords.find((candidate) => candidate[\"name\"] === repairTrack);\n\t\tif (!target || effective(target, \"packaging\") !== \"fec-repair\") {\n\t\t\tcatalogError(\"track_repair_track\", `$.tracks[${index}].fec.repairTrack`, `unknown FEC repair track ${JSON.stringify(repairTrack)}`);\n\t\t}\n\t}\n\n\tconst switchingSets = new Map<number, { name: string; ticks: bigint; timescale: bigint }>();\n\tfor (let index = 0; index < trackRecords.length; index++) {\n\t\tconst track = trackRecords[index]!;\n\t\tif (effective(track, \"packaging\") !== \"mmtp\") continue;\n\t\tconst altGroup = effective(track, \"altGroup\");\n\t\tif (!Number.isSafeInteger(altGroup)) continue;\n\t\tconst timescale = BigInt(effective(track, \"timescale\") as number);\n\t\tconst durationTicks = effective(track, \"groupDurationTicks\");\n\t\tconst ticks = durationTicks !== undefined\n\t\t\t? BigInt(durationTicks as number)\n\t\t\t: BigInt(effective(track, \"groupDurationMs\") as number) * timescale / 1000n;\n\t\tconst anchor = switchingSets.get(altGroup as number);\n\t\tif (anchor && ticks * anchor.timescale !== anchor.ticks * timescale) {\n\t\t\tcatalogError(\"track_switching_set\", `$.tracks[${index}]`, `group duration does not match ${JSON.stringify(anchor.name)} in altGroup ${altGroup}`);\n\t\t}\n\t\tif (!anchor) switchingSets.set(altGroup as number, { name: track[\"name\"] as string, ticks, timescale });\n\t}\n\n\tconst multicast = catalog[\"multicast\"];\n\tif (typeof multicast === \"object\" && multicast !== null && !Array.isArray(multicast)) {\n\t\tconst endpoints = (multicast as Record<string, unknown>)[\"endpoints\"];\n\t\tif (Array.isArray(endpoints)) {\n\t\t\tfor (let endpointIndex = 0; endpointIndex < endpoints.length; endpointIndex++) {\n\t\t\t\tconst endpoint = endpoints[endpointIndex];\n\t\t\t\tif (typeof endpoint !== \"object\" || endpoint === null || Array.isArray(endpoint)) continue;\n\t\t\t\tconst refs = (endpoint as Record<string, unknown>)[\"tracks\"];\n\t\t\t\tif (!Array.isArray(refs)) continue;\n\t\t\t\tconst packetIds = new Map<number, string>();\n\t\t\t\tfor (let refIndex = 0; refIndex < refs.length; refIndex++) {\n\t\t\t\t\tconst ref = refs[refIndex];\n\t\t\t\t\tif (typeof ref !== \"object\" || ref === null || Array.isArray(ref)) continue;\n\t\t\t\t\tconst trackRef = ref as Record<string, unknown>;\n\t\t\t\t\tconst refPath = `$.multicast.endpoints[${endpointIndex}].tracks[${refIndex}]`;\n\t\t\t\t\tconst name = trackRef[\"name\"];\n\t\t\t\t\tif (typeof name !== \"string\" || !trackRecords.some((track) => track[\"name\"] === name)) {\n\t\t\t\t\t\tcatalogError(\"multicast_track\", `${refPath}.name`, `unknown catalog track ${JSON.stringify(name)}`);\n\t\t\t\t\t}\n\t\t\t\t\tconst packetId = trackRef[\"packetId\"];\n\t\t\t\t\tif (!Number.isSafeInteger(packetId) || (packetId as number) < 0 || (packetId as number) > 65535) {\n\t\t\t\t\t\tcatalogError(\"multicast_packet_id\", `${refPath}.packetId`, \"packetId must be an integer from 0 to 65535\");\n\t\t\t\t\t}\n\t\t\t\t\tconst previous = packetIds.get(packetId as number);\n\t\t\t\t\tif (previous !== undefined) {\n\t\t\t\t\t\tcatalogError(\"multicast_packet_id\", `${refPath}.packetId`, `packetId is already assigned to ${JSON.stringify(previous)}`);\n\t\t\t\t\t}\n\t\t\t\t\tpacketIds.set(packetId as number, name as string);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\ttry {\n\t\tresolveMulticastAuthCatalog(catalog);\n\t} catch (error) {\n\t\tcatalogError(\n\t\t\t\"multicast_auth\",\n\t\t\t\"$.multicast.auth\",\n\t\t\terror instanceof Error ? error.message : \"invalid multicast.auth v2 block\",\n\t\t);\n\t}\n\n\treturn catalog as CmsfCatalog;\n}\n\n/**\n * Resolve a track's group duration to integer ticks using the supplied\n * timescale (Hz). Implements mmt-00 \u00A74.4.4:\n *\n * - If `groupDurationTicks` is present, return it (override wins).\n * - Else compute `groupDurationMs * timescale / 1000`. The result MUST\n * be an exact integer; throws if `(ms * timescale) % 1000 != 0`.\n *\n * Throws on invalid timing config or non-positive timescale (CLAUDE.md:\n * error on bad init).\n */\nexport function resolveGroupDurationTicks(\n\ttiming: TrackTimingConfig,\n\ttimescale: number,\n): number {\n\tif (!Number.isFinite(timescale) || !Number.isInteger(timescale) || timescale <= 0) {\n\t\tthrow new Error(\n\t\t\t`[carp-catalog] resolveGroupDurationTicks: timescale must be a positive integer Hz, got ${timescale}`,\n\t\t);\n\t}\n\tif (!isTrackTimingConfig(timing)) {\n\t\tthrow new Error(\n\t\t\t`[carp-catalog] resolveGroupDurationTicks: invalid TrackTimingConfig: ${JSON.stringify(timing)}`,\n\t\t);\n\t}\n\tif (timing.groupDurationTicks !== undefined) {\n\t\treturn timing.groupDurationTicks;\n\t}\n\tif (timing.groupDurationMs === undefined) {\n\t\tthrow new Error(\n\t\t\t\"[carp-catalog] resolveGroupDurationTicks: groupDurationMs is required when groupDurationTicks is absent\",\n\t\t);\n\t}\n\tconst product = timing.groupDurationMs * timescale;\n\tif (product % 1000 !== 0) {\n\t\tthrow new Error(\n\t\t\t`[carp-catalog] resolveGroupDurationTicks: groupDurationMs=${timing.groupDurationMs} at timescale=${timescale} ` +\n\t\t\t\t`produces non-integer ticks (${product / 1000}); publisher must use groupDurationTicks override (mmt-00 \u00A74.4.4)`,\n\t\t);\n\t}\n\treturn product / 1000;\n}\n\n/**\n * Validate that every track in a switching set agrees on the same\n * wall-clock group duration (mmt-00 \u00A74.4.4). Per-track timescales may\n * differ, so raw tick counts cannot be compared directly.\n *\n * Returns `{ ok: true }` when all tracks agree (or the set is empty);\n * `{ ok: false, mismatches }` listing each track whose effective ticks\n * differ from the first track's value. Subscribers per spec SHOULD\n * reject the catalog on mismatch.\n *\n * Throws if any track's timing config is invalid (per\n * `resolveGroupDurationTicks`).\n */\nexport function validateSwitchingSetTiming(\n\ttracks: Array<{ name: string; timing: TrackTimingConfig; timescale: number }>,\n):\n\t| { ok: true }\n\t| { ok: false; expectedTicks: number; mismatches: Array<{ name: string; ticks: number }> } {\n\tif (tracks.length === 0) return { ok: true };\n\tconst ticksByTrack = tracks.map((t) => ({\n\t\tname: t.name,\n\t\tticks: resolveGroupDurationTicks(t.timing, t.timescale),\n\t\ttimescale: t.timescale,\n\t}));\n\tconst expectedTicks = ticksByTrack[0].ticks;\n\tconst expectedTimescale = ticksByTrack[0].timescale;\n\tconst mismatches = ticksByTrack\n\t\t.slice(1)\n\t\t.filter(\n\t\t\t(t) =>\n\t\t\t\tBigInt(t.ticks) * BigInt(expectedTimescale) !==\n\t\t\t\tBigInt(expectedTicks) * BigInt(t.timescale),\n\t\t)\n\t\t.map(({ name, ticks }) => ({ name, ticks }));\n\tif (mismatches.length === 0) return { ok: true };\n\treturn { ok: false, expectedTicks, mismatches };\n}\n", "/**\n * RFC 6330 Object Transmission Information (OTI) utilities.\n *\n * Shared OTI encoding/decoding for both moq-lib and moqtail players.\n * Eliminates duplicated OTI byte manipulation across codebases.\n */\n\nimport { parseMoqRepairFrame } from \"@blockcast/mmt-base\";\n\nexport interface OTIParams {\n\t/** Transfer length F (total source block size in bytes) */\n\ttransferLength: number;\n\t/** Symbol size T (bytes per symbol) */\n\tsymbolSize: number;\n\t/** Number of source blocks Z */\n\tsourceBlocks: number;\n\t/** Number of sub-blocks N */\n\tsubBlocks: number;\n\t/** Symbol alignment Al */\n\talignment: number;\n}\n\n/**\n * Build a 12-byte RFC 6330 Common + Scheme-Specific OTI from parameters.\n *\n * Wire format (per RFC 6330 \u00A74.3.1 + \u00A74.3.3):\n * byte 0: F high byte (bit 32 \u2014 transfer length is 40-bit)\n * bytes 1-4: F low 32 bits (big-endian)\n * byte 5: reserved (0)\n * bytes 6-7: T (symbol size, big-endian)\n * byte 8: Z (source blocks)\n * bytes 9-10: N (sub-blocks, big-endian)\n * byte 11: Al (alignment)\n */\nexport function buildOTI(params: OTIParams): Uint8Array {\n\tconst {\n\t\ttransferLength: F,\n\t\tsymbolSize: T,\n\t\tsourceBlocks: Z,\n\t\tsubBlocks: N,\n\t\talignment: Al,\n\t} = params;\n\tvalidateOTIFields(F, T, Z, N, Al);\n\tconst oti = new Uint8Array(12);\n\t// F: 40-bit big-endian (byte 0 = high, bytes 1-4 = low 32)\n\toti[0] = (F / 0x100000000) & 0xFF;\n\toti[1] = (F >>> 24) & 0xFF;\n\toti[2] = (F >>> 16) & 0xFF;\n\toti[3] = (F >>> 8) & 0xFF;\n\toti[4] = F & 0xFF;\n\t// byte 5: reserved\n\toti[6] = (T >>> 8) & 0xFF;\n\toti[7] = T & 0xFF;\n\toti[8] = Z & 0xFF;\n\toti[9] = (N >>> 8) & 0xFF;\n\toti[10] = N & 0xFF;\n\toti[11] = Al & 0xFF;\n\treturn oti;\n}\n\n/**\n * Build OTI from catalog FEC config (K and T).\n * F = K \u00D7 T (interleaved encoder convention from FFmpeg moqenc_mmt.c).\n */\nexport function buildOTIFromCatalog(K: number, T: number): Uint8Array {\n\tif (!Number.isInteger(K) || K <= 0 || K > 56_403) {\n\t\tthrow new Error(`K must be an integer in 1..56403 (got ${K})`);\n\t}\n\treturn buildOTI({\n\t\ttransferLength: K * T,\n\t\tsymbolSize: T,\n\t\tsourceBlocks: 1,\n\t\tsubBlocks: 1,\n\t\talignment: 8,\n\t});\n}\n\n/**\n * Parse a 12-byte OTI into structured parameters.\n */\nexport function parseOTI(oti: Uint8Array): OTIParams & { K: number } {\n\tif (oti.length !== 12) throw new Error(`OTI must be exactly 12 bytes (got ${oti.length})`);\n\tif (oti[5] !== 0) throw new Error(`OTI reserved byte 5 must be zero (got ${oti[5]})`);\n\tconst F = ((oti[0] & 0xFF) * 0x100000000) +\n\t\t(((oti[1] << 24) | (oti[2] << 16) | (oti[3] << 8) | oti[4]) >>> 0);\n\tconst T = (oti[6] << 8) | oti[7];\n\tconst Z = oti[8];\n\tconst N = (oti[9] << 8) | oti[10];\n\tconst Al = oti[11];\n\tvalidateOTIFields(F, T, Z, N, Al);\n\tconst K = Math.ceil(Math.ceil(F / T) / Z);\n\treturn { transferLength: F, symbolSize: T, sourceBlocks: Z, subBlocks: N, alignment: Al, K };\n}\n\nfunction validateOTIFields(F: number, T: number, Z: number, N: number, Al: number): void {\n\tif (!Number.isSafeInteger(F) || F <= 0 || F > 0xffffffffff) {\n\t\tthrow new Error(`F must be a positive 40-bit integer (got ${F})`);\n\t}\n\tif (!Number.isInteger(T) || T <= 0 || T > 0xffff) {\n\t\tthrow new Error(`T must be an integer in 1..65535 (got ${T})`);\n\t}\n\tif (!Number.isInteger(Z) || Z <= 0 || Z > 0xff) {\n\t\tthrow new Error(`Z must be an integer in 1..255 (got ${Z})`);\n\t}\n\tif (!Number.isInteger(N) || N <= 0 || N > 0xffff) {\n\t\tthrow new Error(`N must be an integer in 1..65535 (got ${N})`);\n\t}\n\tif (!Number.isInteger(Al) || Al <= 0 || Al > 0xff || T % Al !== 0) {\n\t\tthrow new Error(`Al must be an integer in 1..255 that divides T (got Al=${Al}, T=${T})`);\n\t}\n\tconst K = Math.ceil(Math.ceil(F / T) / Z);\n\tif (K > 56_403) {\n\t\tthrow new Error(`OTI requires K=${K}, above the RFC 6330 systematic limit 56403`);\n\t}\n}\n\n/**\n * Resolve a catalog FEC block's interleave window in milliseconds.\n *\n * The catalog carries exactly ONE interleave field: `interleaveDepthMs`, the\n * full FEC block span in MILLISECONDS (draft-ramadan-moq-fec \u00A75.1). Receivers\n * derive the block count D with `deriveFecInterleaveDepth`.\n *\n * Absent or non-positive \u2192 undefined; callers treat that as unconfigured and\n * error rather than guess. The legacy `interleaveDepth` frame-count key and\n * the `interleaveMs` alias were removed in the BLO-14526 clean cut \u2014 producers\n * emit milliseconds only, and there is deliberately NO fallback read.\n */\nexport type FecInterleaveCatalog = {\n\tinterleaveDepthMs?: number;\n};\n\nexport function catalogFecInterleaveMs(\n\tfec: FecInterleaveCatalog | undefined,\n): number | undefined {\n\tconst ms = fec?.interleaveDepthMs;\n\treturn typeof ms === \"number\" && ms > 0 ? ms : undefined;\n}\n\n/**\n * Derive the integer FEC interleave depth D from a catalog block span and the\n * duration of one media unit.\n *\n * `interleaveDepthMs` is nearest-millisecond catalog signaling while media\n * unit durations are commonly fractional. Invert that quantization with\n * positive-value round-half-up semantics:\n *\n * D = max(1, floor(interleaveDepthMs / mediaUnitDurationMs + 0.5))\n *\n * `Math.ceil` is not equivalent: 4000 / 33.333 is slightly greater than 120,\n * but represents D=120 rather than D=121.\n */\nexport function deriveFecInterleaveDepth(\n\tinterleaveDepthMs: number,\n\tmediaUnitDurationMs: number,\n): number {\n\tif (!Number.isFinite(interleaveDepthMs) || interleaveDepthMs <= 0) {\n\t\tthrow new Error(`[FEC] interleaveDepthMs must be finite and > 0 (got ${interleaveDepthMs})`);\n\t}\n\tif (!Number.isFinite(mediaUnitDurationMs) || mediaUnitDurationMs <= 0) {\n\t\tthrow new Error(`[FEC] mediaUnitDurationMs must be finite and > 0 (got ${mediaUnitDurationMs})`);\n\t}\n\treturn Math.max(1, Math.floor(interleaveDepthMs / mediaUnitDurationMs + 0.5));\n}\n\n/**\n * Compute the full FEC block completion timeout from the interleave window.\n *\n * The catalog's `interleaveDepthMs` IS the full FEC block span in\n * milliseconds (draft-ramadan-moq-fec \u00A75.1): producers emit\n * D \u00D7 unit-duration, and every symbol of a block \u2014 source and repair \u2014\n * arrives within that span. The full-block timeout is therefore\n * K-INDEPENDENT:\n *\n * timeout = interleaveDepthMs * safetyFactor\n *\n * The retired per-symbol-window model multiplied the interleave value by\n * (K-1); under \u00A75.1 semantics that overshoots ~(K-1)\u00D7 (K=32 @ 133ms \u2192\n * ~12.4s instead of ~0.4s). A caller that genuinely needs a per-sub-block\n * deadline scales the block span by K_sub / K instead \u2014 do NOT reintroduce\n * (K-1) here.\n *\n * @param interleaveDepthMs - Full FEC block span in ms (catalog fec.interleaveDepthMs)\n * @param safetyFactor - Jitter margin (default 3.0)\n * @returns Timeout in milliseconds\n */\nexport function computeFecTimeout(\n\tinterleaveDepthMs: number,\n\tsafetyFactor: number = 3.0,\n): number {\n\tif (interleaveDepthMs <= 0) {\n\t\tthrow new Error(`[FEC] interleaveDepthMs must be > 0 (got ${interleaveDepthMs}ms). Fix encoder config.`);\n\t}\n\t// interleaveDepthMs IS the block span. K=4, D=4 at 30fps:\n\t// interleaveDepthMs = 133ms \u2192 timeout = ceil(133 * 3) = 399ms.\n\treturn Math.ceil(interleaveDepthMs * safetyFactor);\n}\n\n/**\n * Absolute deadline for one FEC block.\n *\n * deadline = firstAcceptedAtMs + interleaveDepthMs + reorderToleranceMs\n *\n * Two properties matter, and both are contract, not preference:\n *\n * 1. The anchor is an ABSOLUTE receiver-local timestamp of the first accepted\n * packet of the block -- not \"now when we noticed\", and not a duration a\n * caller starts counting at an unspecified moment. A relative timeout\n * cannot say WHEN a block was due, so it cannot yield playback latency and\n * it cannot be compared across two consumers that started their timers at\n * different instants.\n *\n * 2. The reorder/jitter allowance is ADDITIVE and SIGNALED, never a multiplier\n * on the span. Jitter is a property of the network path; the FEC block span\n * is a property of the encoder. Multiplying them couples two independent\n * quantities: at a 133ms video span a x3 factor grants 266ms of slack, and\n * at a 43ms audio span only 86ms -- for the same network. The tolerance\n * therefore arrives as its own catalog value and is added once.\n *\n * Both arguments are required. There is no default tolerance: a missing value\n * is an encoder/catalog bug and must surface at the boundary, not be papered\n * over with a constant here.\n *\n * @param firstAcceptedAtMs - Receiver-local ms timestamp of the block's first accepted packet\n * @param interleaveDepthMs - Full FEC block span in ms (catalog fec.interleaveDepthMs)\n * @param reorderToleranceMs - Declared jitter/reorder allowance in ms (catalog fec.reorderToleranceMs)\n * @returns Absolute receiver-local deadline in milliseconds\n */\nexport function fecBlockDeadlineMs(params: {\n\tfirstAcceptedAtMs: number;\n\tinterleaveDepthMs: number;\n\treorderToleranceMs: number;\n}): number {\n\tconst { firstAcceptedAtMs, interleaveDepthMs, reorderToleranceMs } = params;\n\tif (!Number.isFinite(firstAcceptedAtMs)) {\n\t\tthrow new Error(`[FEC] firstAcceptedAtMs must be finite (got ${firstAcceptedAtMs}).`);\n\t}\n\treturn firstAcceptedAtMs + fecBlockBudgetMs(interleaveDepthMs, reorderToleranceMs);\n}\n\n/**\n * Relative budget for one FEC block: span + declared tolerance.\n *\n * Only for consumers whose interface genuinely takes a duration (the WASM\n * reassembler's `timeoutMs`). Anything that can hold a timestamp should use\n * `fecBlockDeadlineMs` instead, so the anchor stays explicit and latency stays\n * extractable. This is deliberately NOT `span * factor` -- see the note on\n * `fecBlockDeadlineMs` for why the tolerance is additive.\n */\nexport function fecBlockBudgetMs(interleaveDepthMs: number, reorderToleranceMs: number): number {\n\t// Finite, not merely > 0: Infinity satisfies `> 0` and would yield an\n\t// infinite budget, which fecBlockDeadlineMs then turns into a deadline no\n\t// block can ever miss -- the eviction bound silently stops bounding. The\n\t// tolerance check below already required finiteness; this is the same bar\n\t// for the encoder's span.\n\tif (!Number.isFinite(interleaveDepthMs) || !(interleaveDepthMs > 0)) {\n\t\tthrow new Error(\n\t\t\t`[FEC] interleaveDepthMs must be a finite value > 0 (got ${interleaveDepthMs}ms). Fix encoder config.`,\n\t\t);\n\t}\n\tif (!(reorderToleranceMs >= 0) || !Number.isFinite(reorderToleranceMs)) {\n\t\tthrow new Error(\n\t\t\t`[FEC] reorderToleranceMs must be a finite value >= 0 (got ${reorderToleranceMs}ms). ` +\n\t\t\t\t`It is a catalog value (fec.reorderToleranceMs), not a local default.`,\n\t\t);\n\t}\n\treturn Math.ceil(interleaveDepthMs + reorderToleranceMs);\n}\n\n/**\n * Playback latency for a block, from the same anchor the deadline uses.\n *\n * latency = presentedAtMs - firstAcceptedAtMs\n *\n * Both timestamps are receiver-local, so this needs NO publisher/receiver\n * clock agreement. That is the point of anchoring the deadline absolutely:\n * publisher-stamped media time and receiver BCTM disagree by roughly the\n * quantity we are trying to measure, which makes any cross-host subtraction\n * unusable at a 33ms target. This subtraction is immune to that skew.\n *\n * It measures first-accepted-packet to presentation. It is NOT glass-to-glass\n * and must not be reported as such -- capture and encode sit outside both\n * timestamps.\n */\nexport function playbackLatencyMs(params: { presentedAtMs: number; firstAcceptedAtMs: number }): number {\n\tconst { presentedAtMs, firstAcceptedAtMs } = params;\n\tif (!Number.isFinite(presentedAtMs) || !Number.isFinite(firstAcceptedAtMs)) {\n\t\tthrow new Error(`[FEC] playback latency needs two finite timestamps (got ${presentedAtMs}, ${firstAcceptedAtMs}).`);\n\t}\n\tif (presentedAtMs < firstAcceptedAtMs) {\n\t\tthrow new Error(\n\t\t\t`[FEC] presentedAtMs ${presentedAtMs} precedes firstAcceptedAtMs ${firstAcceptedAtMs}; ` +\n\t\t\t\t`the two timestamps must come from one receiver-local clock.`,\n\t\t);\n\t}\n\treturn presentedAtMs - firstAcceptedAtMs;\n}\n\n/**\n * Extract FEC parameters from an MMTP repair packet.\n *\n * Per ISO/IEC 23008-1 Section C.5.3, the 13-byte Repair FEC Payload ID\n * follows the complete MMTP header, including optional C/X fields.\n *\n * Returns raw fields \u2014 caller passes directly to WASM add_repair(ss_start, ssb_length, rs_id, data).\n * No SBN/ESI derivation \u2014 the WASM decoder handles block assignment.\n */\nexport function parseRepairPacket(packet: Uint8Array): {\n\tssStart: number; ssbLength: number; rsId: number; repairData: Uint8Array;\n} | null {\n\tconst parsed = parseMoqRepairFrame(packet);\n\tif (!parsed) return null;\n\treturn {\n\t\tssStart: parsed.ssStart,\n\t\tssbLength: parsed.ssbLength,\n\t\trsId: parsed.rsId,\n\t\trepairData: parsed.symbolData,\n\t};\n}\n", "/**\n * MMTP \u2192 CMAF converter per draft-ramadan-moq-mmt \u00A75.3.\n *\n * Converts reassembled MFU frames (raw codec samples from MMTP) into\n * fMP4 segments (moof+mdat) suitable for MSE SourceBuffer.appendBuffer().\n *\n * MPU metadata (fragment_type=0) packets from FFmpeg are complete\n * ftyp+moov init segments and can be used directly as MSE init data.\n *\n * MFU data (fragment_type=2) contains raw AVCC samples that must be\n * wrapped in moof+mdat boxes for MSE consumption.\n *\n * ISO 14496-12 (ISOBMFF) box construction is inline \u2014 no dependencies.\n */\n\n// \u2500\u2500 ISOBMFF box helpers \u2500\u2500\n\nfunction box(type: string, ...children: Uint8Array[]): Uint8Array {\n let size = 8\n for (const c of children) size += c.length\n const buf = new Uint8Array(size)\n new DataView(buf.buffer).setUint32(0, size)\n buf[4] = type.charCodeAt(0)\n buf[5] = type.charCodeAt(1)\n buf[6] = type.charCodeAt(2)\n buf[7] = type.charCodeAt(3)\n let pos = 8\n for (const c of children) {\n buf.set(c, pos)\n pos += c.length\n }\n return buf\n}\n\nfunction fullBox(type: string, version: number, flags: number, ...children: Uint8Array[]): Uint8Array {\n let size = 12\n for (const c of children) size += c.length\n const buf = new Uint8Array(size)\n const dv = new DataView(buf.buffer)\n dv.setUint32(0, size)\n buf[4] = type.charCodeAt(0)\n buf[5] = type.charCodeAt(1)\n buf[6] = type.charCodeAt(2)\n buf[7] = type.charCodeAt(3)\n dv.setUint32(8, (version << 24) | (flags & 0xffffff))\n let pos = 12\n for (const c of children) {\n buf.set(c, pos)\n pos += c.length\n }\n return buf\n}\n\nfunction u32(v: number): Uint8Array {\n const b = new Uint8Array(4)\n new DataView(b.buffer).setUint32(0, v)\n return b\n}\n\n// \u2500\u2500 Sample flags per ISO 14496-12 \u00A78.8.3.1 \u2500\u2500\nconst KEYFRAME_FLAGS = 0x02000000\nconst DELTA_FLAGS = 0x01010000\n\n// \u2500\u2500 Track geometry field ranges per ISO 14496-12 \u2500\u2500\n// tkhd/trex/tfhd track_ID and the mdhd/mvhd timescales are all unsigned 32-bit\n// fields, written below with DataView.setUint32. That call takes the value\n// modulo 2^32 without complaint, so an out-of-range configuration does not\n// fail \u2014 it silently emits different geometry than the caller asked for\n// (trackId 2^32 becomes track 0, which no fragment can ever reference).\nconst UINT32_MAX = 0xffffffff\n// mvhd next_track_ID is emitted as track_ID + 1 by both buildVideoInitSegment\n// and buildAudioInitSegment (ISO 14496-12 \u00A78.2.2.3, \"a non-zero integer\"). At\n// track_ID = UINT32_MAX that sum wraps to 0, which is both invalid and\n// indistinguishable from an unset field, so the largest usable track_ID is one\n// below the field maximum. (Cited by symbol, not line: this repo's docs gate\n// exists because line anchors rot silently \u2014 see rustfmt.yml's citation check.)\nconst MAX_TRACK_ID = UINT32_MAX - 1\nconst INT32_MIN = -0x80000000\nconst INT32_MAX = 0x7fffffff\n\n/**\n * Fail closed on a track_ID the fMP4 writers below cannot serialize faithfully.\n *\n * Called from both low-level encoders (encodeDataSegment,\n * encodeMultiSampleSegment) so every fragment path is covered by construction\n * rather than by enumerating callers. The class wrappers and init builders call\n * it earlier as well \u2014 partly for a clearer label, partly because the encoders\n * receive an already-incremented sequence number, so their throw would gap the\n * sequence on a call that emitted nothing.\n */\nfunction assertTrackId(trackId: number, label: string): void {\n if (!Number.isInteger(trackId) || trackId <= 0 || trackId > MAX_TRACK_ID) {\n throw new RangeError(`${label} must be an integer in 1..${MAX_TRACK_ID}, got ${trackId}`)\n }\n}\n\n/** Fail closed on a timescale the mdhd/mvhd uint32 fields cannot hold. */\nfunction assertTimescale(timescale: number, label: string): void {\n if (!Number.isInteger(timescale) || timescale <= 0 || timescale > UINT32_MAX) {\n throw new RangeError(`${label} must be an integer in 1..${UINT32_MAX}, got ${timescale}`)\n }\n}\n\n/** Fail closed on a signed trun sample_composition_time_offset. */\nfunction assertCompositionTimeOffsets(\n samples: Array<{ compositionTimeOffset?: number }>,\n): void {\n for (let i = 0; i < samples.length; i++) {\n const offset = samples[i]!.compositionTimeOffset\n if (offset !== undefined &&\n (!Number.isInteger(offset) || offset < INT32_MIN || offset > INT32_MAX)) {\n throw new RangeError(\n `sample ${i} compositionTimeOffset must be an integer in ${INT32_MIN}..${INT32_MAX}, got ${offset}`,\n )\n }\n }\n}\n\n/**\n * Wrap multiple samples in a single moof+mdat fMP4 segment.\n *\n * Builds a trun with N sample entries (duration + size + flags each).\n * Used by CmafBlockAssembler to emit one segment per FEC source block.\n *\n * @param samples - Array of samples with data, duration (timescale units), keyframe flag,\n * and an optional signed composition-time offset (same timescale units)\n * @param baseDecodeTime - Decode time of the first sample in timescale units\n * @param sequence - moof sequence number\n * @param trackId - ISO track ID (default 1)\n * @returns moof+mdat bytes ready for SourceBuffer.appendBuffer()\n */\nexport function encodeMultiSampleSegment(\n samples: Array<{\n data: Uint8Array\n duration: number\n keyframe: boolean\n compositionTimeOffset?: number\n }>,\n baseDecodeTime: number,\n sequence: number,\n trackId = 1,\n): Uint8Array {\n if (samples.length === 0) return new Uint8Array(0)\n assertTrackId(trackId, 'trackId')\n assertCompositionTimeOffsets(samples)\n\n const mfhd = fullBox('mfhd', 0, 0, u32(sequence))\n const tfhd = fullBox('tfhd', 0, 0x020000, u32(trackId))\n\n // tfdt version=1 for 64-bit baseMediaDecodeTime\n const tfdtBody = new Uint8Array(8)\n const tfdtView = new DataView(tfdtBody.buffer)\n tfdtView.setUint32(0, Math.floor(baseDecodeTime / 0x100000000))\n tfdtView.setUint32(4, baseDecodeTime >>> 0)\n const tfdt = fullBox('tfdt', 1, 0, tfdtBody)\n\n // A composition-time offset is signed only in trun version 1. When one is\n // present, every sample gets the field; omitted offsets are encoded as zero.\n const hasCompositionTimeOffset = samples.some(sample => sample.compositionTimeOffset !== undefined)\n const trunVersion = hasCompositionTimeOffset ? 1 : 0\n const trunFlags = 0x000701 | (hasCompositionTimeOffset ? 0x000800 : 0)\n // 4 bytes sample_count + 4 bytes data_offset + N * (4+4+4 [+4]) per sample\n const sampleCount = samples.length\n const sampleEntrySize = hasCompositionTimeOffset ? 16 : 12\n const trunBody = new Uint8Array(8 + sampleCount * sampleEntrySize)\n const trunView = new DataView(trunBody.buffer)\n trunView.setUint32(0, sampleCount)\n trunView.setUint32(4, 0) // dataOffset placeholder\n for (let i = 0; i < sampleCount; i++) {\n const s = samples[i]!\n const off = 8 + i * sampleEntrySize\n trunView.setUint32(off, s.duration >>> 0)\n trunView.setUint32(off + 4, s.data.length)\n trunView.setUint32(off + 8, s.keyframe ? KEYFRAME_FLAGS : DELTA_FLAGS)\n if (hasCompositionTimeOffset) {\n trunView.setInt32(off + 12, s.compositionTimeOffset ?? 0)\n }\n }\n const trun = fullBox('trun', trunVersion, trunFlags, trunBody)\n\n const traf = box('traf', tfhd, tfdt, trun)\n const moof = box('moof', mfhd, traf)\n\n // Concatenate all sample data into mdat\n let mdatSize = 0\n for (const s of samples) mdatSize += s.data.length\n const mdatPayload = new Uint8Array(mdatSize)\n let pos = 0\n for (const s of samples) {\n mdatPayload.set(s.data, pos)\n pos += s.data.length\n }\n const mdat = box('mdat', mdatPayload)\n\n // Fix trun.dataOffset: moof size + 8 (mdat box header)\n const dataOffsetPos = 8 + mfhd.length + 8 + tfhd.length + tfdt.length + 12 + 4\n new DataView(moof.buffer).setUint32(dataOffsetPos, moof.length + 8)\n\n const result = new Uint8Array(moof.length + mdat.length)\n result.set(moof, 0)\n result.set(mdat, moof.length)\n return result\n}\n\n// \u2500\u2500 Green fill / silence generators \u2500\u2500\n\n/**\n * Generate a minimal H.264 IDR slice NAL for green fill (YUV 0,128,128).\n *\n * Reuses SPS/PPS from the stream's avcC so the fill frame is compatible\n * with the existing decoder configuration. Returns AVCC-framed data\n * (4-byte length prefix per NAL) ready for moof+mdat wrapping.\n *\n * @param avcC - Raw avcC payload from catalog description\n * @param width - Video width in pixels\n * @param height - Video height in pixels\n */\nexport function generateGreenFillNAL(avcC: Uint8Array, width: number, height: number): Uint8Array {\n // Parse SPS and PPS from avcC box payload\n // avcC layout: version(1) + profile(1) + compat(1) + level(1) + lengthSizeMinusOne(1)\n // + numSPS(1) + [spsLen(2) + spsData]... + numPPS(1) + [ppsLen(2) + ppsData]...\n if (avcC.length < 8) return new Uint8Array(0)\n\n const lengthSize = (avcC[4]! & 0x03) + 1 // NAL length field size (usually 4)\n let offset = 5\n const numSPS = avcC[offset++]! & 0x1f\n const nals: Uint8Array[] = []\n\n // Extract SPS NAL(s)\n for (let i = 0; i < numSPS; i++) {\n if (offset + 2 > avcC.length) break\n const spsLen = (avcC[offset]! << 8) | avcC[offset + 1]!\n offset += 2\n if (offset + spsLen > avcC.length) break\n const sps = avcC.subarray(offset, offset + spsLen)\n // AVCC frame: 4-byte length + NAL\n const framed = new Uint8Array(4 + sps.length)\n new DataView(framed.buffer).setUint32(0, sps.length)\n framed.set(sps, 4)\n nals.push(framed)\n offset += spsLen\n }\n\n // Extract PPS NAL(s)\n if (offset < avcC.length) {\n const numPPS = avcC[offset++]!\n for (let i = 0; i < numPPS; i++) {\n if (offset + 2 > avcC.length) break\n const ppsLen = (avcC[offset]! << 8) | avcC[offset + 1]!\n offset += 2\n if (offset + ppsLen > avcC.length) break\n const pps = avcC.subarray(offset, offset + ppsLen)\n const framed = new Uint8Array(4 + pps.length)\n new DataView(framed.buffer).setUint32(0, pps.length)\n framed.set(pps, 4)\n nals.push(framed)\n offset += ppsLen\n }\n }\n\n // Build minimal IDR slice NAL (NAL type 5)\n // Slice header: first_mb_in_slice=0, slice_type=7 (I), pic_parameter_set_id=0\n // Exp-Golomb coded: 0(1 bit) + 0001000(slice_type=7=I-all, ue(v)) + 1(pps_id=0, ue(v))\n // Then fill with green macroblocks.\n //\n // For a minimal valid IDR that decodes to green, we use:\n // nal_type=5 (IDR), slice_type=I, then CABAC/CAVLC all-intra-16x16\n // with luma DC=0, chroma DC=128. Exact encoding depends on SPS entropy mode.\n //\n // Simplified approach: generate a very small IDR slice that MSE will accept.\n // The slice header + minimal macroblock data. The decoder fills with the\n // predicted values which default to mid-gray/green.\n const mbWidth = Math.ceil(width / 16)\n const mbHeight = Math.ceil(height / 16)\n const totalMBs = mbWidth * mbHeight\n\n // Minimal IDR slice: nal_ref_idc=3, nal_type=5\n // Slice header bits: first_mb=0 (1 bit ue), slice_type=7 (I-all, 0001000 ue),\n // pps_id=0 (1 bit ue), frame_num=0 (depends on SPS log2_max)\n // We construct a minimal bitstream that encodes an all-skip I-slice.\n // For simplicity, build a fixed small IDR payload \u2014 the decoder will\n // pad/error-conceal remaining MBs producing a solid fill frame.\n const idrSlice = new Uint8Array([\n 0x65, // nal_ref_idc=3, nal_type=5 (IDR)\n 0x88, // slice header: first_mb_in_slice=0, slice_type=7 (I)\n 0x80, // pps_id=0, frame_num=0, idr_pic_id=0\n 0x40, // slice data: mb_skip_run covering remaining MBs\n // Truncated \u2014 decoder will error-conceal remaining MBs as green/gray\n ])\n const idrFramed = new Uint8Array(4 + idrSlice.length)\n new DataView(idrFramed.buffer).setUint32(0, idrSlice.length)\n idrFramed.set(idrSlice, 4)\n nals.push(idrFramed)\n\n // Concatenate all NALs: SPS + PPS + IDR\n let totalLen = 0\n for (const n of nals) totalLen += n.length\n const result = new Uint8Array(totalLen)\n let p = 0\n for (const n of nals) {\n result.set(n, p)\n p += n.length\n }\n return result\n}\n\n/**\n * Generate a minimal silent audio frame for FEC fill.\n *\n * Supports AAC (mp4a) and Opus codecs. Returns raw frame data (no ADTS/OBU\n * header) suitable for fMP4/CMAF wrapping.\n *\n * @param codec - Audio codec string (e.g. 'mp4a.40.2', 'opus')\n * @param sampleRate - Audio sample rate (e.g. 48000)\n * @param channels - Channel count (e.g. 1 or 2)\n */\nexport function generateSilenceFrame(codec: string, sampleRate: number, channels: number): Uint8Array {\n if (codec.startsWith('opus') || codec.startsWith('Opus')) {\n return generateSilenceOpus(channels)\n }\n return generateSilenceAAC(sampleRate, channels)\n}\n\n/** Minimal silent AAC-LC access unit (raw, no ADTS). */\nfunction generateSilenceAAC(sampleRate: number, channels: number): Uint8Array {\n if (channels >= 2) {\n // CPE (channel pair element) + END\n return new Uint8Array([\n 0x21, 0x00, 0x49, 0x90, 0x02, 0x19, 0x00, 0x23, 0x80,\n ])\n }\n // SCE (single channel element) + END\n return new Uint8Array([\n 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,\n ])\n}\n\n/** Minimal silent Opus frame.\n * RFC 6716 \u00A73.1: a 1-byte frame with code 0 encodes silence for SILK/CELT. */\nfunction generateSilenceOpus(channels: number): Uint8Array {\n // Opus TOC byte: config=0 (SILK NB 10ms), s=0 (mono/stereo from channel mapping), c=0 (1 frame)\n // Frame data: single zero byte \u2192 silence\n // For stereo, channel mapping in fMP4 init handles routing; the Opus frame itself is the same.\n return new Uint8Array([0xF8, 0xFF, 0xFE])\n}\n\nexport function normalizeAacSampleForCmaf(data: Uint8Array): Uint8Array {\n if (data.length < 7 || data[0] !== 0xff || (data[1]! & 0xf6) !== 0xf0) {\n return data\n }\n const headerLength = (data[1]! & 0x01) ? 7 : 9\n if (data.length <= headerLength) return data\n const frameLength = ((data[3]! & 0x03) << 11) | (data[4]! << 3) | ((data[5]! & 0xe0) >>> 5)\n if (frameLength !== data.length || frameLength <= headerLength) return data\n return data.subarray(headerLength)\n}\n\n/**\n * Wrap a single raw codec sample in a moof+mdat fMP4 segment.\n *\n * @param data - Raw sample bytes (AVCC H.264 or raw AAC)\n * @param timestamp - Decode time in timescale units\n * @param duration - Sample duration in timescale units\n * @param keyframe - true for IDR/sync sample\n * @param sequence - moof sequence number (monotonically incrementing)\n * @param trackId - ISO track ID (default 1)\n * @returns moof+mdat bytes ready for SourceBuffer.appendBuffer()\n */\nexport function encodeDataSegment(\n data: Uint8Array,\n timestamp: number,\n duration: number,\n keyframe: boolean,\n sequence: number,\n trackId = 1,\n compositionTimeOffset?: number,\n): Uint8Array {\n assertTrackId(trackId, 'trackId')\n assertCompositionTimeOffsets([{ compositionTimeOffset }])\n if (compositionTimeOffset !== undefined) {\n return encodeMultiSampleSegment(\n [{ data, duration, keyframe, compositionTimeOffset }],\n timestamp,\n sequence,\n trackId,\n )\n }\n const sampleFlags = keyframe ? KEYFRAME_FLAGS : DELTA_FLAGS\n\n const mfhd = fullBox('mfhd', 0, 0, u32(sequence))\n const tfhd = fullBox('tfhd', 0, 0x020000, u32(trackId))\n\n // tfdt version=1 for 64-bit baseMediaDecodeTime\n const tfdtBody = new Uint8Array(8)\n const tfdtView = new DataView(tfdtBody.buffer)\n tfdtView.setUint32(0, Math.floor(timestamp / 0x100000000))\n tfdtView.setUint32(4, timestamp >>> 0)\n const tfdt = fullBox('tfdt', 1, 0, tfdtBody)\n\n // trun: flags=0x000701 (data-offset + duration + size + flags)\n const trunBody = new Uint8Array(20)\n const trunView = new DataView(trunBody.buffer)\n trunView.setUint32(0, 1) // sample_count\n trunView.setUint32(4, 0) // dataOffset placeholder\n trunView.setUint32(8, duration >>> 0)\n trunView.setUint32(12, data.length)\n trunView.setUint32(16, sampleFlags)\n const trun = fullBox('trun', 0, 0x000701, trunBody)\n\n const traf = box('traf', tfhd, tfdt, trun)\n const moof = box('moof', mfhd, traf)\n const mdat = box('mdat', data)\n\n // Fix trun.dataOffset: moof size + 8 (mdat box header)\n const dataOffsetPos = 8 + mfhd.length + 8 + tfhd.length + tfdt.length + 12 + 4\n new DataView(moof.buffer).setUint32(dataOffsetPos, moof.length + 8)\n\n const result = new Uint8Array(moof.length + mdat.length)\n result.set(moof, 0)\n result.set(mdat, moof.length)\n return result\n}\n\n/**\n * Build an ftyp+moov init segment for H.264 video MSE from an avcC box.\n *\n * @param avcC - Raw avcC box payload (SPS/PPS configuration)\n * @param width - Video width in pixels\n * @param height - Video height in pixels\n * @param timescale - Timescale (default 1_000_000 = microseconds)\n * @param trackId - Track ID (default 1)\n */\nexport function buildVideoInitSegment(\n avcC: Uint8Array,\n width: number,\n height: number,\n timescale = 1_000_000,\n trackId = 1,\n): Uint8Array {\n // Validated here as well as in setVideoTrackParams: this builder is exported\n // from the package index, so a direct caller reaches the same uint32 tkhd /\n // trex / mdhd / mvhd fields without passing through the class.\n assertTrackId(trackId, 'video trackId')\n assertTimescale(timescale, 'video timescale')\n const ftyp = box('ftyp', new Uint8Array([\n 0x69, 0x73, 0x6f, 0x6d, 0, 0, 2, 0,\n 0x69, 0x73, 0x6f, 0x6d,\n 0x69, 0x73, 0x6f, 0x36,\n 0x6d, 0x70, 0x34, 0x31,\n ]))\n\n const avcCBox = box('avcC', avcC)\n const avc1Body = new Uint8Array(78 + avcCBox.length)\n const avc1View = new DataView(avc1Body.buffer)\n avc1View.setUint16(6, 1)\n avc1View.setUint16(24, width)\n avc1View.setUint16(26, height)\n avc1View.setUint32(28, 0x00480000)\n avc1View.setUint32(32, 0x00480000)\n avc1View.setUint16(40, 1)\n avc1View.setUint16(74, 0x0018)\n avc1View.setInt16(76, -1)\n avc1Body.set(avcCBox, 78)\n const avc1 = box('avc1', avc1Body)\n\n const stsd = fullBox('stsd', 0, 0, u32(1), avc1)\n const stbl = box('stbl', stsd,\n fullBox('stts', 0, 0, u32(0)),\n fullBox('stsc', 0, 0, u32(0)),\n fullBox('stsz', 0, 0, u32(0), u32(0)),\n fullBox('stco', 0, 0, u32(0)),\n )\n const dinf = box('dinf', fullBox('dref', 0, 0, u32(1), fullBox('url ', 0, 1)))\n const minf = box('minf', fullBox('vmhd', 0, 1), dinf, stbl)\n const hdlr = fullBox('hdlr', 0, 0, new Uint8Array([\n 0, 0, 0, 0, 0x76, 0x69, 0x64, 0x65,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0x56, 0x69, 0x64, 0x65, 0x6f, 0,\n ]))\n const mdhdBody = new Uint8Array(20)\n new DataView(mdhdBody.buffer).setUint32(8, timescale)\n const mdhd = fullBox('mdhd', 0, 0, mdhdBody)\n const mdia = box('mdia', mdhd, hdlr, minf)\n\n const tkhdBody = new Uint8Array(80)\n const tkhdView = new DataView(tkhdBody.buffer)\n tkhdView.setUint32(8, trackId)\n tkhdView.setUint32(36, 0x00010000)\n tkhdView.setUint32(52, 0x00010000)\n tkhdView.setUint32(64, 0x40000000)\n tkhdView.setUint32(72, width << 16)\n tkhdView.setUint32(76, height << 16)\n const tkhd = fullBox('tkhd', 0, 3, tkhdBody)\n const trak = box('trak', tkhd, mdia)\n\n const mvhdBody = new Uint8Array(96)\n const mvhdView = new DataView(mvhdBody.buffer)\n mvhdView.setUint32(8, timescale)\n mvhdView.setUint32(16, 0x00010000)\n mvhdView.setUint16(20, 0x0100)\n mvhdView.setUint32(32, 0x00010000)\n mvhdView.setUint32(48, 0x00010000)\n mvhdView.setUint32(60, 0x40000000)\n mvhdView.setUint32(92, trackId + 1)\n const mvhd = fullBox('mvhd', 0, 0, mvhdBody)\n\n const trexBody = new Uint8Array(20)\n new DataView(trexBody.buffer).setUint32(0, trackId)\n new DataView(trexBody.buffer).setUint32(4, 1)\n const mvex = box('mvex', fullBox('trex', 0, 0, trexBody))\n\n const moov = box('moov', mvhd, trak, mvex)\n const result = new Uint8Array(ftyp.length + moov.length)\n result.set(ftyp, 0)\n result.set(moov, ftyp.length)\n return result\n}\n\n/**\n * Build ftyp+moov init segment for AAC audio MSE.\n */\nexport function buildAudioInitSegment(\n sampleRate: number,\n channels: number,\n asc?: Uint8Array,\n timescale?: number,\n trackId = 1,\n): Uint8Array {\n // trackId only: this reaches the same uint32 tkhd/trex/mvhd fields as the\n // video builder. The audio *timescale* is deliberately left unchecked here \u2014\n // wrapAudioSample branches on its exact value, so constraining it belongs\n // with that path rather than in this range fix.\n assertTrackId(trackId, 'audio trackId')\n const ts = timescale ?? sampleRate\n\n if (!asc) {\n const freqTable = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350]\n const fi = freqTable.indexOf(sampleRate)\n const freqIdx = fi >= 0 ? fi : 0x0f\n if (freqIdx <= 0x0e) {\n const v = (2 << 11) | (freqIdx << 7) | (channels << 3)\n asc = new Uint8Array([(v >> 8) & 0xff, v & 0xff])\n } else {\n asc = new Uint8Array([\n (2 << 3) | 0x07,\n (0x08 | ((sampleRate >> 20) & 0x07)) & 0xff,\n (sampleRate >> 12) & 0xff,\n (sampleRate >> 4) & 0xff,\n (((sampleRate & 0x0f) << 4) | (channels << 0)) & 0xff,\n ])\n }\n }\n\n // esds: ES_Descriptor \u2192 DecoderConfigDescriptor \u2192 AudioSpecificConfig\n const dsi = new Uint8Array(2 + asc.length)\n dsi[0] = 0x05; dsi[1] = asc.length; dsi.set(asc, 2)\n const dcdBody = new Uint8Array(13 + dsi.length)\n dcdBody[0] = 0x40; dcdBody[1] = 0x15; dcdBody.set(dsi, 13)\n const dcd = new Uint8Array(2 + dcdBody.length)\n dcd[0] = 0x04; dcd[1] = dcdBody.length; dcd.set(dcdBody, 2)\n const esBody = new Uint8Array(3 + dcd.length)\n esBody[0] = 0; esBody[1] = 0x01; esBody[2] = 0; esBody.set(dcd, 3)\n const es = new Uint8Array(2 + esBody.length)\n es[0] = 0x03; es[1] = esBody.length; es.set(esBody, 2)\n const esdsBox = fullBox('esds', 0, 0, es)\n\n const mp4aBody = new Uint8Array(28 + esdsBox.length)\n const mp4aView = new DataView(mp4aBody.buffer)\n mp4aView.setUint16(6, 1)\n mp4aView.setUint16(16, channels)\n mp4aView.setUint16(18, 16)\n mp4aView.setUint32(24, sampleRate << 16)\n mp4aBody.set(esdsBox, 28)\n const mp4a = box('mp4a', mp4aBody)\n\n const stsd = fullBox('stsd', 0, 0, u32(1), mp4a)\n const stbl = box('stbl', stsd,\n fullBox('stts', 0, 0, u32(0)),\n fullBox('stsc', 0, 0, u32(0)),\n fullBox('stsz', 0, 0, u32(0), u32(0)),\n fullBox('stco', 0, 0, u32(0)),\n )\n const dinf = box('dinf', fullBox('dref', 0, 0, u32(1), fullBox('url ', 0, 1)))\n const minf = box('minf', fullBox('smhd', 0, 0, new Uint8Array(4)), dinf, stbl)\n const hdlr = fullBox('hdlr', 0, 0, new Uint8Array([\n 0, 0, 0, 0, 0x73, 0x6f, 0x75, 0x6e,\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n 0x53, 0x6f, 0x75, 0x6e, 0x64, 0,\n ]))\n const mdhdBody = new Uint8Array(20)\n new DataView(mdhdBody.buffer).setUint32(8, ts)\n const mdhd = fullBox('mdhd', 0, 0, mdhdBody)\n const mdia = box('mdia', mdhd, hdlr, minf)\n\n const tkhdBody = new Uint8Array(80)\n const tkhdView = new DataView(tkhdBody.buffer)\n tkhdView.setUint32(8, trackId)\n tkhdView.setUint32(36, 0x00010000)\n tkhdView.setUint32(52, 0x00010000)\n tkhdView.setUint32(64, 0x40000000)\n const tkhd = fullBox('tkhd', 0, 3, tkhdBody)\n const trak = box('trak', tkhd, mdia)\n\n const mvhdBody = new Uint8Array(96)\n const mvhdView = new DataView(mvhdBody.buffer)\n mvhdView.setUint32(8, ts)\n mvhdView.setUint32(16, 0x00010000)\n mvhdView.setUint16(20, 0x0100)\n mvhdView.setUint32(32, 0x00010000)\n mvhdView.setUint32(48, 0x00010000)\n mvhdView.setUint32(60, 0x40000000)\n mvhdView.setUint32(92, trackId + 1)\n const mvhd = fullBox('mvhd', 0, 0, mvhdBody)\n\n const trexBody = new Uint8Array(20)\n new DataView(trexBody.buffer).setUint32(0, trackId)\n new DataView(trexBody.buffer).setUint32(4, 1)\n const mvex = box('mvex', fullBox('trex', 0, 0, trexBody))\n\n const moov = box('moov', mvhd, trak, mvex)\n const ftyp = box('ftyp', new Uint8Array([\n 0x69, 0x73, 0x6f, 0x6d, 0, 0, 2, 0,\n 0x69, 0x73, 0x6f, 0x6d,\n 0x69, 0x73, 0x6f, 0x36,\n 0x6d, 0x70, 0x34, 0x31,\n ]))\n const result = new Uint8Array(ftyp.length + moov.length)\n result.set(ftyp, 0)\n result.set(moov, ftyp.length)\n return result\n}\n\n/**\n * MMTP \u2192 CMAF converter.\n *\n * Accepts reassembled MFU frames (raw codec samples) from MmtpDecoder\n * and produces fMP4 segments for MSE SourceBuffer.\n *\n * Per draft-ramadan-moq-mmt \u00A75.3:\n * MPU metadata (ftyp+moov) \u2192 init segment\n * MFU sample bytes \u2192 moof+mdat data segment\n *\n * Timescale is microseconds (1_000_000) matching MMTP NTP short timestamps\n * converted via mmtpTimestampToMicros().\n */\nexport class MmtpToCmaf {\n #videoSeq = 1\n #audioSeq = 1\n #videoInitSegment: Uint8Array | null = null\n // Known only for locally-built init segments. Wire-supplied MPU metadata is\n // intentionally opaque here, so setVideoTrackParams remains the API that\n // lets a caller declare its track geometry before wrapping samples.\n #videoInitTrackId: number | null = null\n #audioInitSegment: Uint8Array | null = null\n #lastVideoTimestamp = 0\n // Sticky sample duration in video timescale units, updated from caller-\n // supplied durations or adjacent-timestamp deltas. null means \"nothing\n // observed yet\", in which case #videoFrameDuration derives ~30fps from the\n // configured timescale (33333 at the 1_000_000 default, i.e. unchanged).\n #frameDuration: number | null = null\n // Per-track rebase: each track anchors on its OWN first sample so\n // baseMediaDecodeTime is never negative. A shared base was wrong \u2014 if the\n // first sample of one track arrives later than the other's first sample,\n // the earlier track computes `timestamp - sharedBase` as a negative number,\n // which serializes into tfdt as a huge unsigned uint64 (~2^64 - 46) and\n // Chromium rejects the segment with CHUNK_DEMUXER_ERROR_APPEND_FAILED,\n // closing the MediaSource and detaching all SourceBuffers.\n // For A/V alignment, choose a COMMON anchor: set when the first sample of\n // EITHER track arrives, but only if that sample's timestamp is <= any\n // subsequent track's first sample. Implementation: each track rebases to\n // the minimum timestamp seen across tracks on their respective first sample.\n #videoBaseTs = -1\n #audioBaseTs = -1\n\n // Video track geometry. These pair with the video init segment's tkhd\n // track_ID and mdhd/mvhd timescale: every moof this converter emits must\n // reference the same track at the same rate or the browser either drops the\n // fragment (unknown track) or plays it at the wrong rate. They are\n // configuration rather than stream state, so \u2014 unlike the sequence numbers\n // and time bases above \u2014 reset() deliberately preserves them, matching the\n // fact that reset() also preserves #videoInitSegment.\n #videoTrackId = 1\n #videoTimescale = 1_000_000\n\n /**\n * Point the single-sample video wrappers at a specific track and rate.\n *\n * Call this when the init segment came off the wire (setInitSegmentFromMpu)\n * rather than from buildVideoInit, so the wrappers match the publisher's\n * tkhd/mdhd instead of assuming trackId=1 at microsecond rate. Consumers\n * that build their init through buildVideoInit can pass the same values\n * there instead and skip this call.\n *\n * The rate is settable only until the first single-sample wrap \u2014 see the\n * throw below for why.\n */\n setVideoTrackParams(trackId: number, timescale: number) {\n assertTrackId(trackId, 'video trackId')\n assertTimescale(timescale, 'video timescale')\n // #frameDuration, #lastVideoTimestamp and #videoBaseTs are all denominated\n // in #videoTimescale, so moving the rate out from under them reinterprets\n // every one at the new rate. Both consequences are silent:\n // - a duration latched as 33333 (1 MHz ~30fps) re-emits as 33333 ticks of\n // 90 kHz, a 370 ms frame;\n // - a base captured on the old scale rebases new-scale timestamps to a\n // negative relTs, which tfdt serializes as a ~2^64 uint64 and Chromium\n // rejects with CHUNK_DEMUXER_ERROR_APPEND_FAILED, closing the\n // MediaSource (same failure the #videoBaseTs comment above describes).\n // Rescaling instead of refusing would be a guess: the class cannot tell\n // whether the caller's next timestamps continue this timeline in new units\n // or open a fresh epoch. reset() is the exact mechanism for that\n // discontinuity \u2014 it clears all three fields while preserving geometry \u2014\n // so require it rather than infer. Re-asserting the same rate is a no-op.\n // A cached init also fixes the track ID in tkhd/trex; changing only the\n // wrapper setting would make later tfhd IDs disagree with that init.\n if (trackId !== this.#videoTrackId && this.#videoInitTrackId !== null) {\n throw new Error(\n `video track ID cannot change from ${this.#videoTrackId} to ${trackId} ` +\n 'after a video init has been cached; replace the init atomically',\n )\n }\n if (timescale !== this.#videoTimescale && this.#videoBaseTs >= 0) {\n throw new Error(\n `video timescale cannot change from ${this.#videoTimescale} to ${timescale} ` +\n `after video samples have been wrapped; call reset() first`,\n )\n }\n this.#videoTrackId = trackId\n this.#videoTimescale = timescale\n }\n\n /** Set init segment from MPU metadata packet (fragment_type=0).\n * These are complete ftyp+moov bytes from FFmpeg \u2014 use directly. */\n setInitSegmentFromMpu(data: Uint8Array, isAudio: boolean) {\n if (isAudio) {\n this.#audioInitSegment = data\n } else {\n this.#videoInitSegment = data\n this.#videoInitTrackId = null\n }\n }\n\n /** Build init segment from codec config (catalog path \u2014 no MPU metadata available).\n * Passing timescale/trackId also configures the wrappers via\n * setVideoTrackParams, so init and media segments cannot disagree. */\n buildVideoInit(avcC: Uint8Array, width: number, height: number, timescale?: number, trackId?: number) {\n const nextTimescale = timescale ?? this.#videoTimescale\n const nextTrackId = trackId ?? this.#videoTrackId\n assertTrackId(nextTrackId, 'video trackId')\n assertTimescale(nextTimescale, 'video timescale')\n if (nextTimescale !== this.#videoTimescale && this.#videoBaseTs >= 0) {\n throw new Error(\n `video timescale cannot change from ${this.#videoTimescale} to ${nextTimescale} ` +\n 'after video samples have been wrapped; call reset() first',\n )\n }\n // Build first, then publish both geometry and init together. This is the\n // sanctioned path for replacing a cached init with a new track ID.\n const init = buildVideoInitSegment(\n avcC,\n width,\n height,\n nextTimescale,\n nextTrackId,\n )\n this.#videoTimescale = nextTimescale\n this.#videoTrackId = nextTrackId\n this.#videoInitSegment = init\n this.#videoInitTrackId = nextTrackId\n }\n\n buildAudioInit(sampleRate: number, channels: number, asc?: Uint8Array, timescale?: number) {\n const ts = timescale ?? sampleRate\n this.#audioTimescale = ts\n this.#audioInitSegment = buildAudioInitSegment(sampleRate, channels, asc, ts)\n }\n\n get videoInitSegment(): Uint8Array | null { return this.#videoInitSegment }\n get audioInitSegment(): Uint8Array | null { return this.#audioInitSegment }\n\n /** Convert a raw video sample to an fMP4 moof+mdat segment. */\n wrapVideoSample(data: Uint8Array, timestamp: number, keyframe: boolean, duration?: number): Uint8Array {\n return this.wrapVideoSampleWithTiming(data, timestamp, keyframe, duration).segment\n }\n\n /**\n * Convert a raw video sample and return the exact browser media interval\n * encoded into tfdt/trun. Consumers that correlate SourceBuffer appends with\n * requestVideoFrameCallback must use this rebased timestamp, not the wire or\n * caller-owned timestamp passed above.\n */\n wrapVideoSampleWithTiming(\n data: Uint8Array,\n timestamp: number,\n keyframe: boolean,\n duration?: number,\n ): Readonly<{ segment: Uint8Array; mediaTimestamp: number; duration: number }> {\n // Prefer a caller-provided media duration when the browser append timeline\n // is intentionally decoupled from sparse MMTP wire timestamps. Fall back to\n // estimating from adjacent timestamps for legacy/direct callers. A delta of\n // a full second or more is not a frame interval, so it is rejected as a\n // discontinuity rather than latched.\n if (duration !== undefined && Number.isFinite(duration) && duration > 0) {\n this.#frameDuration = Math.round(duration)\n } else if (this.#lastVideoTimestamp > 0 && timestamp > this.#lastVideoTimestamp) {\n const delta = timestamp - this.#lastVideoTimestamp\n if (delta > 0 && delta < this.#videoTimescale) this.#frameDuration = delta\n }\n this.#lastVideoTimestamp = timestamp\n if (this.#videoBaseTs < 0) this.#videoBaseTs = timestamp\n const relTs = timestamp - this.#videoBaseTs\n const frameDuration = this.#videoFrameDuration\n return Object.freeze({\n segment: encodeDataSegment(\n data,\n relTs,\n frameDuration,\n keyframe,\n this.#videoSeq++,\n this.#videoTrackId,\n ),\n mediaTimestamp: relTs,\n duration: frameDuration,\n })\n }\n\n /** Sticky duration if one has been observed, else ~30fps at the current rate. */\n get #videoFrameDuration(): number {\n return this.#frameDuration ?? Math.max(1, Math.round(this.#videoTimescale / 30))\n }\n\n /** Convert an append-safe video batch using the caller-owned timeline.\n * Durations, baseDecodeTime, and compositionTimeOffset are in the\n * configured video timescale. compositionTimeOffset is the signed PTS-DTS\n * delta; its presence selects a version-1 trun for the whole batch.\n * An explicit trackId is range-checked before #videoSeq++ for the same\n * reason as wrapAudioSamples: the encoder's own check fires too late to\n * keep the sequence ungapped. */\n wrapVideoSamples(\n samples: Array<{\n data: Uint8Array\n duration: number\n keyframe: boolean\n compositionTimeOffset?: number\n }>,\n baseDecodeTime: number,\n trackId = this.#videoTrackId,\n ): Uint8Array {\n assertTrackId(trackId, 'video trackId')\n assertCompositionTimeOffsets(samples)\n return encodeMultiSampleSegment(samples, baseDecodeTime, this.#videoSeq++, trackId)\n }\n\n // Audio timescale from init segment (default 1M \u00B5s; real FFmpeg init uses sampleRate).\n // Set by buildAudioInit or setAudioTimescale.\n #audioTimescale = 1_000_000\n\n /** Set audio timescale to match the init segment's mdhd timescale.\n * Call after appending the real encoder init (FT=0 ftyp+moov). */\n setAudioTimescale(timescale: number) { this.#audioTimescale = timescale }\n\n // Audio sample counter for drift-free baseMediaDecodeTime.\n // AAC frames are exactly 1024 samples at sampleRate. Using sequential\n // counter \u00D7 1024 avoids floating-point rounding drift from timestamp conversion.\n #audioSampleCount = 0\n\n /** AAC access-unit length in samples. ISO/IEC 14496-3: an AAC-LC frame is\n * exactly 1024 samples at every sample rate \u2014 it is not rate-dependent. */\n readonly #aacFrameSamples = 1024\n\n /** Convert a raw audio sample to an fMP4 moof+mdat segment. */\n wrapAudioSample(\n data: Uint8Array,\n timestamp: number,\n sampleDuration = 21333,\n compositionTimeOffset?: number,\n ): Uint8Array {\n assertCompositionTimeOffsets([{ compositionTimeOffset }])\n const sampleData = normalizeAacSampleForCmaf(data)\n if (this.#audioBaseTs < 0) this.#audioBaseTs = timestamp\n\n // When timescale matches sampleRate (e.g. 48000), use integer sample counting\n // for exact baseMediaDecodeTime alignment. This eliminates cumulative rounding\n // drift from Math.round(\u00B5s * sampleRate / 1_000_000) that causes frequency\n // wandering in FFT analysis (42% consistency \u2192 99%+ with exact counting).\n //\n // samplesPerFrame is the AAC access-unit length, NOT a rescaled duration.\n // Deriving it as Math.round(sampleDuration * timescale / 1e6) only lands on\n // 1024 when the rate happens to be 48 kHz (21333 * 48000 / 1e6 = 1023.98),\n // which made the default silently correct at 48 kHz and wrong everywhere\n // else: at 44.1 kHz it yields 941, so every moof declared ~8% short frames\n // and Chrome rejected the first packet with PIPELINE_ERROR_DECODE\n // (\"Failed to send audio packet for decoding\", duration=21337\u00B5s = 941/44100).\n const samplesPerFrame = this.#audioTimescale !== 1_000_000\n ? this.#aacFrameSamples\n : sampleDuration\n const scaledTs = this.#audioTimescale !== 1_000_000\n ? this.#audioSampleCount * samplesPerFrame\n : (timestamp - this.#audioBaseTs)\n this.#audioSampleCount++\n\n return encodeDataSegment(\n sampleData,\n scaledTs,\n samplesPerFrame,\n true,\n this.#audioSeq++,\n 1,\n compositionTimeOffset,\n )\n }\n\n /** Convert an ordered audio batch using the caller-owned timeline. */\n wrapAudioSamples(\n samples: Array<{\n data: Uint8Array\n duration: number\n compositionTimeOffset?: number\n }>,\n baseDecodeTime: number,\n trackId = 1,\n ): Uint8Array {\n // Checked before #audioSeq++ below: the encoder validates too, but its\n // throw would land after the counter had already advanced, leaving the\n // sequence gapped by a call that produced no segment.\n assertTrackId(trackId, 'audio trackId')\n assertCompositionTimeOffsets(samples)\n return encodeMultiSampleSegment(\n samples.map(sample => ({\n data: normalizeAacSampleForCmaf(sample.data),\n duration: sample.duration,\n keyframe: true,\n compositionTimeOffset: sample.compositionTimeOffset,\n })),\n baseDecodeTime,\n this.#audioSeq++,\n trackId,\n )\n }\n\n /** Clear per-stream sequencing and time bases.\n * Cached init segments and the video track geometry survive, so a converter\n * reset mid-subscription keeps emitting moofs the existing init can resolve.\n * Clearing the timescale-denominated timing state also re-opens the video\n * rate for change \u2014 this is the sanctioned way to retarget mid-subscription. */\n reset() {\n this.#videoSeq = 1\n this.#audioSeq = 1\n this.#audioSampleCount = 0\n this.#lastVideoTimestamp = 0\n this.#frameDuration = null\n this.#videoBaseTs = -1\n this.#audioBaseTs = -1\n this.#audioTimescale = 1_000_000\n }\n}\n", "/**\n * Utilities for hex, bytes, CSPRNG.\n * @module\n */\n/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */\n\n// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.\n// node.js versions earlier than v19 don't declare it in global scope.\n// For node.js, package.json#exports field mapping rewrites import\n// from `crypto` to `cryptoNode`, which imports native module.\n// Makes the utils un-importable in browsers without a bundler.\n// Once node.js 18 is deprecated (2025-04-30), we can just drop the import.\nimport { crypto } from '@noble/hashes/crypto';\n\n/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */\nexport function isBytes(a: unknown): a is Uint8Array {\n return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n}\n\n/** Asserts something is positive integer. */\nexport function anumber(n: number): void {\n if (!Number.isSafeInteger(n) || n < 0) throw new Error('positive integer expected, got ' + n);\n}\n\n/** Asserts something is Uint8Array. */\nexport function abytes(b: Uint8Array | undefined, ...lengths: number[]): void {\n if (!isBytes(b)) throw new Error('Uint8Array expected');\n if (lengths.length > 0 && !lengths.includes(b.length))\n throw new Error('Uint8Array expected of length ' + lengths + ', got length=' + b.length);\n}\n\n/** Asserts something is hash */\nexport function ahash(h: IHash): void {\n if (typeof h !== 'function' || typeof h.create !== 'function')\n throw new Error('Hash should be wrapped by utils.createHasher');\n anumber(h.outputLen);\n anumber(h.blockLen);\n}\n\n/** Asserts a hash instance has not been destroyed / finished */\nexport function aexists(instance: any, checkFinished = true): void {\n if (instance.destroyed) throw new Error('Hash instance has been destroyed');\n if (checkFinished && instance.finished) throw new Error('Hash#digest() has already been called');\n}\n\n/** Asserts output is properly-sized byte array */\nexport function aoutput(out: any, instance: any): void {\n abytes(out);\n const min = instance.outputLen;\n if (out.length < min) {\n throw new Error('digestInto() expects output buffer of length at least ' + min);\n }\n}\n\n/** Generic type encompassing 8/16/32-byte arrays - but not 64-byte. */\n// prettier-ignore\nexport type TypedArray = Int8Array | Uint8ClampedArray | Uint8Array |\n Uint16Array | Int16Array | Uint32Array | Int32Array;\n\n/** Cast u8 / u16 / u32 to u8. */\nexport function u8(arr: TypedArray): Uint8Array {\n return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** Cast u8 / u16 / u32 to u32. */\nexport function u32(arr: TypedArray): Uint32Array {\n return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));\n}\n\n/** Zeroize a byte array. Warning: JS provides no guarantees. */\nexport function clean(...arrays: TypedArray[]): void {\n for (let i = 0; i < arrays.length; i++) {\n arrays[i].fill(0);\n }\n}\n\n/** Create DataView of an array for easy byte-level manipulation. */\nexport function createView(arr: TypedArray): DataView {\n return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n\n/** The rotate right (circular right shift) operation for uint32 */\nexport function rotr(word: number, shift: number): number {\n return (word << (32 - shift)) | (word >>> shift);\n}\n\n/** The rotate left (circular left shift) operation for uint32 */\nexport function rotl(word: number, shift: number): number {\n return (word << shift) | ((word >>> (32 - shift)) >>> 0);\n}\n\n/** Is current platform little-endian? Most are. Big-Endian platform: IBM */\nexport const isLE: boolean = /* @__PURE__ */ (() =>\n new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44)();\n\n/** The byte swap operation for uint32 */\nexport function byteSwap(word: number): number {\n return (\n ((word << 24) & 0xff000000) |\n ((word << 8) & 0xff0000) |\n ((word >>> 8) & 0xff00) |\n ((word >>> 24) & 0xff)\n );\n}\n/** Conditionally byte swap if on a big-endian platform */\nexport const swap8IfBE: (n: number) => number = isLE\n ? (n: number) => n\n : (n: number) => byteSwap(n);\n\n/** @deprecated */\nexport const byteSwapIfBE: typeof swap8IfBE = swap8IfBE;\n/** In place byte swap for Uint32Array */\nexport function byteSwap32(arr: Uint32Array): Uint32Array {\n for (let i = 0; i < arr.length; i++) {\n arr[i] = byteSwap(arr[i]);\n }\n return arr;\n}\n\nexport const swap32IfBE: (u: Uint32Array) => Uint32Array = isLE\n ? (u: Uint32Array) => u\n : byteSwap32;\n\n// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex\nconst hasHexBuiltin: boolean = /* @__PURE__ */ (() =>\n // @ts-ignore\n typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();\n\n// Array where index 0xf0 (240) is mapped to string 'f0'\nconst hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>\n i.toString(16).padStart(2, '0')\n);\n\n/**\n * Convert byte array to hex string. Uses built-in function, when available.\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\n */\nexport function bytesToHex(bytes: Uint8Array): string {\n abytes(bytes);\n // @ts-ignore\n if (hasHexBuiltin) return bytes.toHex();\n // pre-caching improves the speed 6x\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += hexes[bytes[i]];\n }\n return hex;\n}\n\n// We use optimized technique to convert hex string to byte array\nconst asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 } as const;\nfunction asciiToBase16(ch: number): number | undefined {\n if (ch >= asciis._0 && ch <= asciis._9) return ch - asciis._0; // '2' => 50-48\n if (ch >= asciis.A && ch <= asciis.F) return ch - (asciis.A - 10); // 'B' => 66-(65-10)\n if (ch >= asciis.a && ch <= asciis.f) return ch - (asciis.a - 10); // 'b' => 98-(97-10)\n return;\n}\n\n/**\n * Convert hex string to byte array. Uses built-in function, when available.\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\n */\nexport function hexToBytes(hex: string): Uint8Array {\n if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);\n // @ts-ignore\n if (hasHexBuiltin) return Uint8Array.fromHex(hex);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2) throw new Error('hex string expected, got unpadded hex of length ' + hl);\n const array = new Uint8Array(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n const n1 = asciiToBase16(hex.charCodeAt(hi));\n const n2 = asciiToBase16(hex.charCodeAt(hi + 1));\n if (n1 === undefined || n2 === undefined) {\n const char = hex[hi] + hex[hi + 1];\n throw new Error('hex string expected, got non-hex character \"' + char + '\" at index ' + hi);\n }\n array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163\n }\n return array;\n}\n\n/**\n * There is no setImmediate in browser and setTimeout is slow.\n * Call of async fn will return Promise, which will be fullfiled only on\n * next scheduler queue processing step and this is exactly what we need.\n */\nexport const nextTick = async (): Promise<void> => {};\n\n/** Returns control to thread each 'tick' ms to avoid blocking. */\nexport async function asyncLoop(\n iters: number,\n tick: number,\n cb: (i: number) => void\n): Promise<void> {\n let ts = Date.now();\n for (let i = 0; i < iters; i++) {\n cb(i);\n // Date.now() is not monotonic, so in case if clock goes backwards we return return control too\n const diff = Date.now() - ts;\n if (diff >= 0 && diff < tick) continue;\n await nextTick();\n ts += diff;\n }\n}\n\n// Global symbols, but ts doesn't see them: https://github.com/microsoft/TypeScript/issues/31535\ndeclare const TextEncoder: any;\ndeclare const TextDecoder: any;\n\n/**\n * Converts string to bytes using UTF8 encoding.\n * @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])\n */\nexport function utf8ToBytes(str: string): Uint8Array {\n if (typeof str !== 'string') throw new Error('string expected');\n return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\n}\n\n/**\n * Converts bytes to string using UTF8 encoding.\n * @example bytesToUtf8(Uint8Array.from([97, 98, 99])) // 'abc'\n */\nexport function bytesToUtf8(bytes: Uint8Array): string {\n return new TextDecoder().decode(bytes);\n}\n\n/** Accepted input of hash functions. Strings are converted to byte arrays. */\nexport type Input = string | Uint8Array;\n/**\n * Normalizes (non-hex) string or Uint8Array to Uint8Array.\n * Warning: when Uint8Array is passed, it would NOT get copied.\n * Keep in mind for future mutable operations.\n */\nexport function toBytes(data: Input): Uint8Array {\n if (typeof data === 'string') data = utf8ToBytes(data);\n abytes(data);\n return data;\n}\n\n/** KDFs can accept string or Uint8Array for user convenience. */\nexport type KDFInput = string | Uint8Array;\n/**\n * Helper for KDFs: consumes uint8array or string.\n * When string is passed, does utf8 decoding, using TextDecoder.\n */\nexport function kdfInputToBytes(data: KDFInput): Uint8Array {\n if (typeof data === 'string') data = utf8ToBytes(data);\n abytes(data);\n return data;\n}\n\n/** Copies several Uint8Arrays into one. */\nexport function concatBytes(...arrays: Uint8Array[]): Uint8Array {\n let sum = 0;\n for (let i = 0; i < arrays.length; i++) {\n const a = arrays[i];\n abytes(a);\n sum += a.length;\n }\n const res = new Uint8Array(sum);\n for (let i = 0, pad = 0; i < arrays.length; i++) {\n const a = arrays[i];\n res.set(a, pad);\n pad += a.length;\n }\n return res;\n}\n\ntype EmptyObj = {};\nexport function checkOpts<T1 extends EmptyObj, T2 extends EmptyObj>(\n defaults: T1,\n opts?: T2\n): T1 & T2 {\n if (opts !== undefined && {}.toString.call(opts) !== '[object Object]')\n throw new Error('options should be object or undefined');\n const merged = Object.assign(defaults, opts);\n return merged as T1 & T2;\n}\n\n/** Hash interface. */\nexport type IHash = {\n (data: Uint8Array): Uint8Array;\n blockLen: number;\n outputLen: number;\n create: any;\n};\n\n/** For runtime check if class implements interface */\nexport abstract class Hash<T extends Hash<T>> {\n abstract blockLen: number; // Bytes per block\n abstract outputLen: number; // Bytes in output\n abstract update(buf: Input): this;\n // Writes digest into buf\n abstract digestInto(buf: Uint8Array): void;\n abstract digest(): Uint8Array;\n /**\n * Resets internal state. Makes Hash instance unusable.\n * Reset is impossible for keyed hashes if key is consumed into state. If digest is not consumed\n * by user, they will need to manually call `destroy()` when zeroing is necessary.\n */\n abstract destroy(): void;\n /**\n * Clones hash instance. Unsafe: doesn't check whether `to` is valid. Can be used as `clone()`\n * when no options are passed.\n * Reasons to use `_cloneInto` instead of clone: 1) performance 2) reuse instance => all internal\n * buffers are overwritten => causes buffer overwrite which is used for digest in some cases.\n * There are no guarantees for clean-up because it's impossible in JS.\n */\n abstract _cloneInto(to?: T): T;\n // Safe version that clones internal state\n abstract clone(): T;\n}\n\n/**\n * XOF: streaming API to read digest in chunks.\n * Same as 'squeeze' in keccak/k12 and 'seek' in blake3, but more generic name.\n * When hash used in XOF mode it is up to user to call '.destroy' afterwards, since we cannot\n * destroy state, next call can require more bytes.\n */\nexport type HashXOF<T extends Hash<T>> = Hash<T> & {\n xof(bytes: number): Uint8Array; // Read 'bytes' bytes from digest stream\n xofInto(buf: Uint8Array): Uint8Array; // read buf.length bytes from digest stream into buf\n};\n\n/** Hash function */\nexport type CHash = ReturnType<typeof createHasher>;\n/** Hash function with output */\nexport type CHashO = ReturnType<typeof createOptHasher>;\n/** XOF with output */\nexport type CHashXO = ReturnType<typeof createXOFer>;\n\n/** Wraps hash function, creating an interface on top of it */\nexport function createHasher<T extends Hash<T>>(\n hashCons: () => Hash<T>\n): {\n (msg: Input): Uint8Array;\n outputLen: number;\n blockLen: number;\n create(): Hash<T>;\n} {\n const hashC = (msg: Input): Uint8Array => hashCons().update(toBytes(msg)).digest();\n const tmp = hashCons();\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = () => hashCons();\n return hashC;\n}\n\nexport function createOptHasher<H extends Hash<H>, T extends Object>(\n hashCons: (opts?: T) => Hash<H>\n): {\n (msg: Input, opts?: T): Uint8Array;\n outputLen: number;\n blockLen: number;\n create(opts?: T): Hash<H>;\n} {\n const hashC = (msg: Input, opts?: T): Uint8Array => hashCons(opts).update(toBytes(msg)).digest();\n const tmp = hashCons({} as T);\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = (opts?: T) => hashCons(opts);\n return hashC;\n}\n\nexport function createXOFer<H extends HashXOF<H>, T extends Object>(\n hashCons: (opts?: T) => HashXOF<H>\n): {\n (msg: Input, opts?: T): Uint8Array;\n outputLen: number;\n blockLen: number;\n create(opts?: T): HashXOF<H>;\n} {\n const hashC = (msg: Input, opts?: T): Uint8Array => hashCons(opts).update(toBytes(msg)).digest();\n const tmp = hashCons({} as T);\n hashC.outputLen = tmp.outputLen;\n hashC.blockLen = tmp.blockLen;\n hashC.create = (opts?: T) => hashCons(opts);\n return hashC;\n}\nexport const wrapConstructor: typeof createHasher = createHasher;\nexport const wrapConstructorWithOpts: typeof createOptHasher = createOptHasher;\nexport const wrapXOFConstructorWithOpts: typeof createXOFer = createXOFer;\n\n/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */\nexport function randomBytes(bytesLength = 32): Uint8Array {\n if (crypto && typeof crypto.getRandomValues === 'function') {\n return crypto.getRandomValues(new Uint8Array(bytesLength));\n }\n // Legacy Node.js compatibility\n if (crypto && typeof crypto.randomBytes === 'function') {\n return Uint8Array.from(crypto.randomBytes(bytesLength));\n }\n throw new Error('crypto.getRandomValues must be defined');\n}\n", "/**\n * Internal Merkle-Damgard hash utils.\n * @module\n */\nimport { type Input, Hash, abytes, aexists, aoutput, clean, createView, toBytes } from './utils.ts';\n\n/** Polyfill for Safari 14. https://caniuse.com/mdn-javascript_builtins_dataview_setbiguint64 */\nexport function setBigUint64(\n view: DataView,\n byteOffset: number,\n value: bigint,\n isLE: boolean\n): void {\n if (typeof view.setBigUint64 === 'function') return view.setBigUint64(byteOffset, value, isLE);\n const _32n = BigInt(32);\n const _u32_max = BigInt(0xffffffff);\n const wh = Number((value >> _32n) & _u32_max);\n const wl = Number(value & _u32_max);\n const h = isLE ? 4 : 0;\n const l = isLE ? 0 : 4;\n view.setUint32(byteOffset + h, wh, isLE);\n view.setUint32(byteOffset + l, wl, isLE);\n}\n\n/** Choice: a ? b : c */\nexport function Chi(a: number, b: number, c: number): number {\n return (a & b) ^ (~a & c);\n}\n\n/** Majority function, true if any two inputs is true. */\nexport function Maj(a: number, b: number, c: number): number {\n return (a & b) ^ (a & c) ^ (b & c);\n}\n\n/**\n * Merkle-Damgard hash construction base class.\n * Could be used to create MD5, RIPEMD, SHA1, SHA2.\n */\nexport abstract class HashMD<T extends HashMD<T>> extends Hash<T> {\n protected abstract process(buf: DataView, offset: number): void;\n protected abstract get(): number[];\n protected abstract set(...args: number[]): void;\n abstract destroy(): void;\n protected abstract roundClean(): void;\n\n readonly blockLen: number;\n readonly outputLen: number;\n readonly padOffset: number;\n readonly isLE: boolean;\n\n // For partial updates less than block size\n protected buffer: Uint8Array;\n protected view: DataView;\n protected finished = false;\n protected length = 0;\n protected pos = 0;\n protected destroyed = false;\n\n constructor(blockLen: number, outputLen: number, padOffset: number, isLE: boolean) {\n super();\n this.blockLen = blockLen;\n this.outputLen = outputLen;\n this.padOffset = padOffset;\n this.isLE = isLE;\n this.buffer = new Uint8Array(blockLen);\n this.view = createView(this.buffer);\n }\n update(data: Input): this {\n aexists(this);\n data = toBytes(data);\n abytes(data);\n const { view, buffer, blockLen } = this;\n const len = data.length;\n for (let pos = 0; pos < len; ) {\n const take = Math.min(blockLen - this.pos, len - pos);\n // Fast path: we have at least one block in input, cast it to view and process\n if (take === blockLen) {\n const dataView = createView(data);\n for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);\n continue;\n }\n buffer.set(data.subarray(pos, pos + take), this.pos);\n this.pos += take;\n pos += take;\n if (this.pos === blockLen) {\n this.process(view, 0);\n this.pos = 0;\n }\n }\n this.length += data.length;\n this.roundClean();\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n aoutput(out, this);\n this.finished = true;\n // Padding\n // We can avoid allocation of buffer for padding completely if it\n // was previously not allocated here. But it won't change performance.\n const { buffer, view, blockLen, isLE } = this;\n let { pos } = this;\n // append the bit '1' to the message\n buffer[pos++] = 0b10000000;\n clean(this.buffer.subarray(pos));\n // we have less than padOffset left in buffer, so we cannot put length in\n // current block, need process it and pad again\n if (this.padOffset > blockLen - pos) {\n this.process(view, 0);\n pos = 0;\n }\n // Pad until full block byte with zeros\n for (let i = pos; i < blockLen; i++) buffer[i] = 0;\n // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that\n // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.\n // So we just write lowest 64 bits of that value.\n setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);\n this.process(view, 0);\n const oview = createView(out);\n const len = this.outputLen;\n // NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT\n if (len % 4) throw new Error('_sha2: outputLen should be aligned to 32bit');\n const outLen = len / 4;\n const state = this.get();\n if (outLen > state.length) throw new Error('_sha2: outputLen bigger than state');\n for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);\n }\n digest(): Uint8Array {\n const { buffer, outputLen } = this;\n this.digestInto(buffer);\n const res = buffer.slice(0, outputLen);\n this.destroy();\n return res;\n }\n _cloneInto(to?: T): T {\n to ||= new (this.constructor as any)() as T;\n to.set(...this.get());\n const { blockLen, buffer, length, finished, destroyed, pos } = this;\n to.destroyed = destroyed;\n to.finished = finished;\n to.length = length;\n to.pos = pos;\n if (length % blockLen) to.buffer.set(buffer);\n return to;\n }\n clone(): T {\n return this._cloneInto();\n }\n}\n\n/**\n * Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.\n * Check out `test/misc/sha2-gen-iv.js` for recomputation guide.\n */\n\n/** Initial SHA256 state. Bits 0..32 of frac part of sqrt of primes 2..19 */\nexport const SHA256_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\n]);\n\n/** Initial SHA224 state. Bits 32..64 of frac part of sqrt of primes 23..53 */\nexport const SHA224_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,\n]);\n\n/** Initial SHA384 state. Bits 0..64 of frac part of sqrt of primes 23..53 */\nexport const SHA384_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0xcbbb9d5d, 0xc1059ed8, 0x629a292a, 0x367cd507, 0x9159015a, 0x3070dd17, 0x152fecd8, 0xf70e5939,\n 0x67332667, 0xffc00b31, 0x8eb44a87, 0x68581511, 0xdb0c2e0d, 0x64f98fa7, 0x47b5481d, 0xbefa4fa4,\n]);\n\n/** Initial SHA512 state. Bits 0..64 of frac part of sqrt of primes 2..19 */\nexport const SHA512_IV: Uint32Array = /* @__PURE__ */ Uint32Array.from([\n 0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1,\n 0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179,\n]);\n", "/**\n * Internal helpers for u64. BigUint64Array is too slow as per 2025, so we implement it using Uint32Array.\n * @todo re-check https://issues.chromium.org/issues/42212588\n * @module\n */\nconst U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);\nconst _32n = /* @__PURE__ */ BigInt(32);\n\nfunction fromBig(\n n: bigint,\n le = false\n): {\n h: number;\n l: number;\n} {\n if (le) return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) };\n return { h: Number((n >> _32n) & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };\n}\n\nfunction split(lst: bigint[], le = false): Uint32Array[] {\n const len = lst.length;\n let Ah = new Uint32Array(len);\n let Al = new Uint32Array(len);\n for (let i = 0; i < len; i++) {\n const { h, l } = fromBig(lst[i], le);\n [Ah[i], Al[i]] = [h, l];\n }\n return [Ah, Al];\n}\n\nconst toBig = (h: number, l: number): bigint => (BigInt(h >>> 0) << _32n) | BigInt(l >>> 0);\n// for Shift in [0, 32)\nconst shrSH = (h: number, _l: number, s: number): number => h >>> s;\nconst shrSL = (h: number, l: number, s: number): number => (h << (32 - s)) | (l >>> s);\n// Right rotate for Shift in [1, 32)\nconst rotrSH = (h: number, l: number, s: number): number => (h >>> s) | (l << (32 - s));\nconst rotrSL = (h: number, l: number, s: number): number => (h << (32 - s)) | (l >>> s);\n// Right rotate for Shift in (32, 64), NOTE: 32 is special case.\nconst rotrBH = (h: number, l: number, s: number): number => (h << (64 - s)) | (l >>> (s - 32));\nconst rotrBL = (h: number, l: number, s: number): number => (h >>> (s - 32)) | (l << (64 - s));\n// Right rotate for shift===32 (just swaps l&h)\nconst rotr32H = (_h: number, l: number): number => l;\nconst rotr32L = (h: number, _l: number): number => h;\n// Left rotate for Shift in [1, 32)\nconst rotlSH = (h: number, l: number, s: number): number => (h << s) | (l >>> (32 - s));\nconst rotlSL = (h: number, l: number, s: number): number => (l << s) | (h >>> (32 - s));\n// Left rotate for Shift in (32, 64), NOTE: 32 is special case.\nconst rotlBH = (h: number, l: number, s: number): number => (l << (s - 32)) | (h >>> (64 - s));\nconst rotlBL = (h: number, l: number, s: number): number => (h << (s - 32)) | (l >>> (64 - s));\n\n// JS uses 32-bit signed integers for bitwise operations which means we cannot\n// simple take carry out of low bit sum by shift, we need to use division.\nfunction add(\n Ah: number,\n Al: number,\n Bh: number,\n Bl: number\n): {\n h: number;\n l: number;\n} {\n const l = (Al >>> 0) + (Bl >>> 0);\n return { h: (Ah + Bh + ((l / 2 ** 32) | 0)) | 0, l: l | 0 };\n}\n// Addition with more than 2 elements\nconst add3L = (Al: number, Bl: number, Cl: number): number => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);\nconst add3H = (low: number, Ah: number, Bh: number, Ch: number): number =>\n (Ah + Bh + Ch + ((low / 2 ** 32) | 0)) | 0;\nconst add4L = (Al: number, Bl: number, Cl: number, Dl: number): number =>\n (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);\nconst add4H = (low: number, Ah: number, Bh: number, Ch: number, Dh: number): number =>\n (Ah + Bh + Ch + Dh + ((low / 2 ** 32) | 0)) | 0;\nconst add5L = (Al: number, Bl: number, Cl: number, Dl: number, El: number): number =>\n (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);\nconst add5H = (low: number, Ah: number, Bh: number, Ch: number, Dh: number, Eh: number): number =>\n (Ah + Bh + Ch + Dh + Eh + ((low / 2 ** 32) | 0)) | 0;\n\n// prettier-ignore\nexport {\n add, add3H, add3L, add4H, add4L, add5H, add5L, fromBig, rotlBH, rotlBL, rotlSH, rotlSL, rotr32H, rotr32L, rotrBH, rotrBL, rotrSH, rotrSL, shrSH, shrSL, split, toBig\n};\n// prettier-ignore\nconst u64: { fromBig: typeof fromBig; split: typeof split; toBig: (h: number, l: number) => bigint; shrSH: (h: number, _l: number, s: number) => number; shrSL: (h: number, l: number, s: number) => number; rotrSH: (h: number, l: number, s: number) => number; rotrSL: (h: number, l: number, s: number) => number; rotrBH: (h: number, l: number, s: number) => number; rotrBL: (h: number, l: number, s: number) => number; rotr32H: (_h: number, l: number) => number; rotr32L: (h: number, _l: number) => number; rotlSH: (h: number, l: number, s: number) => number; rotlSL: (h: number, l: number, s: number) => number; rotlBH: (h: number, l: number, s: number) => number; rotlBL: (h: number, l: number, s: number) => number; add: typeof add; add3L: (Al: number, Bl: number, Cl: number) => number; add3H: (low: number, Ah: number, Bh: number, Ch: number) => number; add4L: (Al: number, Bl: number, Cl: number, Dl: number) => number; add4H: (low: number, Ah: number, Bh: number, Ch: number, Dh: number) => number; add5H: (low: number, Ah: number, Bh: number, Ch: number, Dh: number, Eh: number) => number; add5L: (Al: number, Bl: number, Cl: number, Dl: number, El: number) => number; } = {\n fromBig, split, toBig,\n shrSH, shrSL,\n rotrSH, rotrSL, rotrBH, rotrBL,\n rotr32H, rotr32L,\n rotlSH, rotlSL, rotlBH, rotlBL,\n add, add3L, add3H, add4L, add4H, add5H, add5L,\n};\nexport default u64;\n", "/**\n * Internal helpers for blake hash.\n * @module\n */\nimport { rotr } from './utils.ts';\n\n/**\n * Internal blake variable.\n * For BLAKE2b, the two extra permutations for rounds 10 and 11 are SIGMA[10..11] = SIGMA[0..1].\n */\n// prettier-ignore\nexport const BSIGMA: Uint8Array = /* @__PURE__ */ Uint8Array.from([\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,\n 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,\n 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,\n 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,\n 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,\n 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,\n 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,\n 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,\n 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,\n // Blake1, unused in others\n 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,\n 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,\n 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,\n 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,\n]);\n\n// prettier-ignore\nexport type Num4 = { a: number; b: number; c: number; d: number; };\n\n// Mixing function G splitted in two halfs\nexport function G1s(a: number, b: number, c: number, d: number, x: number): Num4 {\n a = (a + b + x) | 0;\n d = rotr(d ^ a, 16);\n c = (c + d) | 0;\n b = rotr(b ^ c, 12);\n return { a, b, c, d };\n}\n\nexport function G2s(a: number, b: number, c: number, d: number, x: number): Num4 {\n a = (a + b + x) | 0;\n d = rotr(d ^ a, 8);\n c = (c + d) | 0;\n b = rotr(b ^ c, 7);\n return { a, b, c, d };\n}\n", "/**\n * blake2b (64-bit) & blake2s (8 to 32-bit) hash functions.\n * b could have been faster, but there is no fast u64 in js, so s is 1.5x faster.\n * @module\n */\nimport { BSIGMA, G1s, G2s } from './_blake.ts';\nimport { SHA256_IV } from './_md.ts';\nimport * as u64 from './_u64.ts';\n// prettier-ignore\nimport {\n abytes, aexists, anumber, aoutput,\n clean, createOptHasher, Hash, swap32IfBE, swap8IfBE, toBytes, u32,\n type CHashO, type Input\n} from './utils.ts';\n\n/** Blake hash options. dkLen is output length. key is used in MAC mode. salt is used in KDF mode. */\nexport type Blake2Opts = {\n dkLen?: number;\n key?: Input;\n salt?: Input;\n personalization?: Input;\n};\n\n// Same as SHA512_IV, but swapped endianness: LE instead of BE. iv[1] is iv[0], etc.\nconst B2B_IV = /* @__PURE__ */ Uint32Array.from([\n 0xf3bcc908, 0x6a09e667, 0x84caa73b, 0xbb67ae85, 0xfe94f82b, 0x3c6ef372, 0x5f1d36f1, 0xa54ff53a,\n 0xade682d1, 0x510e527f, 0x2b3e6c1f, 0x9b05688c, 0xfb41bd6b, 0x1f83d9ab, 0x137e2179, 0x5be0cd19,\n]);\n// Temporary buffer\nconst BBUF = /* @__PURE__ */ new Uint32Array(32);\n\n// Mixing function G splitted in two halfs\nfunction G1b(a: number, b: number, c: number, d: number, msg: Uint32Array, x: number) {\n // NOTE: V is LE here\n const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore\n let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; // prettier-ignore\n let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; // prettier-ignore\n let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; // prettier-ignore\n let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; // prettier-ignore\n // v[a] = (v[a] + v[b] + x) | 0;\n let ll = u64.add3L(Al, Bl, Xl);\n Ah = u64.add3H(ll, Ah, Bh, Xh);\n Al = ll | 0;\n // v[d] = rotr(v[d] ^ v[a], 32)\n ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al });\n ({ Dh, Dl } = { Dh: u64.rotr32H(Dh, Dl), Dl: u64.rotr32L(Dh, Dl) });\n // v[c] = (v[c] + v[d]) | 0;\n ({ h: Ch, l: Cl } = u64.add(Ch, Cl, Dh, Dl));\n // v[b] = rotr(v[b] ^ v[c], 24)\n ({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl });\n ({ Bh, Bl } = { Bh: u64.rotrSH(Bh, Bl, 24), Bl: u64.rotrSL(Bh, Bl, 24) });\n (BBUF[2 * a] = Al), (BBUF[2 * a + 1] = Ah);\n (BBUF[2 * b] = Bl), (BBUF[2 * b + 1] = Bh);\n (BBUF[2 * c] = Cl), (BBUF[2 * c + 1] = Ch);\n (BBUF[2 * d] = Dl), (BBUF[2 * d + 1] = Dh);\n}\n\nfunction G2b(a: number, b: number, c: number, d: number, msg: Uint32Array, x: number) {\n // NOTE: V is LE here\n const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore\n let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; // prettier-ignore\n let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; // prettier-ignore\n let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; // prettier-ignore\n let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; // prettier-ignore\n // v[a] = (v[a] + v[b] + x) | 0;\n let ll = u64.add3L(Al, Bl, Xl);\n Ah = u64.add3H(ll, Ah, Bh, Xh);\n Al = ll | 0;\n // v[d] = rotr(v[d] ^ v[a], 16)\n ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al });\n ({ Dh, Dl } = { Dh: u64.rotrSH(Dh, Dl, 16), Dl: u64.rotrSL(Dh, Dl, 16) });\n // v[c] = (v[c] + v[d]) | 0;\n ({ h: Ch, l: Cl } = u64.add(Ch, Cl, Dh, Dl));\n // v[b] = rotr(v[b] ^ v[c], 63)\n ({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl });\n ({ Bh, Bl } = { Bh: u64.rotrBH(Bh, Bl, 63), Bl: u64.rotrBL(Bh, Bl, 63) });\n (BBUF[2 * a] = Al), (BBUF[2 * a + 1] = Ah);\n (BBUF[2 * b] = Bl), (BBUF[2 * b + 1] = Bh);\n (BBUF[2 * c] = Cl), (BBUF[2 * c + 1] = Ch);\n (BBUF[2 * d] = Dl), (BBUF[2 * d + 1] = Dh);\n}\n\nfunction checkBlake2Opts(\n outputLen: number,\n opts: Blake2Opts | undefined = {},\n keyLen: number,\n saltLen: number,\n persLen: number\n) {\n anumber(keyLen);\n if (outputLen < 0 || outputLen > keyLen) throw new Error('outputLen bigger than keyLen');\n const { key, salt, personalization } = opts;\n if (key !== undefined && (key.length < 1 || key.length > keyLen))\n throw new Error('key length must be undefined or 1..' + keyLen);\n if (salt !== undefined && salt.length !== saltLen)\n throw new Error('salt must be undefined or ' + saltLen);\n if (personalization !== undefined && personalization.length !== persLen)\n throw new Error('personalization must be undefined or ' + persLen);\n}\n\n/** Class, from which others are subclassed. */\nexport abstract class BLAKE2<T extends BLAKE2<T>> extends Hash<T> {\n protected abstract compress(msg: Uint32Array, offset: number, isLast: boolean): void;\n protected abstract get(): number[];\n protected abstract set(...args: number[]): void;\n abstract destroy(): void;\n protected buffer: Uint8Array;\n protected buffer32: Uint32Array;\n protected finished = false;\n protected destroyed = false;\n protected length: number = 0;\n protected pos: number = 0;\n readonly blockLen: number;\n readonly outputLen: number;\n\n constructor(blockLen: number, outputLen: number) {\n super();\n anumber(blockLen);\n anumber(outputLen);\n this.blockLen = blockLen;\n this.outputLen = outputLen;\n this.buffer = new Uint8Array(blockLen);\n this.buffer32 = u32(this.buffer);\n }\n update(data: Input): this {\n aexists(this);\n data = toBytes(data);\n abytes(data);\n // Main difference with other hashes: there is flag for last block,\n // so we cannot process current block before we know that there\n // is the next one. This significantly complicates logic and reduces ability\n // to do zero-copy processing\n const { blockLen, buffer, buffer32 } = this;\n const len = data.length;\n const offset = data.byteOffset;\n const buf = data.buffer;\n for (let pos = 0; pos < len; ) {\n // If buffer is full and we still have input (don't process last block, same as blake2s)\n if (this.pos === blockLen) {\n swap32IfBE(buffer32);\n this.compress(buffer32, 0, false);\n swap32IfBE(buffer32);\n this.pos = 0;\n }\n const take = Math.min(blockLen - this.pos, len - pos);\n const dataOffset = offset + pos;\n // full block && aligned to 4 bytes && not last in input\n if (take === blockLen && !(dataOffset % 4) && pos + take < len) {\n const data32 = new Uint32Array(buf, dataOffset, Math.floor((len - pos) / 4));\n swap32IfBE(data32);\n for (let pos32 = 0; pos + blockLen < len; pos32 += buffer32.length, pos += blockLen) {\n this.length += blockLen;\n this.compress(data32, pos32, false);\n }\n swap32IfBE(data32);\n continue;\n }\n buffer.set(data.subarray(pos, pos + take), this.pos);\n this.pos += take;\n this.length += take;\n pos += take;\n }\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n aoutput(out, this);\n const { pos, buffer32 } = this;\n this.finished = true;\n // Padding\n clean(this.buffer.subarray(pos));\n swap32IfBE(buffer32);\n this.compress(buffer32, 0, true);\n swap32IfBE(buffer32);\n const out32 = u32(out);\n this.get().forEach((v, i) => (out32[i] = swap8IfBE(v)));\n }\n digest(): Uint8Array {\n const { buffer, outputLen } = this;\n this.digestInto(buffer);\n const res = buffer.slice(0, outputLen);\n this.destroy();\n return res;\n }\n _cloneInto(to?: T): T {\n const { buffer, length, finished, destroyed, outputLen, pos } = this;\n to ||= new (this.constructor as any)({ dkLen: outputLen }) as T;\n to.set(...this.get());\n to.buffer.set(buffer);\n to.destroyed = destroyed;\n to.finished = finished;\n to.length = length;\n to.pos = pos;\n // @ts-ignore\n to.outputLen = outputLen;\n return to;\n }\n clone(): T {\n return this._cloneInto();\n }\n}\n\nexport class BLAKE2b extends BLAKE2<BLAKE2b> {\n // Same as SHA-512, but LE\n private v0l = B2B_IV[0] | 0;\n private v0h = B2B_IV[1] | 0;\n private v1l = B2B_IV[2] | 0;\n private v1h = B2B_IV[3] | 0;\n private v2l = B2B_IV[4] | 0;\n private v2h = B2B_IV[5] | 0;\n private v3l = B2B_IV[6] | 0;\n private v3h = B2B_IV[7] | 0;\n private v4l = B2B_IV[8] | 0;\n private v4h = B2B_IV[9] | 0;\n private v5l = B2B_IV[10] | 0;\n private v5h = B2B_IV[11] | 0;\n private v6l = B2B_IV[12] | 0;\n private v6h = B2B_IV[13] | 0;\n private v7l = B2B_IV[14] | 0;\n private v7h = B2B_IV[15] | 0;\n\n constructor(opts: Blake2Opts = {}) {\n const olen = opts.dkLen === undefined ? 64 : opts.dkLen;\n super(128, olen);\n checkBlake2Opts(olen, opts, 64, 16, 16);\n let { key, personalization, salt } = opts;\n let keyLength = 0;\n if (key !== undefined) {\n key = toBytes(key);\n keyLength = key.length;\n }\n this.v0l ^= this.outputLen | (keyLength << 8) | (0x01 << 16) | (0x01 << 24);\n if (salt !== undefined) {\n salt = toBytes(salt);\n const slt = u32(salt);\n this.v4l ^= swap8IfBE(slt[0]);\n this.v4h ^= swap8IfBE(slt[1]);\n this.v5l ^= swap8IfBE(slt[2]);\n this.v5h ^= swap8IfBE(slt[3]);\n }\n if (personalization !== undefined) {\n personalization = toBytes(personalization);\n const pers = u32(personalization);\n this.v6l ^= swap8IfBE(pers[0]);\n this.v6h ^= swap8IfBE(pers[1]);\n this.v7l ^= swap8IfBE(pers[2]);\n this.v7h ^= swap8IfBE(pers[3]);\n }\n if (key !== undefined) {\n // Pad to blockLen and update\n const tmp = new Uint8Array(this.blockLen);\n tmp.set(key);\n this.update(tmp);\n }\n }\n // prettier-ignore\n protected get(): [\n number, number, number, number, number, number, number, number,\n number, number, number, number, number, number, number, number\n ] {\n let { v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h } = this;\n return [v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h];\n }\n // prettier-ignore\n protected set(\n v0l: number, v0h: number, v1l: number, v1h: number,\n v2l: number, v2h: number, v3l: number, v3h: number,\n v4l: number, v4h: number, v5l: number, v5h: number,\n v6l: number, v6h: number, v7l: number, v7h: number\n ): void {\n this.v0l = v0l | 0;\n this.v0h = v0h | 0;\n this.v1l = v1l | 0;\n this.v1h = v1h | 0;\n this.v2l = v2l | 0;\n this.v2h = v2h | 0;\n this.v3l = v3l | 0;\n this.v3h = v3h | 0;\n this.v4l = v4l | 0;\n this.v4h = v4h | 0;\n this.v5l = v5l | 0;\n this.v5h = v5h | 0;\n this.v6l = v6l | 0;\n this.v6h = v6h | 0;\n this.v7l = v7l | 0;\n this.v7h = v7h | 0;\n }\n protected compress(msg: Uint32Array, offset: number, isLast: boolean): void {\n this.get().forEach((v, i) => (BBUF[i] = v)); // First half from state.\n BBUF.set(B2B_IV, 16); // Second half from IV.\n let { h, l } = u64.fromBig(BigInt(this.length));\n BBUF[24] = B2B_IV[8] ^ l; // Low word of the offset.\n BBUF[25] = B2B_IV[9] ^ h; // High word.\n // Invert all bits for last block\n if (isLast) {\n BBUF[28] = ~BBUF[28];\n BBUF[29] = ~BBUF[29];\n }\n let j = 0;\n const s = BSIGMA;\n for (let i = 0; i < 12; i++) {\n G1b(0, 4, 8, 12, msg, offset + 2 * s[j++]);\n G2b(0, 4, 8, 12, msg, offset + 2 * s[j++]);\n G1b(1, 5, 9, 13, msg, offset + 2 * s[j++]);\n G2b(1, 5, 9, 13, msg, offset + 2 * s[j++]);\n G1b(2, 6, 10, 14, msg, offset + 2 * s[j++]);\n G2b(2, 6, 10, 14, msg, offset + 2 * s[j++]);\n G1b(3, 7, 11, 15, msg, offset + 2 * s[j++]);\n G2b(3, 7, 11, 15, msg, offset + 2 * s[j++]);\n\n G1b(0, 5, 10, 15, msg, offset + 2 * s[j++]);\n G2b(0, 5, 10, 15, msg, offset + 2 * s[j++]);\n G1b(1, 6, 11, 12, msg, offset + 2 * s[j++]);\n G2b(1, 6, 11, 12, msg, offset + 2 * s[j++]);\n G1b(2, 7, 8, 13, msg, offset + 2 * s[j++]);\n G2b(2, 7, 8, 13, msg, offset + 2 * s[j++]);\n G1b(3, 4, 9, 14, msg, offset + 2 * s[j++]);\n G2b(3, 4, 9, 14, msg, offset + 2 * s[j++]);\n }\n this.v0l ^= BBUF[0] ^ BBUF[16];\n this.v0h ^= BBUF[1] ^ BBUF[17];\n this.v1l ^= BBUF[2] ^ BBUF[18];\n this.v1h ^= BBUF[3] ^ BBUF[19];\n this.v2l ^= BBUF[4] ^ BBUF[20];\n this.v2h ^= BBUF[5] ^ BBUF[21];\n this.v3l ^= BBUF[6] ^ BBUF[22];\n this.v3h ^= BBUF[7] ^ BBUF[23];\n this.v4l ^= BBUF[8] ^ BBUF[24];\n this.v4h ^= BBUF[9] ^ BBUF[25];\n this.v5l ^= BBUF[10] ^ BBUF[26];\n this.v5h ^= BBUF[11] ^ BBUF[27];\n this.v6l ^= BBUF[12] ^ BBUF[28];\n this.v6h ^= BBUF[13] ^ BBUF[29];\n this.v7l ^= BBUF[14] ^ BBUF[30];\n this.v7h ^= BBUF[15] ^ BBUF[31];\n clean(BBUF);\n }\n destroy(): void {\n this.destroyed = true;\n clean(this.buffer32);\n this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n }\n}\n\n/**\n * Blake2b hash function. 64-bit. 1.5x slower than blake2s in JS.\n * @param msg - message that would be hashed\n * @param opts - dkLen output length, key for MAC mode, salt, personalization\n */\nexport const blake2b: CHashO = /* @__PURE__ */ createOptHasher<BLAKE2b, Blake2Opts>(\n (opts) => new BLAKE2b(opts)\n);\n\n// =================\n// Blake2S\n// =================\n\n// prettier-ignore\nexport type Num16 = {\n v0: number; v1: number; v2: number; v3: number;\n v4: number; v5: number; v6: number; v7: number;\n v8: number; v9: number; v10: number; v11: number;\n v12: number; v13: number; v14: number; v15: number;\n};\n\n// prettier-ignore\nexport function compress(s: Uint8Array, offset: number, msg: Uint32Array, rounds: number,\n v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number,\n v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number,\n): Num16 {\n let j = 0;\n for (let i = 0; i < rounds; i++) {\n ({ a: v0, b: v4, c: v8, d: v12 } = G1s(v0, v4, v8, v12, msg[offset + s[j++]]));\n ({ a: v0, b: v4, c: v8, d: v12 } = G2s(v0, v4, v8, v12, msg[offset + s[j++]]));\n ({ a: v1, b: v5, c: v9, d: v13 } = G1s(v1, v5, v9, v13, msg[offset + s[j++]]));\n ({ a: v1, b: v5, c: v9, d: v13 } = G2s(v1, v5, v9, v13, msg[offset + s[j++]]));\n ({ a: v2, b: v6, c: v10, d: v14 } = G1s(v2, v6, v10, v14, msg[offset + s[j++]]));\n ({ a: v2, b: v6, c: v10, d: v14 } = G2s(v2, v6, v10, v14, msg[offset + s[j++]]));\n ({ a: v3, b: v7, c: v11, d: v15 } = G1s(v3, v7, v11, v15, msg[offset + s[j++]]));\n ({ a: v3, b: v7, c: v11, d: v15 } = G2s(v3, v7, v11, v15, msg[offset + s[j++]]));\n\n ({ a: v0, b: v5, c: v10, d: v15 } = G1s(v0, v5, v10, v15, msg[offset + s[j++]]));\n ({ a: v0, b: v5, c: v10, d: v15 } = G2s(v0, v5, v10, v15, msg[offset + s[j++]]));\n ({ a: v1, b: v6, c: v11, d: v12 } = G1s(v1, v6, v11, v12, msg[offset + s[j++]]));\n ({ a: v1, b: v6, c: v11, d: v12 } = G2s(v1, v6, v11, v12, msg[offset + s[j++]]));\n ({ a: v2, b: v7, c: v8, d: v13 } = G1s(v2, v7, v8, v13, msg[offset + s[j++]]));\n ({ a: v2, b: v7, c: v8, d: v13 } = G2s(v2, v7, v8, v13, msg[offset + s[j++]]));\n ({ a: v3, b: v4, c: v9, d: v14 } = G1s(v3, v4, v9, v14, msg[offset + s[j++]]));\n ({ a: v3, b: v4, c: v9, d: v14 } = G2s(v3, v4, v9, v14, msg[offset + s[j++]]));\n }\n return { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 };\n}\n\nconst B2S_IV = SHA256_IV;\nexport class BLAKE2s extends BLAKE2<BLAKE2s> {\n // Internal state, same as SHA-256\n private v0 = B2S_IV[0] | 0;\n private v1 = B2S_IV[1] | 0;\n private v2 = B2S_IV[2] | 0;\n private v3 = B2S_IV[3] | 0;\n private v4 = B2S_IV[4] | 0;\n private v5 = B2S_IV[5] | 0;\n private v6 = B2S_IV[6] | 0;\n private v7 = B2S_IV[7] | 0;\n\n constructor(opts: Blake2Opts = {}) {\n const olen = opts.dkLen === undefined ? 32 : opts.dkLen;\n super(64, olen);\n checkBlake2Opts(olen, opts, 32, 8, 8);\n let { key, personalization, salt } = opts;\n let keyLength = 0;\n if (key !== undefined) {\n key = toBytes(key);\n keyLength = key.length;\n }\n this.v0 ^= this.outputLen | (keyLength << 8) | (0x01 << 16) | (0x01 << 24);\n if (salt !== undefined) {\n salt = toBytes(salt);\n const slt = u32(salt as Uint8Array);\n this.v4 ^= swap8IfBE(slt[0]);\n this.v5 ^= swap8IfBE(slt[1]);\n }\n if (personalization !== undefined) {\n personalization = toBytes(personalization);\n const pers = u32(personalization as Uint8Array);\n this.v6 ^= swap8IfBE(pers[0]);\n this.v7 ^= swap8IfBE(pers[1]);\n }\n if (key !== undefined) {\n // Pad to blockLen and update\n abytes(key);\n const tmp = new Uint8Array(this.blockLen);\n tmp.set(key);\n this.update(tmp);\n }\n }\n protected get(): [number, number, number, number, number, number, number, number] {\n const { v0, v1, v2, v3, v4, v5, v6, v7 } = this;\n return [v0, v1, v2, v3, v4, v5, v6, v7];\n }\n // prettier-ignore\n protected set(\n v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number\n ): void {\n this.v0 = v0 | 0;\n this.v1 = v1 | 0;\n this.v2 = v2 | 0;\n this.v3 = v3 | 0;\n this.v4 = v4 | 0;\n this.v5 = v5 | 0;\n this.v6 = v6 | 0;\n this.v7 = v7 | 0;\n }\n protected compress(msg: Uint32Array, offset: number, isLast: boolean): void {\n const { h, l } = u64.fromBig(BigInt(this.length));\n // prettier-ignore\n const { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } =\n compress(\n BSIGMA, offset, msg, 10,\n this.v0, this.v1, this.v2, this.v3, this.v4, this.v5, this.v6, this.v7,\n B2S_IV[0], B2S_IV[1], B2S_IV[2], B2S_IV[3], l ^ B2S_IV[4], h ^ B2S_IV[5], isLast ? ~B2S_IV[6] : B2S_IV[6], B2S_IV[7]\n );\n this.v0 ^= v0 ^ v8;\n this.v1 ^= v1 ^ v9;\n this.v2 ^= v2 ^ v10;\n this.v3 ^= v3 ^ v11;\n this.v4 ^= v4 ^ v12;\n this.v5 ^= v5 ^ v13;\n this.v6 ^= v6 ^ v14;\n this.v7 ^= v7 ^ v15;\n }\n destroy(): void {\n this.destroyed = true;\n clean(this.buffer32);\n this.set(0, 0, 0, 0, 0, 0, 0, 0);\n }\n}\n\n/**\n * Blake2s hash function. Focuses on 8-bit to 32-bit platforms. 1.5x faster than blake2b in JS.\n * @param msg - message that would be hashed\n * @param opts - dkLen output length, key for MAC mode, salt, personalization\n */\nexport const blake2s: CHashO = /* @__PURE__ */ createOptHasher<BLAKE2s, Blake2Opts>(\n (opts) => new BLAKE2s(opts)\n);\n", "/**\n * Blake3 fast hash is Blake2 with reduced security (round count). Can also be used as MAC & KDF.\n *\n * It is advertised as \"the fastest cryptographic hash\". However, it isn't true in JS.\n * Why is this so slow? While it should be 6x faster than blake2b, perf diff is only 20%:\n *\n * * There is only 30% reduction in number of rounds from blake2s\n * * Speed-up comes from tree structure, which is parallelized using SIMD & threading.\n * These features are not present in JS, so we only get overhead from trees.\n * * Parallelization only happens on 1024-byte chunks: there is no benefit for small inputs.\n * * It is still possible to make it faster using: a) loop unrolling b) web workers c) wasm\n * @module\n */\nimport { SHA256_IV } from './_md.ts';\nimport { fromBig } from './_u64.ts';\nimport { BLAKE2, compress } from './blake2.ts';\n// prettier-ignore\nimport {\n abytes, aexists, anumber, aoutput,\n clean, createXOFer, swap32IfBE, toBytes, u32, u8,\n type CHashXO, type HashXOF, type Input\n} from './utils.ts';\n\n// Flag bitset\nconst B3_Flags = {\n CHUNK_START: 0b1,\n CHUNK_END: 0b10,\n PARENT: 0b100,\n ROOT: 0b1000,\n KEYED_HASH: 0b10000,\n DERIVE_KEY_CONTEXT: 0b100000,\n DERIVE_KEY_MATERIAL: 0b1000000,\n} as const;\n\nconst B3_IV = SHA256_IV.slice();\n\nconst B3_SIGMA: Uint8Array = /* @__PURE__ */ (() => {\n const Id = Array.from({ length: 16 }, (_, i) => i);\n const permute = (arr: number[]) =>\n [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8].map((i) => arr[i]);\n const res: number[] = [];\n for (let i = 0, v = Id; i < 7; i++, v = permute(v)) res.push(...v);\n return Uint8Array.from(res);\n})();\n\n/**\n * Ensure to use EITHER `key` OR `context`, not both.\n *\n * * `key`: 32-byte MAC key.\n * * `context`: string for KDF. Should be hardcoded, globally unique, and application - specific.\n * A good default format for the context string is \"[application] [commit timestamp] [purpose]\".\n */\nexport type Blake3Opts = { dkLen?: number; key?: Input; context?: Input };\n\n/** Blake3 hash. Can be used as MAC and KDF. */\nexport class BLAKE3 extends BLAKE2<BLAKE3> implements HashXOF<BLAKE3> {\n private chunkPos = 0; // Position of current block in chunk\n private chunksDone = 0; // How many chunks we already have\n private flags = 0 | 0;\n private IV: Uint32Array;\n private state: Uint32Array;\n private stack: Uint32Array[] = [];\n // Output\n private posOut = 0;\n private bufferOut32 = new Uint32Array(16);\n private bufferOut: Uint8Array;\n private chunkOut = 0; // index of output chunk\n private enableXOF = true;\n\n constructor(opts: Blake3Opts = {}, flags = 0) {\n super(64, opts.dkLen === undefined ? 32 : opts.dkLen);\n const { key, context } = opts;\n const hasContext = context !== undefined;\n if (key !== undefined) {\n if (hasContext) throw new Error('Only \"key\" or \"context\" can be specified at same time');\n const k = toBytes(key).slice();\n abytes(k, 32);\n this.IV = u32(k);\n swap32IfBE(this.IV);\n this.flags = flags | B3_Flags.KEYED_HASH;\n } else if (hasContext) {\n const ctx = toBytes(context);\n const contextKey = new BLAKE3({ dkLen: 32 }, B3_Flags.DERIVE_KEY_CONTEXT)\n .update(ctx)\n .digest();\n this.IV = u32(contextKey);\n swap32IfBE(this.IV);\n this.flags = flags | B3_Flags.DERIVE_KEY_MATERIAL;\n } else {\n this.IV = B3_IV.slice();\n this.flags = flags;\n }\n this.state = this.IV.slice();\n this.bufferOut = u8(this.bufferOut32);\n }\n // Unused\n protected get(): [] {\n return [];\n }\n protected set(): void {}\n private b2Compress(counter: number, flags: number, buf: Uint32Array, bufPos: number = 0) {\n const { state: s, pos } = this;\n const { h, l } = fromBig(BigInt(counter), true);\n // prettier-ignore\n const { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } =\n compress(\n B3_SIGMA, bufPos, buf, 7,\n s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7],\n B3_IV[0], B3_IV[1], B3_IV[2], B3_IV[3], h, l, pos, flags\n );\n s[0] = v0 ^ v8;\n s[1] = v1 ^ v9;\n s[2] = v2 ^ v10;\n s[3] = v3 ^ v11;\n s[4] = v4 ^ v12;\n s[5] = v5 ^ v13;\n s[6] = v6 ^ v14;\n s[7] = v7 ^ v15;\n }\n protected compress(buf: Uint32Array, bufPos: number = 0, isLast: boolean = false): void {\n // Compress last block\n let flags = this.flags;\n if (!this.chunkPos) flags |= B3_Flags.CHUNK_START;\n if (this.chunkPos === 15 || isLast) flags |= B3_Flags.CHUNK_END;\n if (!isLast) this.pos = this.blockLen;\n this.b2Compress(this.chunksDone, flags, buf, bufPos);\n this.chunkPos += 1;\n // If current block is last in chunk (16 blocks), then compress chunks\n if (this.chunkPos === 16 || isLast) {\n let chunk = this.state;\n this.state = this.IV.slice();\n // If not the last one, compress only when there are trailing zeros in chunk counter\n // chunks used as binary tree where current stack is path. Zero means current leaf is finished and can be compressed.\n // 1 (001) - leaf not finished (just push current chunk to stack)\n // 2 (010) - leaf finished at depth=1 (merge with last elm on stack and push back)\n // 3 (011) - last leaf not finished\n // 4 (100) - leafs finished at depth=1 and depth=2\n for (let last, chunks = this.chunksDone + 1; isLast || !(chunks & 1); chunks >>= 1) {\n if (!(last = this.stack.pop())) break;\n this.buffer32.set(last, 0);\n this.buffer32.set(chunk, 8);\n this.pos = this.blockLen;\n this.b2Compress(0, this.flags | B3_Flags.PARENT, this.buffer32, 0);\n chunk = this.state;\n this.state = this.IV.slice();\n }\n this.chunksDone++;\n this.chunkPos = 0;\n this.stack.push(chunk);\n }\n this.pos = 0;\n }\n _cloneInto(to?: BLAKE3): BLAKE3 {\n to = super._cloneInto(to) as BLAKE3;\n const { IV, flags, state, chunkPos, posOut, chunkOut, stack, chunksDone } = this;\n to.state.set(state.slice());\n to.stack = stack.map((i) => Uint32Array.from(i));\n to.IV.set(IV);\n to.flags = flags;\n to.chunkPos = chunkPos;\n to.chunksDone = chunksDone;\n to.posOut = posOut;\n to.chunkOut = chunkOut;\n to.enableXOF = this.enableXOF;\n to.bufferOut32.set(this.bufferOut32);\n return to;\n }\n destroy(): void {\n this.destroyed = true;\n clean(this.state, this.buffer32, this.IV, this.bufferOut32);\n clean(...this.stack);\n }\n // Same as b2Compress, but doesn't modify state and returns 16 u32 array (instead of 8)\n private b2CompressOut() {\n const { state: s, pos, flags, buffer32, bufferOut32: out32 } = this;\n const { h, l } = fromBig(BigInt(this.chunkOut++));\n swap32IfBE(buffer32);\n // prettier-ignore\n const { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } =\n compress(\n B3_SIGMA, 0, buffer32, 7,\n s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7],\n B3_IV[0], B3_IV[1], B3_IV[2], B3_IV[3], l, h, pos, flags\n );\n out32[0] = v0 ^ v8;\n out32[1] = v1 ^ v9;\n out32[2] = v2 ^ v10;\n out32[3] = v3 ^ v11;\n out32[4] = v4 ^ v12;\n out32[5] = v5 ^ v13;\n out32[6] = v6 ^ v14;\n out32[7] = v7 ^ v15;\n out32[8] = s[0] ^ v8;\n out32[9] = s[1] ^ v9;\n out32[10] = s[2] ^ v10;\n out32[11] = s[3] ^ v11;\n out32[12] = s[4] ^ v12;\n out32[13] = s[5] ^ v13;\n out32[14] = s[6] ^ v14;\n out32[15] = s[7] ^ v15;\n swap32IfBE(buffer32);\n swap32IfBE(out32);\n this.posOut = 0;\n }\n protected finish(): void {\n if (this.finished) return;\n this.finished = true;\n // Padding\n clean(this.buffer.subarray(this.pos));\n // Process last chunk\n let flags = this.flags | B3_Flags.ROOT;\n if (this.stack.length) {\n flags |= B3_Flags.PARENT;\n swap32IfBE(this.buffer32);\n this.compress(this.buffer32, 0, true);\n swap32IfBE(this.buffer32);\n this.chunksDone = 0;\n this.pos = this.blockLen;\n } else {\n flags |= (!this.chunkPos ? B3_Flags.CHUNK_START : 0) | B3_Flags.CHUNK_END;\n }\n this.flags = flags;\n this.b2CompressOut();\n }\n private writeInto(out: Uint8Array) {\n aexists(this, false);\n abytes(out);\n this.finish();\n const { blockLen, bufferOut } = this;\n for (let pos = 0, len = out.length; pos < len; ) {\n if (this.posOut >= blockLen) this.b2CompressOut();\n const take = Math.min(blockLen - this.posOut, len - pos);\n out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);\n this.posOut += take;\n pos += take;\n }\n return out;\n }\n xofInto(out: Uint8Array): Uint8Array {\n if (!this.enableXOF) throw new Error('XOF is not possible after digest call');\n return this.writeInto(out);\n }\n xof(bytes: number): Uint8Array {\n anumber(bytes);\n return this.xofInto(new Uint8Array(bytes));\n }\n digestInto(out: Uint8Array): Uint8Array {\n aoutput(out, this);\n if (this.finished) throw new Error('digest() was already called');\n this.enableXOF = false;\n this.writeInto(out);\n this.destroy();\n return out;\n }\n digest(): Uint8Array {\n return this.digestInto(new Uint8Array(this.outputLen));\n }\n}\n\n/**\n * BLAKE3 hash function. Can be used as MAC and KDF.\n * @param msg - message that would be hashed\n * @param opts - `dkLen` for output length, `key` for MAC mode, `context` for KDF mode\n * @example\n * const data = new Uint8Array(32);\n * const hash = blake3(data);\n * const mac = blake3(data, { key: new Uint8Array(32) });\n * const kdf = blake3(data, { context: 'application name' });\n */\nexport const blake3: CHashXO = /* @__PURE__ */ createXOFer<BLAKE3, Blake3Opts>(\n (opts) => new BLAKE3(opts)\n);\n", "import { blake3 } from '@noble/hashes/blake3'\n\nexport const SOURCE_AUTH_MANIFEST_VERSION = 1\nexport const SOURCE_AUTH_OBJECT_ENTRY_FRAME = 1\nexport const SOURCE_AUTH_GROUP_CLOSE_FRAME = 2\nexport const SOURCE_AUTH_OBJECT_ENTRY_LENGTH = 52\nexport const SOURCE_AUTH_GROUP_CLOSE_LENGTH = 112\nexport const SOURCE_AUTH_MAX_OBJECTS_PER_GROUP = 4096\nexport const SOURCE_AUTH_MAX_TRUE_LENGTH = 16 * 1024 * 1024\nexport const SOURCE_AUTH_SCOPE_LENGTH = 32\n\nconst SIGNATURE_DOMAIN = new TextEncoder().encode('blockcast-mmt-root-v1\\0\\0\\0')\n\nexport interface SourceAuthObjectEntry {\n kind: 'object'\n groupId: bigint\n objectId: number\n trueLength: number\n digest: Uint8Array\n}\n\nexport interface SourceAuthGroupClose {\n kind: 'close'\n groupId: bigint\n objectCount: number\n root: Uint8Array\n signature: Uint8Array\n}\n\nexport type SourceAuthManifestFrame = SourceAuthObjectEntry | SourceAuthGroupClose\n\nfunction requireBytes(name: string, value: Uint8Array, length: number): void {\n if (value.byteLength !== length) {\n throw new Error(`${name} must be ${length} bytes, got ${value.byteLength}`)\n }\n}\n\nfunction requireU32(name: string, value: number): void {\n if (!Number.isInteger(value) || value < 0 || value > 0xffff_ffff) {\n throw new Error(`${name} must be an unsigned 32-bit integer`)\n }\n}\n\nfunction requireU64(name: string, value: bigint): void {\n if (value < 0n || value > 0xffff_ffff_ffff_ffffn) {\n throw new Error(`${name} must be an unsigned 64-bit integer`)\n }\n}\n\nfunction requireTrueLength(value: number): void {\n requireU32('trueLength', value)\n if (value > SOURCE_AUTH_MAX_TRUE_LENGTH) {\n throw new Error(`trueLength exceeds the ${SOURCE_AUTH_MAX_TRUE_LENGTH}-byte profile maximum`)\n }\n}\n\nexport function sourceAuthObjectDigest(object: Uint8Array): Uint8Array {\n return blake3(object)\n}\n\nexport function sourceAuthLeafHash(\n groupId: bigint,\n objectId: number,\n digest: Uint8Array,\n trueLength: number,\n): Uint8Array {\n requireU64('groupId', groupId)\n requireU32('objectId', objectId)\n requireBytes('digest', digest, 32)\n requireTrueLength(trueLength)\n const preimage = new Uint8Array(49)\n const view = new DataView(preimage.buffer)\n view.setBigUint64(1, groupId)\n view.setUint32(9, objectId)\n preimage.set(digest, 13)\n view.setUint32(45, trueLength)\n return blake3(preimage)\n}\n\nexport function sourceAuthMerkleRoot(\n entries: readonly {\n groupId: bigint\n objectId: number\n digest: Uint8Array\n trueLength: number\n }[],\n): Uint8Array {\n if (entries.length === 0) throw new Error('Merkle tree requires at least one object')\n if (entries.length > SOURCE_AUTH_MAX_OBJECTS_PER_GROUP) {\n throw new Error(`group exceeds ${SOURCE_AUTH_MAX_OBJECTS_PER_GROUP} objects`)\n }\n const groupId = entries[0]!.groupId\n const objectIds = new Set<number>()\n const ordered = [...entries].sort((left, right) => left.objectId - right.objectId)\n let level = ordered.map((entry) => {\n if (entry.groupId !== groupId) throw new Error('Merkle entries must belong to one group')\n if (objectIds.has(entry.objectId)) throw new Error(`duplicate objectId ${entry.objectId}`)\n objectIds.add(entry.objectId)\n return sourceAuthLeafHash(entry.groupId, entry.objectId, entry.digest, entry.trueLength)\n })\n while (level.length > 1) {\n const parents: Uint8Array[] = []\n for (let index = 0; index < level.length; index += 2) {\n const left = level[index]!\n const right = level[index + 1] ?? left\n const preimage = new Uint8Array(65)\n preimage[0] = 1\n preimage.set(left, 1)\n preimage.set(right, 33)\n parents.push(blake3(preimage))\n }\n level = parents\n }\n return level[0]!\n}\n\nexport function trimRecoveredSourceAuthObject(\n recoveredSymbol: Uint8Array,\n trueLength: number,\n): Uint8Array {\n requireTrueLength(trueLength)\n if (trueLength > recoveredSymbol.byteLength) {\n throw new Error(`true length ${trueLength} exceeds recovered object size ${recoveredSymbol.byteLength}`)\n }\n return recoveredSymbol.subarray(0, trueLength)\n}\n\nexport function encodeSourceAuthObjectEntry(\n entry: Omit<SourceAuthObjectEntry, 'kind'>,\n): Uint8Array {\n requireU32('objectId', entry.objectId)\n requireTrueLength(entry.trueLength)\n requireU64('groupId', entry.groupId)\n requireBytes('digest', entry.digest, 32)\n const frame = new Uint8Array(SOURCE_AUTH_OBJECT_ENTRY_LENGTH)\n const view = new DataView(frame.buffer)\n frame[0] = SOURCE_AUTH_OBJECT_ENTRY_FRAME\n frame[1] = SOURCE_AUTH_MANIFEST_VERSION\n view.setBigUint64(4, entry.groupId)\n view.setUint32(12, entry.objectId)\n view.setUint32(16, entry.trueLength)\n frame.set(entry.digest, 20)\n return frame\n}\n\nexport function encodeSourceAuthGroupClose(\n close: Omit<SourceAuthGroupClose, 'kind'>,\n): Uint8Array {\n requireU32('objectCount', close.objectCount)\n if (close.objectCount === 0 || close.objectCount > SOURCE_AUTH_MAX_OBJECTS_PER_GROUP) {\n throw new Error(`objectCount must be between 1 and ${SOURCE_AUTH_MAX_OBJECTS_PER_GROUP}`)\n }\n requireU64('groupId', close.groupId)\n requireBytes('root', close.root, 32)\n requireBytes('signature', close.signature, 64)\n const frame = new Uint8Array(SOURCE_AUTH_GROUP_CLOSE_LENGTH)\n const view = new DataView(frame.buffer)\n frame[0] = SOURCE_AUTH_GROUP_CLOSE_FRAME\n frame[1] = SOURCE_AUTH_MANIFEST_VERSION\n view.setBigUint64(4, close.groupId)\n view.setUint32(12, close.objectCount)\n frame.set(close.root, 16)\n frame.set(close.signature, 48)\n return frame\n}\n\nexport function sourceAuthSignaturePreimage(\n authScope: Uint8Array,\n groupId: bigint,\n objectCount: number,\n root: Uint8Array,\n): Uint8Array {\n requireU32('objectCount', objectCount)\n if (objectCount === 0 || objectCount > SOURCE_AUTH_MAX_OBJECTS_PER_GROUP) {\n throw new Error(`objectCount must be between 1 and ${SOURCE_AUTH_MAX_OBJECTS_PER_GROUP}`)\n }\n requireU64('groupId', groupId)\n requireBytes('authScope', authScope, SOURCE_AUTH_SCOPE_LENGTH)\n requireBytes('root', root, 32)\n const preimage = new Uint8Array(100)\n const view = new DataView(preimage.buffer)\n preimage.set(SIGNATURE_DOMAIN)\n preimage.set(authScope, 24)\n view.setBigUint64(56, groupId)\n view.setUint32(64, objectCount)\n preimage.set(root, 68)\n return preimage\n}\n\nexport function decodeSourceAuthManifestFrame(frame: Uint8Array): SourceAuthManifestFrame {\n const frameType = frame[0]\n const expectedLength = frameType === SOURCE_AUTH_OBJECT_ENTRY_FRAME\n ? SOURCE_AUTH_OBJECT_ENTRY_LENGTH\n : frameType === SOURCE_AUTH_GROUP_CLOSE_FRAME\n ? SOURCE_AUTH_GROUP_CLOSE_LENGTH\n : 0\n if (expectedLength === 0) throw new Error(`unsupported manifest frame type ${frameType}`)\n if (frame.byteLength !== expectedLength) {\n throw new Error(`manifest frame has invalid length ${frame.byteLength} for type ${frameType}`)\n }\n if (frame[1] !== SOURCE_AUTH_MANIFEST_VERSION) {\n throw new Error(`unsupported manifest version ${frame[1]}`)\n }\n if (frame[2] !== 0 || frame[3] !== 0) throw new Error('manifest reserved bits must be zero')\n\n const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength)\n const groupId = view.getBigUint64(4)\n if (frameType === SOURCE_AUTH_OBJECT_ENTRY_FRAME) {\n const entry: SourceAuthObjectEntry = {\n kind: 'object',\n groupId,\n objectId: view.getUint32(12),\n trueLength: view.getUint32(16),\n digest: frame.slice(20, 52),\n }\n requireTrueLength(entry.trueLength)\n return entry\n }\n const close: SourceAuthGroupClose = {\n kind: 'close',\n groupId,\n objectCount: view.getUint32(12),\n root: frame.slice(16, 48),\n signature: frame.slice(48, 112),\n }\n if (close.objectCount === 0 || close.objectCount > SOURCE_AUTH_MAX_OBJECTS_PER_GROUP) {\n throw new Error(`objectCount must be between 1 and ${SOURCE_AUTH_MAX_OBJECTS_PER_GROUP}`)\n }\n return close\n}\n", "import {\n decodeSourceAuthManifestFrame,\n sourceAuthMerkleRoot,\n sourceAuthObjectDigest,\n sourceAuthSignaturePreimage,\n type SourceAuthGroupClose,\n type SourceAuthObjectEntry,\n} from './source-auth.js'\n\nexport type ManifestAuthMode = 'off' | 'shadow' | 'enforce'\nexport type MissingManifestPolicy = 'stall' | 'fallback-shadow'\nexport type ManifestFailureReason =\n | 'sigInvalid'\n | 'digestMismatch'\n | 'manifestLate'\n | 'manifestAbsent'\n | 'verifierError'\n\nexport interface ManifestAuthConfig {\n mode: ManifestAuthMode\n onMissingManifest: MissingManifestPolicy\n}\n\nexport interface ManifestObjectIdentity {\n trackName: string\n /** Stable v2 auth binding. Defaults to trackName for legacy single-format callers. */\n bindingId?: string\n /** MoQ group ids are u62; values above 2^53 must be passed as bigint. */\n groupId: number | bigint\n objectId: number\n packetId?: number\n ssId?: number\n}\n\nexport interface ManifestFecBlockMapper {\n readonly d: number\n derive(groupId: number, objectId: number): { ssId: number }\n}\n\nexport interface ManifestTrackContext {\n broadcastNamespaceId: string\n trackName: string\n /** Stable v2 auth binding. Defaults to trackName for legacy single-format callers. */\n bindingId?: string\n sourceSymbolFormat?: string\n keyEpoch: number\n codec: string\n timing: string\n fecGeometry: string\n manifestFormatVersion: number\n /** Authenticated-catalog binding for the namespace, track, epoch, codec,\n * timing, FEC geometry, and manifest version fields above. */\n authScope: Uint8Array\n publicKey: Uint8Array\n /** Current key first, followed by any catalog-advertised overlap keys. */\n acceptedPublicKeys?: readonly Uint8Array[]\n bitrate: number\n groupDurationMs: number\n mapper: ManifestFecBlockMapper\n manifestChannelAuthenticated: boolean\n}\n\nexport interface ManifestVerificationStats {\n verified: number\n /** Terminal outcomes only: an object counted here will never be verified. */\n failures: Record<ManifestFailureReason, number>\n /**\n * Objects currently held in quarantine awaiting a manifest \u2014 pending, NOT\n * failed, and deliberately disjoint from `failures`. An enforce-mode stall is\n * accounted here first and moves into `failures` only once the verifier gives\n * up on it, so a reason breakdown that ignores this gauge under-reports live\n * stalls by whatever is still in flight (BLO-30007).\n */\n quarantined: number\n quarantinedBytes: number\n}\n\nexport interface ManifestFailure {\n trackName: string\n bindingId?: string\n groupId: number | bigint\n objectId: number\n reason: ManifestFailureReason\n}\n\nexport interface ManifestAdmission {\n action: 'play' | 'stall' | 'drop'\n verified: boolean\n reason?: ManifestFailureReason\n}\n\nexport type SignatureVerifier = (\n publicKey: Uint8Array,\n message: Uint8Array,\n signature: Uint8Array,\n) => boolean | Promise<boolean>\n\nexport function manifestBindingId(trackName: string, sourceSymbolFormat: string): string {\n return JSON.stringify([trackName, sourceSymbolFormat])\n}\n\nexport function createWebCryptoEd25519Verifier(\n subtle: SubtleCrypto = globalThis.crypto.subtle,\n): SignatureVerifier {\n return async (publicKey, message, signature) => {\n const keyBytes = Uint8Array.from(publicKey)\n const messageBytes = Uint8Array.from(message)\n const signatureBytes = Uint8Array.from(signature)\n const key = await subtle.importKey('raw', keyBytes.buffer, 'Ed25519', false, ['verify'])\n return subtle.verify('Ed25519', key, signatureBytes.buffer, messageBytes.buffer)\n }\n}\n\ninterface PendingObject {\n identity: ManifestObjectIdentity\n data: Uint8Array\n release: () => void\n bytes: number\n}\n\ninterface GroupState {\n entries: Map<number, SourceAuthObjectEntry>\n pending: Map<number, PendingObject>\n close?: SourceAuthGroupClose\n /** Close frame that arrived before all object entries (manifest-channel\n * reordering); retried once the entry count matches. */\n pendingClose?: SourceAuthGroupClose\n rootVerified: boolean\n signaturePending?: boolean\n failed?: ManifestFailureReason\n}\n\ninterface TrackState {\n context: ManifestTrackContext\n groups: Map<bigint, GroupState>\n quarantine: PendingObject[]\n quarantinedBytes: number\n capBytes: number\n manifestEntries: number\n maxManifestEntries: number\n maxGroups: number\n}\n\nconst FAILURE_REASONS: readonly ManifestFailureReason[] = [\n 'sigInvalid',\n 'digestMismatch',\n 'manifestLate',\n 'manifestAbsent',\n 'verifierError',\n]\n\nconst equalBytes = (left: Uint8Array, right: Uint8Array): boolean => {\n if (left.byteLength !== right.byteLength) return false\n let diff = 0\n for (let index = 0; index < left.byteLength; index++) diff |= left[index]! ^ right[index]!\n return diff === 0\n}\n\nconst isPromiseLike = (value: boolean | Promise<boolean>): value is Promise<boolean> =>\n typeof value === 'object' && value !== null && typeof value.then === 'function'\n\nexport class ManifestVerifier {\n #config: ManifestAuthConfig\n readonly #verifySignature: SignatureVerifier\n readonly #onFailure?: (failure: ManifestFailure) => void\n readonly #tracks = new Map<string, TrackState>()\n readonly #stats: Omit<ManifestVerificationStats, 'quarantined'> = {\n verified: 0,\n failures: Object.fromEntries(FAILURE_REASONS.map((reason) => [reason, 0])) as Record<ManifestFailureReason, number>,\n quarantinedBytes: 0,\n }\n #disposed = false\n\n constructor(options: {\n manifestAuth: ManifestAuthConfig\n verifySignature: SignatureVerifier\n onFailure?: (failure: ManifestFailure) => void\n }) {\n this.#config = { ...options.manifestAuth }\n this.#verifySignature = options.verifySignature\n this.#onFailure = options.onFailure\n }\n\n get config(): Readonly<ManifestAuthConfig> {\n return this.#config\n }\n\n get stats(): ManifestVerificationStats {\n let quarantined = 0\n for (const track of this.#tracks.values()) quarantined += track.quarantine.length\n return {\n verified: this.#stats.verified,\n failures: { ...this.#stats.failures },\n quarantined,\n quarantinedBytes: this.#stats.quarantinedBytes,\n }\n }\n\n setMode(mode: ManifestAuthMode): void {\n this.#config = { ...this.#config, mode }\n if (mode !== 'enforce') this.#releaseAllQuarantine(false)\n }\n\n registerTrack(context: ManifestTrackContext): void {\n const bindingId = context.bindingId ?? context.trackName\n if (this.#tracks.has(bindingId)) {\n throw new Error(`manifest binding ${bindingId} is already registered`)\n }\n if (!Number.isFinite(context.bitrate) || context.bitrate <= 0) {\n throw new Error('manifest track bitrate must be > 0')\n }\n if (!Number.isFinite(context.groupDurationMs) || context.groupDurationMs <= 0) {\n throw new Error('manifest track groupDurationMs must be > 0')\n }\n if (context.authScope.byteLength !== 32) throw new Error('manifest authScope must be 32 bytes')\n if (context.publicKey.byteLength !== 32) throw new Error('manifest publicKey must be 32 bytes')\n for (const key of context.acceptedPublicKeys ?? []) {\n if (key.byteLength !== 32) throw new Error('manifest acceptedPublicKeys must contain 32-byte keys')\n }\n for (const [name, value] of Object.entries({\n broadcastNamespaceId: context.broadcastNamespaceId,\n trackName: context.trackName,\n codec: context.codec,\n timing: context.timing,\n fecGeometry: context.fecGeometry,\n })) {\n if (value.length === 0) throw new Error(`manifest ${name} must not be empty`)\n }\n this.#tracks.set(bindingId, {\n context: { ...context, bindingId },\n groups: new Map(),\n quarantine: [],\n quarantinedBytes: 0,\n capBytes: Math.ceil((context.bitrate * context.groupDurationMs) / 8000),\n manifestEntries: 0,\n maxManifestEntries: Math.ceil((context.bitrate * context.groupDurationMs) / (8000 * 52)),\n maxGroups: context.mapper.d + 1,\n })\n }\n\n ingestManifestFrame(bindingId: string, frameBytes: Uint8Array): void {\n const track = this.#requireTrack(bindingId)\n try {\n const frame = decodeSourceAuthManifestFrame(frameBytes)\n const groupId = frame.groupId\n const group = this.#group(track, groupId)\n if (frame.kind === 'object') {\n if (group.close || group.signaturePending || group.failed) {\n this.#failure({ trackName: track.context.trackName, bindingId, groupId, objectId: frame.objectId }, 'verifierError')\n return\n }\n if (group.entries.has(frame.objectId)) {\n this.#failure({ trackName: track.context.trackName, bindingId, groupId, objectId: frame.objectId }, 'verifierError')\n return\n }\n if (group.entries.size >= 4096 || track.manifestEntries >= track.maxManifestEntries) {\n this.#failure({ trackName: track.context.trackName, bindingId, groupId, objectId: frame.objectId }, 'verifierError')\n return\n }\n group.entries.set(frame.objectId, frame)\n track.manifestEntries++\n const pending = group.pending.get(frame.objectId)\n if (pending) {\n this.#failure(pending.identity, 'manifestLate')\n this.#resolvePending(track, group, pending, frame)\n }\n if (group.pendingClose && group.entries.size === group.pendingClose.objectCount) {\n const close = group.pendingClose\n group.pendingClose = undefined\n this.#closeGroup(track, groupId, group, close)\n }\n return\n }\n this.#closeGroup(track, groupId, group, frame)\n } catch {\n this.#failure({ trackName: track.context.trackName, bindingId, groupId: 0, objectId: 0 }, 'verifierError')\n }\n }\n\n admitObject(\n identity: ManifestObjectIdentity,\n data: Uint8Array,\n release: () => void,\n ): ManifestAdmission {\n if (this.#config.mode === 'off') {\n release()\n return { action: 'play', verified: false }\n }\n const track = this.#tracks.get(identity.bindingId ?? identity.trackName)\n if (!track) {\n release()\n this.#failure(identity, 'verifierError')\n return { action: 'play', verified: false, reason: 'verifierError' }\n }\n try {\n if (!this.#validateIdentity(track, identity)) {\n return this.#rejectOrShadow(identity, release, 'digestMismatch')\n }\n const group = this.#group(track, BigInt(identity.groupId))\n if (group.failed === 'sigInvalid' || group.failed === 'digestMismatch') {\n return this.#rejectOrShadow(identity, release, group.failed)\n }\n const entry = group.entries.get(identity.objectId)\n if (entry) return this.#admitAgainstEntry(track, group, identity, data, release, entry)\n if (this.#config.mode === 'shadow' || this.#config.onMissingManifest === 'fallback-shadow') {\n release()\n this.#failure(identity, 'manifestAbsent')\n return { action: 'play', verified: false, reason: 'manifestAbsent' }\n }\n if (!this.#quarantine(track, group, { identity, data, release, bytes: data.byteLength })) {\n return { action: 'drop', verified: false }\n }\n return { action: 'stall', verified: false }\n } catch {\n release()\n this.#failure(identity, 'verifierError')\n return { action: 'play', verified: false, reason: 'verifierError' }\n }\n }\n\n dispose(): void {\n if (this.#disposed) return\n this.#disposed = true\n this.#releaseAllQuarantine(false)\n this.#tracks.clear()\n }\n\n #requireTrack(bindingId: string): TrackState {\n const track = this.#tracks.get(bindingId)\n if (!track) throw new Error(`unknown manifest binding ${bindingId}`)\n return track\n }\n\n #group(track: TrackState, groupId: bigint): GroupState {\n let group = track.groups.get(groupId)\n if (!group) {\n group = { entries: new Map(), pending: new Map(), rootVerified: false }\n track.groups.set(groupId, group)\n while (track.groups.size > track.maxGroups) {\n const oldest = track.groups.entries().next().value as [bigint, GroupState] | undefined\n if (!oldest) break\n const [oldestId, oldestGroup] = oldest\n for (const pending of [...oldestGroup.pending.values()]) {\n this.#removePending(track, oldestGroup, pending)\n pending.release()\n // The group aged out with objects still waiting on a manifest that\n // never arrived. That is an absent manifest, not a verifier fault:\n // `verifierError` is reserved for an exception/crash in the verifier\n // itself, so mislabelling here reads on the graduation dashboard as a\n // software bug and hides a benign absent-manifest stall (BLO-30007).\n this.#failure(pending.identity, 'manifestAbsent')\n }\n track.manifestEntries -= oldestGroup.entries.size\n track.groups.delete(oldestId)\n }\n }\n return group\n }\n\n #validateIdentity(track: TrackState, identity: ManifestObjectIdentity): boolean {\n const coordinates = track.context.mapper.derive(Number(identity.groupId), identity.objectId)\n return identity.ssId === undefined || coordinates.ssId === identity.ssId\n }\n\n #admitAgainstEntry(\n track: TrackState,\n group: GroupState,\n identity: ManifestObjectIdentity,\n data: Uint8Array,\n release: () => void,\n entry: SourceAuthObjectEntry,\n ): ManifestAdmission {\n if (entry.trueLength !== data.byteLength) {\n return this.#rejectOrShadow(identity, release, 'digestMismatch')\n }\n const digestMatches = equalBytes(sourceAuthObjectDigest(data.subarray(0, entry.trueLength)), entry.digest)\n if (!digestMatches) return this.#rejectOrShadow(identity, release, 'digestMismatch')\n if (!track.context.manifestChannelAuthenticated && !group.rootVerified) {\n if (this.#config.mode === 'shadow') {\n release()\n return { action: 'play', verified: false }\n }\n if (!this.#quarantine(track, group, { identity, data, release, bytes: data.byteLength })) {\n return { action: 'drop', verified: false }\n }\n return { action: 'stall', verified: false }\n }\n release()\n this.#stats.verified++\n return { action: 'play', verified: true }\n }\n\n #rejectOrShadow(\n identity: ManifestObjectIdentity,\n release: () => void,\n reason: 'digestMismatch' | 'sigInvalid',\n ): ManifestAdmission {\n this.#failure(identity, reason)\n if (this.#config.mode === 'enforce') {\n console.warn(JSON.stringify({ event: 'manifest-enforce-drop', track: identity.trackName, group: String(identity.groupId), object: identity.objectId, reason }))\n return { action: 'drop', verified: false, reason }\n }\n release()\n return { action: 'play', verified: false, reason }\n }\n\n #resolvePending(\n track: TrackState,\n group: GroupState,\n pending: PendingObject,\n entry: SourceAuthObjectEntry,\n ): void {\n this.#removePending(track, group, pending)\n this.#admitAgainstEntry(track, group, pending.identity, pending.data, pending.release, entry)\n }\n\n #closeGroup(\n track: TrackState,\n groupId: bigint,\n group: GroupState,\n close: SourceAuthGroupClose,\n ): void {\n if (group.close || group.signaturePending) return\n const entries = [...group.entries.values()]\n if (entries.length !== close.objectCount) {\n // Manifest-channel reordering: the close frame beat some object entries.\n // Stash it (latest-wins on duplicates) so the object-entry path can\n // re-attempt the close once the count matches; quarantined objects stay\n // quarantined, and manifestAbsent below is a signal, not an eviction.\n group.pendingClose = close\n const hadPending = group.pending.size > 0\n if (this.#config.onMissingManifest === 'fallback-shadow' || this.#config.mode === 'shadow') {\n for (const pending of [...group.pending.values()]) {\n this.#removePending(track, group, pending)\n pending.release()\n this.#failure(pending.identity, 'manifestAbsent')\n }\n } else {\n for (const pending of group.pending.values()) {\n this.#failure(pending.identity, 'manifestAbsent')\n }\n }\n if (!hadPending) {\n this.#failure({ trackName: track.context.trackName, groupId, objectId: 0 }, 'manifestAbsent')\n }\n return\n }\n if (!equalBytes(sourceAuthMerkleRoot(entries), close.root)) {\n group.failed = 'digestMismatch'\n this.#failGroup(track, groupId, group, 'digestMismatch')\n return\n }\n const preimage = sourceAuthSignaturePreimage(track.context.authScope, close.groupId, close.objectCount, close.root)\n let signatureValid: boolean | Promise<boolean>\n try {\n signatureValid = this.#verifyAcceptedSignature(track, preimage, close.signature)\n } catch {\n this.#failOpenGroup(track, groupId, group)\n return\n }\n if (isPromiseLike(signatureValid)) {\n group.signaturePending = true\n void signatureValid.then(\n (valid) => {\n if (this.#disposed) return\n group.signaturePending = false\n this.#finishGroupSignature(track, groupId, group, close, valid)\n },\n () => {\n if (this.#disposed) return\n group.signaturePending = false\n this.#failOpenGroup(track, groupId, group)\n },\n )\n return\n }\n this.#finishGroupSignature(track, groupId, group, close, signatureValid)\n }\n\n #finishGroupSignature(\n track: TrackState,\n groupId: bigint,\n group: GroupState,\n close: SourceAuthGroupClose,\n signatureValid: boolean,\n ): void {\n if (!signatureValid) {\n group.failed = 'sigInvalid'\n this.#failGroup(track, groupId, group, 'sigInvalid')\n return\n }\n group.failed = undefined\n group.close = close\n group.pendingClose = undefined\n group.rootVerified = true\n for (const pending of [...group.pending.values()]) {\n const entry = group.entries.get(pending.identity.objectId)\n if (entry) this.#resolvePending(track, group, pending, entry)\n else if (this.#config.onMissingManifest === 'fallback-shadow') {\n this.#removePending(track, group, pending)\n pending.release()\n this.#failure(pending.identity, 'manifestAbsent')\n }\n }\n }\n\n #verifyAcceptedSignature(\n track: TrackState,\n message: Uint8Array,\n signature: Uint8Array,\n ): boolean | Promise<boolean> {\n const keys = track.context.acceptedPublicKeys ?? [track.context.publicKey]\n const pending: Promise<boolean | 'error'>[] = []\n let hadSynchronousError = false\n for (const key of keys) {\n try {\n const result = this.#verifySignature(key, message, signature)\n if (isPromiseLike(result)) {\n pending.push(Promise.resolve(result).then((valid) => valid, () => 'error' as const))\n } else if (result) {\n return true\n }\n } catch {\n hadSynchronousError = true\n }\n }\n if (pending.length === 0) {\n if (hadSynchronousError) throw new Error('manifest signature verifier unavailable')\n return false\n }\n return Promise.all(pending).then((results) => {\n if (results.some((valid) => valid === true)) return true\n if (hadSynchronousError || results.some((valid) => valid === 'error')) {\n throw new Error('manifest signature verifier unavailable')\n }\n return false\n })\n }\n\n #failGroup(\n track: TrackState,\n groupId: bigint,\n group: GroupState,\n reason: 'digestMismatch' | 'sigInvalid',\n ): void {\n if (group.pending.size === 0) {\n this.#failure({ trackName: track.context.trackName, groupId, objectId: 0 }, reason)\n return\n }\n for (const pending of [...group.pending.values()]) {\n this.#removePending(track, group, pending)\n this.#rejectOrShadow(pending.identity, pending.release, reason)\n }\n }\n\n #removePending(track: TrackState, group: GroupState, pending: PendingObject): void {\n if (group.pending.get(pending.identity.objectId) === pending) {\n group.pending.delete(pending.identity.objectId)\n }\n const index = track.quarantine.indexOf(pending)\n if (index >= 0) track.quarantine.splice(index, 1)\n track.quarantinedBytes -= pending.bytes\n this.#stats.quarantinedBytes -= pending.bytes\n }\n\n #quarantine(track: TrackState, group: GroupState, pending: PendingObject): boolean {\n if (group.pending.has(pending.identity.objectId)) return false\n group.pending.set(pending.identity.objectId, pending)\n track.quarantine.push(pending)\n track.quarantinedBytes += pending.bytes\n this.#stats.quarantinedBytes += pending.bytes\n this.#enforceCap(track)\n return true\n }\n\n #enforceCap(track: TrackState): void {\n while (track.quarantinedBytes > track.capBytes && track.quarantine.length > 0) {\n const pending = track.quarantine.shift()!\n const group = track.groups.get(BigInt(pending.identity.groupId))\n if (group) group.pending.delete(pending.identity.objectId)\n track.quarantinedBytes -= pending.bytes\n this.#stats.quarantinedBytes -= pending.bytes\n pending.release()\n // Quarantine budget ran out while the object was still waiting on a\n // manifest. The manifest was absent when we gave up; the verifier did not\n // fault. Same reason in shadow and enforce so the dashboard reads one\n // taxonomy across modes (BLO-30007).\n this.#failure(pending.identity, 'manifestAbsent')\n console.warn(`[ManifestVerifier] quarantine cap eviction fail-open track=${pending.identity.trackName} group=${pending.identity.groupId} object=${pending.identity.objectId}`)\n }\n }\n\n #failOpenTrack(track: TrackState, reason: 'verifierError'): void {\n for (const pending of [...track.quarantine]) {\n const group = track.groups.get(BigInt(pending.identity.groupId))\n if (group) this.#removePending(track, group, pending)\n pending.release()\n this.#failure(pending.identity, reason)\n }\n }\n\n #failOpenGroup(track: TrackState, groupId: bigint, group: GroupState): void {\n const pending = [...group.pending.values()]\n if (pending.length === 0) {\n this.#failure({ trackName: track.context.trackName, groupId, objectId: 0 }, 'verifierError')\n return\n }\n for (const object of pending) {\n this.#removePending(track, group, object)\n object.release()\n this.#failure(object.identity, 'verifierError')\n }\n }\n\n #releaseAllQuarantine(countFailure: boolean): void {\n for (const track of this.#tracks.values()) {\n for (const pending of [...track.quarantine]) {\n const group = track.groups.get(BigInt(pending.identity.groupId))\n if (group) this.#removePending(track, group, pending)\n pending.release()\n if (countFailure) this.#failure(pending.identity, 'verifierError')\n }\n }\n }\n\n #failure(identity: ManifestObjectIdentity, reason: ManifestFailureReason): void {\n this.#stats.failures[reason]++\n this.#onFailure?.({\n trackName: identity.trackName,\n ...(identity.bindingId === undefined ? {} : { bindingId: identity.bindingId }),\n groupId: identity.groupId,\n objectId: identity.objectId,\n reason,\n })\n }\n}\n", "import {\n ManifestVerifier,\n manifestBindingId,\n type ManifestAuthConfig,\n type ManifestTrackContext,\n type SignatureVerifier,\n} from '@blockcast/mmt-manifest-verify'\nimport {\n resolveMulticastAuthCatalog,\n type MulticastAuthMode,\n type ResolvedMulticastAuthConfig,\n} from './multicast-auth-catalog.js'\n\nexport interface ManifestAuthBinding {\n bindingId: string\n mediaTrack: string\n manifestTrack: string\n sourceSymbolFormat: string\n}\n\nexport interface ManifestAuthPlan {\n verifier: ManifestVerifier\n mode: MulticastAuthMode\n bindings: readonly ManifestAuthBinding[]\n manifestTracks: readonly string[]\n bindingIdFor(mediaTrack: string, sourceSymbolFormat: string): string | undefined\n ingestManifestPayload(manifestTrack: string, payload: Uint8Array): void\n dispose(): void\n}\n\ntype ContextFields = Omit<\n ManifestTrackContext,\n 'bindingId' | 'trackName' | 'sourceSymbolFormat' | 'authScope' | 'publicKey' | 'acceptedPublicKeys'\n>\n\n/** Build the one canonical verifier plan shared by browser players. Transport\n * implementations subscribe the exact returned manifestTracks and feed each\n * bare source-auth frame to ingestManifestPayload without name inference. */\nexport function createManifestAuthPlan(\n catalog: unknown,\n options: {\n playerMode?: MulticastAuthMode\n onMissingManifest?: ManifestAuthConfig['onMissingManifest']\n verifySignature: SignatureVerifier\n contextFor(\n binding: ResolvedMulticastAuthConfig['tracks'][number],\n resolved: ResolvedMulticastAuthConfig,\n ): ContextFields\n onFailure?: ConstructorParameters<typeof ManifestVerifier>[0]['onFailure']\n },\n): ManifestAuthPlan | undefined {\n const resolved = resolveMulticastAuthCatalog(catalog, options.playerMode)\n if (!resolved || resolved.mode === 'off') return undefined\n\n const verifier = new ManifestVerifier({\n manifestAuth: {\n mode: resolved.mode,\n onMissingManifest: options.onMissingManifest ??\n (resolved.mode === 'enforce' ? 'stall' : 'fallback-shadow'),\n },\n verifySignature: options.verifySignature,\n ...(options.onFailure === undefined ? {} : { onFailure: options.onFailure }),\n })\n const byManifestTrack = new Map<string, ManifestAuthBinding>()\n const bindings = resolved.tracks.map((binding): ManifestAuthBinding => {\n const bindingId = manifestBindingId(binding.mediaTrack, binding.sourceSymbolFormat)\n const planned = {\n bindingId,\n mediaTrack: binding.mediaTrack,\n manifestTrack: binding.manifestTrack,\n sourceSymbolFormat: binding.sourceSymbolFormat,\n }\n verifier.registerTrack({\n ...options.contextFor(binding, resolved),\n bindingId,\n trackName: binding.mediaTrack,\n sourceSymbolFormat: binding.sourceSymbolFormat,\n authScope: binding.authScope,\n publicKey: resolved.acceptedPublicKeys[0]!,\n acceptedPublicKeys: resolved.acceptedPublicKeys,\n })\n byManifestTrack.set(binding.manifestTrack, planned)\n return planned\n })\n let disposed = false\n\n return {\n verifier,\n mode: resolved.mode,\n bindings,\n manifestTracks: [...byManifestTrack.keys()],\n bindingIdFor(mediaTrack, sourceSymbolFormat) {\n const bindingId = manifestBindingId(mediaTrack, sourceSymbolFormat)\n return bindings.some((binding) => binding.bindingId === bindingId) ? bindingId : undefined\n },\n ingestManifestPayload(manifestTrack, payload) {\n const binding = byManifestTrack.get(manifestTrack)\n if (!binding) throw new Error(`unknown manifest subscription track ${manifestTrack}`)\n verifier.ingestManifestFrame(binding.bindingId, payload)\n },\n dispose() {\n if (disposed) return\n disposed = true\n verifier.dispose()\n },\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["MMTP_HEADER_SIZE", "MPU_HEADER_SIZE", "MPU_LENGTH_FIELD_SIZE", "MPU_HEADER_REMAINDER_SIZE", "PACKET_TYPE_MPU", "MMTP_HEADER_SIZE", "view", "MPU_HEADER_SIZE", "view", "MPU_HEADER_REMAINDER_SIZE", "MPU_LENGTH_FIELD_SIZE", "MMTP_HEADER_SIZE", "MPU_HEADER_SIZE", "PACKET_TYPE_MPU", "MPU_HEADER_SIZE", "view", "MMTP_HEADER_SIZE", "MPU_HEADER_SIZE", "PACKET_TYPE_MPU", "MPU_HEADER_REMAINDER_SIZE", "MPU_LENGTH_FIELD_SIZE", "extractAltaTrailer", "active", "view", "_maxBuffered", "box", "box", "trex", "isU32", "emitFrame_fn", "PACKET_TYPE_MPU", "extractAltaTrailer", "resolver", "_timeoutMs", "children", "u32", "u32", "u32", "SOURCE_AUTH_SCOPE_LENGTH", "view", "SOURCE_AUTH_SCOPE_LENGTH", "view", "_tracks", "_stats", "_disposed"]
|
|
7
|
+
}
|