@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/sample-combiner.ts"],
|
|
4
|
+
"sourcesContent": ["/**\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"],
|
|
5
|
+
"mappings": ";;;;;;;;;;AAqDA,SAAS,UACP,kBACA,mBACA,6BACA,cACW;AACX,SAAO,KAAK,UAAU,CAAC,oBAAoB,MAAM,mBAAmB,6BAA6B,YAAY,CAAC;AAChH;AAGA,SAAS,eAAe,KAAoC;AAC1D,QAAM,OAAQ,KAAK,MAAM,GAAG,EAA8C,CAAC;AAC3E,SAAO,QAAQ;AACjB;AAwCO,IAAM,6BAA6B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAUO,IAAM,qBAAN,cAAiC,MAAM;AAAA,EAG5C,YAAqB,MAA8B,SAAiB;AAClE,UAAM,OAAO;AADM;AAFrB,SAAS,OAAO;AAAA,EAIhB;AACF;AA/HA;AAsKO,IAAM,iBAAN,MAAqB;AAAA,EAoB1B,YAAY,SAAgC;AApBvC;AACL;AACA;AACA;AACA,uCAAyC,oBAAI,IAAI;AAEjD;AAAA,iCAA0C,oBAAI,IAAI;AAMlD;AAAA;AAAA;AAAA;AAAA;AAAA,iCAA2B,oBAAI,IAAI;AACnC,+BAA8B;AAAA,MAC5B,iBAAiB;AAAA,MACjB,oBAAoB;AAAA,MACpB,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,IAClB;AAGE,UAAM,EAAE,aAAa,qBAAqB,qBAAqB,IAAI;AACnE,QAAI,CAAC,OAAO,UAAU,WAAW,KAAK,eAAe,GAAG;AACtD,YAAM,IAAI,MAAM,yDAAyD;AAAA,IAC3E;AACA,QAAI,CAAC,OAAO,UAAU,oBAAoB,KAAK,wBAAwB,GAAG;AACxE,YAAM,IAAI,MAAM,kEAAkE;AAAA,IACpF;AACA,uBAAK,cAAe;AACpB,uBAAK,sBAAuB;AAC5B,uBAAK,uBAAwB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyBA,qBACE,kBACA,mBACA,6BACA,cACA,MACuB;AACvB,UAAM,MAAM,UAAU,kBAAkB,mBAAmB,6BAA6B,YAAY;AACpG,uBAAK,UAAS,OAAO,GAAG;AACxB,uBAAK,gBAAe,IAAI,KAAK,IAAI;AACjC,WAAO,sBAAK,2CAAL,WAAkB,KAAK;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAA4C;AACjD,QAAI,IAAI,gCAAgC,UAAa,IAAI,iBAAiB,QAAW;AAEnF,yBAAK,QAAO;AACZ,aAAO,gBAAgB,GAAG;AAAA,IAC5B;AACA,UAAM,SAAS,IAAI,gBAAgB;AACnC,UAAM,MAAM;AAAA,MACV,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IACN;AAEA,QAAI,mBAAK,UAAS,IAAI,GAAG,GAAG;AAM1B,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,IAAI,KAAK;AACzB,UAAM,eAAe,mBAAK,gBAAe,IAAI,GAAG;AAEhD,QAAI,WAAW,KAAK,CAAC,mBAAK,UAAS,IAAI,GAAG,GAAG;AAC3C,YAAM,gBAAgB,iBAAiB,SACnC,CAAC,mBAAK,wBACN,YAAY;AAChB,UAAI,eAAe;AACjB,2BAAK,QAAO;AACZ,8BAAK,sCAAL,WAAa;AACb,eAAO,gBAAgB,GAAG;AAAA,MAC5B;AAAA,IAGF;AAMA,UAAM,UAAU,SAAS;AACzB,QAAI,iBAAiB,UAAa,UAAU,cAAc;AACxD,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,UAAM,WAAW,mBAAK,UAAS,IAAI,GAAG;AACtC,QAAI,aAAa,QAAW;AAC1B,UAAI,SAAS,SAAS,IAAI,MAAM,GAAG;AACjC,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,SAAS,SAAS,QAAQ,mBAAK,wBAAuB;AACxD,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,iBAAW,CAAC,WAAW,GAAG,KAAK,SAAS,UAAU;AAChD,cAAM,SAAS,YAAY,IAAI,KAAK;AACpC,YAAI,SAAS,UAAU,YAAY,SAAS;AAC1C,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,UAAU;AACd,QAAI,YAAY,QAAW;AACzB,UAAI,mBAAK,UAAS,QAAQ,mBAAK,cAAc,uBAAK,kDAAL;AAC7C,gBAAU,EAAE,UAAU,oBAAI,IAAI,GAAG,WAAW,KAAK,IAAI,EAAE;AACvD,yBAAK,UAAS,IAAI,KAAK,OAAO;AAAA,IAChC;AACA,YAAQ,SAAS,IAAI,QAAQ,GAAG;AAEhC,QAAI,iBAAiB,OAAW,QAAO;AACvC,WAAO,sBAAK,2CAAL,WAAkB,KAAK;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoEA,gBAAgB,WAAyB;AACvC,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,KAAK,OAAO,KAAK,CAAC,GAAG,mBAAK,SAAQ,GAAG;AAC/C,UAAI,MAAM,QAAQ,YAAY,WAAW;AACvC,2BAAK,UAAS,OAAO,GAAG;AACxB,2BAAK,QAAO;AACZ,8BAAK,sCAAL,WAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,uBAAK,UAAS,MAAM;AACpB,uBAAK,gBAAe,MAAM;AAC1B,uBAAK,UAAS,MAAM;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,kBAAgC;AAC1C,eAAW,OAAO,mBAAK,UAAS,KAAK,GAAG;AACtC,UAAI,eAAe,GAAG,MAAM,iBAAkB,oBAAK,UAAS,OAAO,GAAG;AAAA,IACxE;AACA,eAAW,OAAO,mBAAK,gBAAe,KAAK,GAAG;AAC5C,UAAI,eAAe,GAAG,MAAM,iBAAkB,oBAAK,gBAAe,OAAO,GAAG;AAAA,IAC9E;AACA,eAAW,OAAO,mBAAK,WAAU;AAC/B,UAAI,eAAe,GAAG,MAAM,iBAAkB,oBAAK,UAAS,OAAO,GAAG;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,IAAI,QAA6B;AAC/B,WAAO,EAAE,GAAG,mBAAK,QAAO;AAAA,EAC1B;AAAA,EAEA,IAAI,eAAuB;AACzB,WAAO,mBAAK,UAAS;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,yBAAiC;AACnC,WAAO,mBAAK,gBAAe;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,oBAA4B;AAC9B,WAAO,mBAAK,UAAS;AAAA,EACvB;AACF;AAxRE;AACA;AACA;AACA;AAEA;AAMA;AACA;AAbK;AAAA;AAAA;AAAA;AAAA;AAoKL,iBAAY,SAAC,KAAgB,MAAqC;AAChE,QAAM,UAAU,mBAAK,UAAS,IAAI,GAAG;AACrC,MAAI,YAAY,OAAW,QAAO;AAClC,MAAI,WAAW;AACf,QAAM,gBAAgB,CAAC,GAAG,QAAQ,SAAS,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AACvE,aAAW,aAAa,eAAe;AACrC,QAAI,cAAc,SAAU,QAAO;AACnC,gBAAY,QAAQ,SAAS,IAAI,SAAS,EAAG,KAAK;AAAA,EACpD;AACA,MAAI,aAAa,KAAM,QAAO;AAE9B,qBAAK,UAAS,OAAO,GAAG;AACxB,qBAAK,QAAO;AACZ,wBAAK,sCAAL,WAAa;AACb,SAAO,aAAa,QAAQ,UAAU,aAAa;AACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA,YAAO,SAAC,KAAsB;AAC5B,qBAAK,gBAAe,OAAO,GAAG;AAC9B,qBAAK,UAAS,IAAI,GAAG;AACrB,SAAO,mBAAK,UAAS,OAAO,mBAAK,eAAc;AAC7C,UAAM,SAAS,mBAAK,UAAS,OAAO,EAAE,KAAK,EAAE;AAC7C,QAAI,WAAW,OAAW;AAC1B,uBAAK,UAAS,OAAO,MAAM;AAAA,EAC7B;AACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,wBAAmB,WAAS;AAC1B,QAAM,SAAS,mBAAK,UAAS,KAAK,EAAE,KAAK,EAAE;AAC3C,MAAI,WAAW,OAAW;AAC1B,qBAAK,UAAS,OAAO,MAAM;AAC3B,qBAAK,QAAO;AACZ,wBAAK,sCAAL,WAAa;AACf;AAkEF,SAAS,gBAAgB,KAAqC;AAC5D,SAAO;AAAA,IACL,mBAAmB,IAAI;AAAA,IACvB,6BAA6B,IAAI,+BAA+B;AAAA,IAChE,cAAc,IAAI,gBAAgB;AAAA,IAClC,MAAM,IAAI;AAAA,IACV,WAAW,IAAI;AAAA,IACf,SAAS,IAAI;AAAA,IACb,UAAU,IAAI;AAAA,IACd,uBAAuB,IAAI;AAAA,IAC3B,+BAA+B,IAAI;AAAA,IACnC,kBAAkB,IAAI;AAAA,IACtB,gBAAgB;AAAA,IAChB,eAAe,IAAI;AAAA,IACnB,QAAQ,IAAI;AAAA;AAAA,IAEZ,oBAAoB,IAAI;AAAA,EAC1B;AACF;AAEA,SAAS,aACP,UACA,eACgB;AAChB,QAAM,YAAY,cAAc,OAAO,CAAC,KAAK,WAAW,MAAM,SAAS,IAAI,MAAM,EAAG,KAAK,YAAY,CAAC;AACtG,QAAM,OAAO,IAAI,WAAW,SAAS;AACrC,MAAI;AACJ,MAAI;AACJ,MAAI,cAAc;AAClB,MAAI;AACJ,MAAI,gBAAgB;AAIpB,MAAI,qBACF,cAAc,WAAW,IAAI,YAAY;AAC3C,aAAW,UAAU,eAAe;AAClC,UAAM,MAAM,SAAS,IAAI,MAAM;AAC/B,yBACE,uBAAuB,WAAW,IAAI,uBAAuB,UACzD,UACA,uBAAuB,aAAa,IAAI,uBAAuB,YAC7D,YACA;AACR,SAAK,IAAI,IAAI,MAAM,WAAW;AAC9B,mBAAe,IAAI,KAAK;AACxB,qBAAiB,IAAI;AACrB,QAAI,IAAI,0BAA0B,QAAW;AAC3C,OAAC,kDAA0B,CAAC,IAAG,KAAK,GAAG,IAAI,qBAAqB;AAAA,IAClE;AACA,QAAI,IAAI,kCAAkC,QAAW;AACnD,OAAC,kEAAkC,CAAC,IAAG,KAAK,GAAG,IAAI,6BAA6B;AAAA,IAClF;AACA,QAAI,UAAU,OAAW,SAAQ;AAAA,EACnC;AACA,SAAO;AAAA,IACL,mBAAmB,MAAO;AAAA,IAC1B,6BAA6B,MAAO;AAAA,IACpC,cAAc,MAAO;AAAA,IACrB;AAAA,IACA,WAAW,MAAO;AAAA,IAClB,SAAS,MAAO;AAAA,IAChB,UAAU,MAAO;AAAA,IACjB;AAAA,IACA;AAAA,IACA,kBAAkB,MAAO;AAAA,IACzB,gBAAgB,SAAS;AAAA,IACzB;AAAA,IACA,QAAQ,MAAO;AAAA,IACf,oBAAoB;AAAA,EACtB;AACF;AAMA,IAAI,QAAoB;AACtB,QAAM,EAAE,UAAU,MAAM,OAAO,IAAI;AAEnC,QAAM,WAAW,CAAC,YAA4C,CAAC,MAC7D,IAAI,eAAe;AAAA,IACjB,aAAa;AAAA,IACb,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,GAAG;AAAA,EACL,CAAC;AAEH,QAAM,MAAM,CACV,KACA,OACA,QACA,QACA,MACA,WACA,SACA,qBAA6C,iBACzB;AAAA,IACpB,mBAAmB;AAAA,IACnB,MAAM,IAAI,WAAW,IAAI;AAAA,IACzB;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA,cAAc;AAAA,IACd,6BAA6B;AAAA,IAC7B,cAAc;AAAA,IACd,uBAAuB,CAAC,MAAM;AAAA,IAC9B;AAAA,EACF;AAEA,WAAS,kBAAkB,MAAM;AAC/B,SAAK,sEAAsE,MAAM;AAC/E,YAAM,IAAI,SAAS;AACnB,YAAM,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC;AACnE,aAAO,GAAG,EAAE,IAAI,SAAS;AACzB,aAAO,IAAK,IAAI,EAAE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AACzD,aAAO,IAAK,cAAc,EAAE,KAAK,CAAC;AAClC,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAAA,IAC/B,CAAC;AAED,SAAK,sEAAsE,MAAM;AAC/E,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,CAAC;AAC7C,YAAM,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC;AACnE,aAAO,KAAK,IAAI,EAAE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AAAA,IAC3D,CAAC;AAED,SAAK,8DAA8D,MAAM;AACvE,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,EAAE;AAE9C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAE7B,YAAM,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,OAAO,KAAK,CAAC;AACrE,aAAO,KAAK,IAAI,EAAE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC;AACzE,aAAO,KAAK,cAAc,EAAE,KAAK,CAAC;AAClC,aAAO,KAAK,OAAO,EAAE,KAAK,IAAI;AAC9B,aAAO,KAAK,SAAS,EAAE,KAAK,KAAK;AACjC,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAC7B,aAAO,EAAE,MAAM,eAAe,EAAE,KAAK,CAAC;AAAA,IACxC,CAAC;AAED,SAAK,6CAA6C,MAAM;AACtD,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,EAAE;AAE9C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,OAAO,KAAK,CAAC,CAAC,EAAE,SAAS;AAC5E,YAAM,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC;AACnE,aAAO,KAAK,IAAI,EAAE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC;AAAA,IAC3E,CAAC;AAED,SAAK,uDAAuD,MAAM;AAKhE,YAAM,IAAI,SAAS;AACnB,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,EAAE,SAAS;AACrE,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AACpE,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAAA,IAC/B,CAAC;AAED,SAAK,8EAA8E,MAAM;AAKvF,YAAM,IAAI,SAAS,EAAE,qBAAqB,KAAK,CAAC;AAChD,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAE7B,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,EAAE;AAC9C,YAAM,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,OAAO,KAAK,CAAC;AACrE,aAAO,KAAK,IAAI,EAAE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC;AAAA,IAC3E,CAAC;AAED,SAAK,gCAAgC,MAAM;AACzC,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,EAAE;AAC9C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAClE,QAAQ,kBAAkB;AAAA,IAC/B,CAAC;AAED,SAAK,qCAAqC,MAAM;AAC9C,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,EAAE;AAC9C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAClE,QAAQ,kBAAkB;AAAA,IAC/B,CAAC;AAED,SAAK,2CAA2C,MAAM;AACpD,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,CAAC;AAC7C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,OAAO,KAAK,CAAC,CAAC,EACpE,QAAQ,kBAAkB;AAAA,IAC/B,CAAC;AAED,SAAK,8CAA8C,MAAM;AACvD,YAAM,IAAI,SAAS,EAAE,sBAAsB,EAAE,CAAC;AAC9C,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,GAAG;AAC/C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AACjE,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,EAAE,SAAS;AAClE,aAAO,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,EAC1D,QAAQ,kBAAkB;AAAA,IAC/B,CAAC;AAED,SAAK,wEAAwE,MAAM;AAIjF,YAAM,IAAI,SAAS,EAAE,aAAa,EAAE,CAAC;AACrC,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,EAAE;AAC9C,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,EAAE;AAC9C,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,EAAE;AAE9C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAG7B,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAC7B,aAAO,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AAGrC,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG,IAAI,EACnE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AACzD,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG,IAAI,EACnE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AAGzD,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,EAAE;AAC9C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG,IAAI,EACnE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AAAA,IAC3D,CAAC;AAED,SAAK,yEAAyE,MAAM;AAClF,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,EAAE;AAC9C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,OAAO,KAAK,CAAC,CAAC,EAAE,IAAI,SAAS;AAIhF,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAAA,IAC5E,CAAC;AAED,SAAK,wDAAwD,MAAM;AACjE,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,cAAc,GAAG,GAAG,IAAI,EAAE;AACjD,QAAE,qBAAqB,SAAS,GAAG,GAAG,IAAI,EAAE;AAC5C,YAAM,QAAQ,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,GAAG,kBAAkB,aAAa;AAClG,YAAM,QAAQ,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,GAAG,kBAAkB,QAAQ;AAC7F,aAAO,EAAE,OAAO,KAAK,CAAC,EAAE,SAAS;AACjC,aAAO,EAAE,OAAO,KAAK,CAAC,EAAE,SAAS;AAEjC,QAAE,YAAY,YAAY;AAC1B,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAE7B,YAAM,YAAY,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,KAAK,GAAG,kBAAkB,QAAQ;AAClG,aAAO,EAAE,OAAO,SAAS,GAAG,IAAI,EAAE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AAAA,IAC1F,CAAC;AAED,SAAK,0CAA0C,MAAM;AACnD,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,CAAC;AAC7C,QAAE,MAAM;AAIR,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG,IAAI,EAClE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AAAA,IAC5C,CAAC;AAED,SAAK,+CAA+C,MAAM;AAGxD,YAAM,IAAI,SAAS,EAAE,aAAa,GAAG,qBAAqB,KAAK,CAAC;AAChE,eAAS,IAAI,GAAG,IAAI,KAAM,KAAK;AAC7B,eAAO,EAAE,qBAAqB,QAAW,GAAG,GAAG,GAAG,EAAE,CAAC,EAAE,SAAS;AAChE,eAAO,EAAE,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AACzE,eAAO,EAAE,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,EAAE,IAAI,SAAS;AAAA,MAChF;AACA,aAAO,EAAE,MAAM,eAAe,EAAE,KAAK,GAAI;AACzC,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAC7B,aAAO,EAAE,sBAAsB,EAAE,KAAK,CAAC;AACvC,aAAO,EAAE,iBAAiB,EAAE,oBAAoB,CAAC;AAAA,IACnD,CAAC;AAED,SAAK,2DAA2D,MAAM;AACpE,YAAM,IAAI,SAAS,EAAE,aAAa,GAAG,qBAAqB,KAAK,CAAC;AAChE,eAAS,IAAI,GAAG,IAAI,KAAM,KAAK;AAC7B,eAAO,EAAE,qBAAqB,QAAW,GAAG,GAAG,GAAG,EAAE,CAAC,EAAE,SAAS;AAChE,eAAO,EAAE,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAAA,MAE3E;AACA,QAAE,gBAAgB,EAAE;AACpB,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAC7B,aAAO,EAAE,sBAAsB,EAAE,KAAK,CAAC;AAAA,IACzC,CAAC;AAED,SAAK,6DAA6D,MAAM;AAKtE,YAAM,IAAI,SAAS,EAAE,qBAAqB,KAAK,CAAC;AAChD,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAE7B,YAAM,MAAM,EAAE,qBAAqB,QAAW,GAAG,GAAG,IAAI,CAAC;AACzD,aAAO,KAAK,IAAI,EAAE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AACzD,aAAO,KAAK,cAAc,EAAE,KAAK,CAAC;AAClC,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAAA,IAC/B,CAAC;AAED,SAAK,qDAAqD,MAAM;AAI9D,YAAM,IAAI,SAAS,EAAE,aAAa,EAAE,CAAC;AACrC,iBAAW,KAAK,CAAC,IAAI,IAAI,EAAE,EAAG,GAAE,qBAAqB,QAAW,GAAG,GAAG,GAAG,EAAE;AAC3E,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAG7B,aAAO,MAAM,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,EACnE,QAAQ,kBAAkB;AAC7B,aAAO,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AACrC,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAG7B,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG,IAAI,EACnE,QAAQ,IAAI,WAAW,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AAAA,IAC3D,CAAC;AAED,SAAK,qDAAqD,MAAM;AAC9D,YAAM,IAAI,SAAS,EAAE,aAAa,EAAE,CAAC;AACrC,iBAAW,KAAK,CAAC,IAAI,EAAE,EAAG,GAAE,qBAAqB,QAAW,GAAG,GAAG,GAAG,EAAE;AACvE,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,EAAE,SAAS;AAC1E,aAAO,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AAGrC,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,EAAE,SAAS;AAC3E,aAAO,EAAE,YAAY,EAAE,KAAK,CAAC;AAAA,IAC/B,CAAC;AAAA,EACH,CAAC;AAED,WAAS,oCAAoC,MAAM;AACjD,SAAK,oEAAoE,MAAM;AAK7E,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,QAAW,GAAG,GAAG,GAAG,CAAC;AAC5C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,SAAS;AAC5E,YAAM,OAAO,EAAE,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,OAAO,OAAO,CAAC;AACnE,aAAO,IAAI,EAAE,IAAI,SAAS;AAC1B,aAAO,KAAM,cAAc,EAAE,KAAK,CAAC;AACnC,aAAO,KAAM,kBAAkB,EAAE,KAAK,OAAO;AAAA,IAC/C,CAAC;AAED,SAAK,4DAA4D,MAAM;AACrE,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,QAAW,GAAG,GAAG,GAAG,CAAC;AAC5C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,SAAS;AAC5E,YAAM,OAAO,EAAE,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,OAAO,SAAS,CAAC;AACrE,aAAO,IAAI,EAAE,IAAI,SAAS;AAC1B,aAAO,KAAM,kBAAkB,EAAE,KAAK,SAAS;AAAA,IACjD,CAAC;AAED,SAAK,qDAAqD,MAAM;AAC9D,YAAM,IAAI,SAAS;AACnB,QAAE,qBAAqB,QAAW,GAAG,GAAG,GAAG,CAAC;AAC5C,aAAO,EAAE,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,SAAS;AAC5E,YAAM,OAAO,EAAE,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,OAAO,WAAW,CAAC;AACvE,aAAO,IAAI,EAAE,IAAI,SAAS;AAC1B,aAAO,KAAM,kBAAkB,EAAE,KAAK,WAAW;AAAA,IACnD,CAAC;AAED,SAAK,mEAAmE,MAAM;AAC5E,YAAM,IAAI,SAAS;AACnB,YAAM,OAAO,EAAE,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,MAAM,OAAO,CAAC;AAClE,aAAO,IAAI,EAAE,IAAI,SAAS;AAC1B,aAAO,KAAM,cAAc,EAAE,KAAK,CAAC;AACnC,aAAO,KAAM,kBAAkB,EAAE,KAAK,OAAO;AAAA,IAC/C,CAAC;AAAA,EACH,CAAC;AACH;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MMTP Signaling Parser for Multicast
|
|
3
|
+
*
|
|
4
|
+
* Provides packet type detection and AL-FEC signaling message parsing.
|
|
5
|
+
* Used by the multicast pipeline to classify and route MMTP packets.
|
|
6
|
+
*
|
|
7
|
+
* Packet types (ISO/IEC 23008-1:2023 Section 9.2.2):
|
|
8
|
+
* - 0x00: MPU (Media Processing Unit) - video/audio data
|
|
9
|
+
* - 0x02: Signaling - control messages including AL-FEC config
|
|
10
|
+
* - 0x03: Repair - FEC repair symbols
|
|
11
|
+
*/
|
|
12
|
+
import { ALFEC_MESSAGE_ID, FEC_CODE_RAPTORQ, FEC_CODE_XOR, PACKET_TYPE_MPU, PACKET_TYPE_REPAIR, PACKET_TYPE_SIGNALING, parseAlFecMessage } from "@blockcast/mmt-base";
|
|
13
|
+
export { ALFEC_MESSAGE_ID, FEC_CODE_RAPTORQ, FEC_CODE_XOR, PACKET_TYPE_MPU, PACKET_TYPE_REPAIR, PACKET_TYPE_SIGNALING, parseAlFecMessage, };
|
|
14
|
+
export type PacketClass = "source" | "signaling" | "repair" | "unknown";
|
|
15
|
+
/** Get the MMTP packet type from raw multicast packet bytes.
|
|
16
|
+
*
|
|
17
|
+
* ISO/IEC 23008-1:2023 Figure 8 (V=0): byte 1 is
|
|
18
|
+
* reserved(2)|packet_type(6), so signaling is 0x02 and repair is 0x03.
|
|
19
|
+
* Pre-migration FFmpeg high-bits bytes (0x08/0x0c) are NOT accepted:
|
|
20
|
+
* writers and readers move together in the pinned smoke train.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getPacketType(mmtpPacket: Uint8Array): number;
|
|
23
|
+
/** Check if packet is a signaling packet (type 0x02). */
|
|
24
|
+
export declare function isSignalingPacket(mmtpPacket: Uint8Array): boolean;
|
|
25
|
+
/** Determine if packet is a source (video/audio) packet. */
|
|
26
|
+
export declare function isSourcePacket(mmtpPacket: Uint8Array): boolean;
|
|
27
|
+
/** Classify MMTP packet for multicast pipeline routing. */
|
|
28
|
+
export declare function classifyPacket(mmtpPacket: Uint8Array): PacketClass;
|
|
29
|
+
//# sourceMappingURL=signaling.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signaling.d.ts","sourceRoot":"","sources":["../src/signaling.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EACN,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACN,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,GACjB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAExE;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAG5D;AAED,yDAAyD;AACzD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAEjE;AAED,4DAA4D;AAC5D,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAK9D;AAED,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,GAAG,WAAW,CAkBlE"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// ../mmt-alta-parse/dist/index.js
|
|
2
|
+
var MPU_HEADER_SIZE = 8;
|
|
3
|
+
var MPU_LENGTH_FIELD_SIZE = 2;
|
|
4
|
+
var MPU_HEADER_REMAINDER_SIZE = MPU_HEADER_SIZE - MPU_LENGTH_FIELD_SIZE;
|
|
5
|
+
|
|
6
|
+
// ../mmt-base/dist/mmtp.js
|
|
7
|
+
var MMTP_HEADER_SIZE = 12;
|
|
8
|
+
var MPU_HEADER_SIZE2 = 8;
|
|
9
|
+
var MPU_LENGTH_FIELD_SIZE2 = 2;
|
|
10
|
+
var MPU_HEADER_REMAINDER_SIZE2 = MPU_HEADER_SIZE2 - MPU_LENGTH_FIELD_SIZE2;
|
|
11
|
+
var PACKET_TYPE_MPU = 0;
|
|
12
|
+
var PACKET_TYPE_SIGNALING = 2;
|
|
13
|
+
var PACKET_TYPE_REPAIR = 3;
|
|
14
|
+
var ALFEC_MESSAGE_ID = 515;
|
|
15
|
+
var FEC_CODE_XOR = 1;
|
|
16
|
+
var FEC_CODE_RAPTORQ = 2;
|
|
17
|
+
function parseMMTPHeader(buffer) {
|
|
18
|
+
if (buffer.length < MMTP_HEADER_SIZE) {
|
|
19
|
+
throw new Error(`MMTP packet too small: ${buffer.length} bytes`);
|
|
20
|
+
}
|
|
21
|
+
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
22
|
+
const version = buffer[0] >> 6 & 3;
|
|
23
|
+
if (version !== 0) {
|
|
24
|
+
throw new Error(`Unsupported MMTP version: ${version}`);
|
|
25
|
+
}
|
|
26
|
+
const fecType = buffer[0] >> 3 & 3;
|
|
27
|
+
const packetCounterFlag = (buffer[0] & 32) !== 0;
|
|
28
|
+
const extensionFlag = (buffer[0] & 2) !== 0;
|
|
29
|
+
const rapFlag = (buffer[0] & 1) === 1;
|
|
30
|
+
const packetType = buffer[1] & 63;
|
|
31
|
+
let offset = 2;
|
|
32
|
+
const packetId = view.getUint16(offset, false);
|
|
33
|
+
offset += 2;
|
|
34
|
+
const timestamp = BigInt(view.getUint32(offset, false));
|
|
35
|
+
offset += 4;
|
|
36
|
+
const sequenceNumber = view.getUint32(offset, false);
|
|
37
|
+
offset += 4;
|
|
38
|
+
let packetCounter;
|
|
39
|
+
if (packetCounterFlag) {
|
|
40
|
+
if (offset + 4 > buffer.length)
|
|
41
|
+
throw new Error("MMTP packet truncated in packet_counter");
|
|
42
|
+
packetCounter = view.getUint32(offset, false);
|
|
43
|
+
offset += 4;
|
|
44
|
+
}
|
|
45
|
+
let extension;
|
|
46
|
+
if (extensionFlag) {
|
|
47
|
+
if (offset + 4 > buffer.length)
|
|
48
|
+
throw new Error("MMTP packet truncated in header extension");
|
|
49
|
+
const type = view.getUint16(offset, false);
|
|
50
|
+
const length = view.getUint16(offset + 2, false);
|
|
51
|
+
offset += 4;
|
|
52
|
+
if (offset + length > buffer.length)
|
|
53
|
+
throw new Error("MMTP packet truncated in header extension value");
|
|
54
|
+
extension = { type, data: buffer.subarray(offset, offset + length) };
|
|
55
|
+
offset += length;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
version,
|
|
59
|
+
packetType,
|
|
60
|
+
packetId,
|
|
61
|
+
timestamp,
|
|
62
|
+
sequenceNumber,
|
|
63
|
+
payloadLength: buffer.length - offset,
|
|
64
|
+
fecType,
|
|
65
|
+
packetCounterFlag,
|
|
66
|
+
packetCounter,
|
|
67
|
+
extensionFlag,
|
|
68
|
+
extension,
|
|
69
|
+
headerLength: offset,
|
|
70
|
+
rapFlag
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function canonicalRaptorQOtiK(oti, repairSymbolSize) {
|
|
74
|
+
if (oti.length !== 12 || oti[5] !== 0)
|
|
75
|
+
return null;
|
|
76
|
+
const transferLength = oti[0] * 4294967296 + ((oti[1] << 24 | oti[2] << 16 | oti[3] << 8 | oti[4]) >>> 0);
|
|
77
|
+
const symbolSize = oti[6] << 8 | oti[7];
|
|
78
|
+
const sourceBlocks = oti[8];
|
|
79
|
+
const subBlocks = oti[9] << 8 | oti[10];
|
|
80
|
+
const alignment = oti[11];
|
|
81
|
+
if (!Number.isSafeInteger(transferLength) || transferLength <= 0 || symbolSize !== repairSymbolSize || symbolSize === 0 || symbolSize % 8 !== 0 || sourceBlocks !== 1 || subBlocks !== 1 || alignment !== 8 || transferLength % symbolSize !== 0) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const k = transferLength / symbolSize;
|
|
85
|
+
return Number.isInteger(k) && k >= 1 && k <= 56403 ? k : null;
|
|
86
|
+
}
|
|
87
|
+
function parseAlFecMessage(mmtpPacket) {
|
|
88
|
+
if (mmtpPacket.length < MMTP_HEADER_SIZE + 9)
|
|
89
|
+
return null;
|
|
90
|
+
let header;
|
|
91
|
+
try {
|
|
92
|
+
header = parseMMTPHeader(mmtpPacket);
|
|
93
|
+
} catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
if (header.packetType !== PACKET_TYPE_SIGNALING || header.fecType !== 0)
|
|
97
|
+
return null;
|
|
98
|
+
const payload = mmtpPacket.subarray(header.headerLength);
|
|
99
|
+
if (payload.length < 9)
|
|
100
|
+
return null;
|
|
101
|
+
const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);
|
|
102
|
+
let off = 0;
|
|
103
|
+
const messageId = view.getUint16(off, false);
|
|
104
|
+
off += 2;
|
|
105
|
+
if (messageId !== ALFEC_MESSAGE_ID)
|
|
106
|
+
return null;
|
|
107
|
+
const version = payload[off];
|
|
108
|
+
off += 1;
|
|
109
|
+
const messageLength = view.getUint16(off, false);
|
|
110
|
+
off += 2;
|
|
111
|
+
if (version !== 1 || messageLength === 0 || messageLength !== payload.length - off)
|
|
112
|
+
return null;
|
|
113
|
+
const flags = payload[off];
|
|
114
|
+
off += 1;
|
|
115
|
+
const fecFlag = flags >> 7 & 1;
|
|
116
|
+
const privateFecFlag = flags >> 6 & 1;
|
|
117
|
+
if (fecFlag !== 1 || privateFecFlag !== 1 || (flags & 63) !== 63)
|
|
118
|
+
return null;
|
|
119
|
+
if (off + 2 > payload.length)
|
|
120
|
+
return null;
|
|
121
|
+
const descriptorLength = view.getUint16(off, false);
|
|
122
|
+
off += 2;
|
|
123
|
+
const descriptorEnd = off + descriptorLength;
|
|
124
|
+
if (descriptorLength === 0 || descriptorEnd !== payload.length)
|
|
125
|
+
return null;
|
|
126
|
+
const numFlows = payload[off];
|
|
127
|
+
off += 1;
|
|
128
|
+
if (numFlows !== 1 || off + 3 > descriptorEnd)
|
|
129
|
+
return null;
|
|
130
|
+
off += 2;
|
|
131
|
+
const numAssets = payload[off];
|
|
132
|
+
off += 1;
|
|
133
|
+
if (numAssets === 0 || off + numAssets * 2 > descriptorEnd)
|
|
134
|
+
return null;
|
|
135
|
+
off += numAssets * 2;
|
|
136
|
+
if (off + 3 > descriptorEnd)
|
|
137
|
+
return null;
|
|
138
|
+
const codingParams = payload[off];
|
|
139
|
+
off += 1;
|
|
140
|
+
const fecCodingStructure = codingParams >> 4 & 15;
|
|
141
|
+
const ssbgMode = codingParams >> 2 & 3;
|
|
142
|
+
const ffsrptsFlag = codingParams >> 1 & 1;
|
|
143
|
+
const fecPayloadIdMode = codingParams & 1;
|
|
144
|
+
if (fecCodingStructure !== 1 || ssbgMode !== 0 || ffsrptsFlag !== 0 || fecPayloadIdMode !== 0) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
const repairSymbolSize = view.getUint16(off, false);
|
|
148
|
+
off += 2;
|
|
149
|
+
if (repairSymbolSize === 0 || repairSymbolSize % 8 !== 0)
|
|
150
|
+
return null;
|
|
151
|
+
if (off + 4 > descriptorEnd)
|
|
152
|
+
return null;
|
|
153
|
+
off += 2;
|
|
154
|
+
const fecCodeId = payload[off];
|
|
155
|
+
off += 1;
|
|
156
|
+
if (fecCodeId !== FEC_CODE_RAPTORQ)
|
|
157
|
+
return null;
|
|
158
|
+
const privateHeader = payload[off];
|
|
159
|
+
off += 1;
|
|
160
|
+
const privateFlag = privateHeader >> 7;
|
|
161
|
+
const privateFieldLength = privateHeader & 127;
|
|
162
|
+
if (privateFlag !== 1 || privateFieldLength !== 13 || off + 13 > descriptorEnd)
|
|
163
|
+
return null;
|
|
164
|
+
const oti = payload.slice(off, off + 12);
|
|
165
|
+
off += 12;
|
|
166
|
+
const interleaveDepth = payload[off];
|
|
167
|
+
off += 1;
|
|
168
|
+
const otiK = canonicalRaptorQOtiK(oti, repairSymbolSize);
|
|
169
|
+
if (otiK === null || interleaveDepth === 0)
|
|
170
|
+
return null;
|
|
171
|
+
if (off + 14 !== descriptorEnd)
|
|
172
|
+
return null;
|
|
173
|
+
const maximumK = payload[off] << 16 | payload[off + 1] << 8 | payload[off + 2];
|
|
174
|
+
off += 3;
|
|
175
|
+
const maximumP = payload[off] << 16 | payload[off + 1] << 8 | payload[off + 2];
|
|
176
|
+
off += 3;
|
|
177
|
+
if (maximumK !== otiK || maximumP === 0 || maximumK + maximumP - 1 > 16777215) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
off += 8;
|
|
181
|
+
if (off !== descriptorEnd)
|
|
182
|
+
return null;
|
|
183
|
+
return { fecCodeId, fecPayloadIdMode, repairSymbolSize, maximumK, maximumP, interleaveDepth, oti };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/signaling.ts
|
|
187
|
+
function getPacketType(mmtpPacket) {
|
|
188
|
+
if (mmtpPacket.length < 2) return -1;
|
|
189
|
+
return mmtpPacket[1] & 63;
|
|
190
|
+
}
|
|
191
|
+
function isSignalingPacket(mmtpPacket) {
|
|
192
|
+
return getPacketType(mmtpPacket) === PACKET_TYPE_SIGNALING;
|
|
193
|
+
}
|
|
194
|
+
function isSourcePacket(mmtpPacket) {
|
|
195
|
+
if (mmtpPacket.length < 2) return false;
|
|
196
|
+
const packetType = mmtpPacket[1] & 63;
|
|
197
|
+
const fecType = mmtpPacket[0] >> 3 & 3;
|
|
198
|
+
return packetType === 0 && fecType <= 1;
|
|
199
|
+
}
|
|
200
|
+
function classifyPacket(mmtpPacket) {
|
|
201
|
+
if (mmtpPacket.length < 2) return "unknown";
|
|
202
|
+
const packetType = mmtpPacket[1] & 63;
|
|
203
|
+
const fecType = mmtpPacket[0] >> 3 & 3;
|
|
204
|
+
if (mmtpPacket[0] >> 6 !== 0) return "unknown";
|
|
205
|
+
switch (packetType) {
|
|
206
|
+
case 0:
|
|
207
|
+
if (mmtpPacket.length < 20) return "unknown";
|
|
208
|
+
if (fecType >= 2) return "repair";
|
|
209
|
+
return "source";
|
|
210
|
+
case 2:
|
|
211
|
+
return "signaling";
|
|
212
|
+
case 3:
|
|
213
|
+
if (mmtpPacket.length < 20) return "unknown";
|
|
214
|
+
return "repair";
|
|
215
|
+
default:
|
|
216
|
+
return "unknown";
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
export {
|
|
220
|
+
ALFEC_MESSAGE_ID,
|
|
221
|
+
FEC_CODE_RAPTORQ,
|
|
222
|
+
FEC_CODE_XOR,
|
|
223
|
+
PACKET_TYPE_MPU,
|
|
224
|
+
PACKET_TYPE_REPAIR,
|
|
225
|
+
PACKET_TYPE_SIGNALING,
|
|
226
|
+
classifyPacket,
|
|
227
|
+
getPacketType,
|
|
228
|
+
isSignalingPacket,
|
|
229
|
+
isSourcePacket,
|
|
230
|
+
parseAlFecMessage
|
|
231
|
+
};
|
|
232
|
+
//# sourceMappingURL=signaling.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../mmt-alta-parse/src/index.ts", "../../mmt-base/src/mmtp.ts", "../src/signaling.ts"],
|
|
4
|
+
"sourcesContent": ["/**\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 * MMTP Signaling Parser for Multicast\n *\n * Provides packet type detection and AL-FEC signaling message parsing.\n * Used by the multicast pipeline to classify and route MMTP packets.\n *\n * Packet types (ISO/IEC 23008-1:2023 Section 9.2.2):\n * - 0x00: MPU (Media Processing Unit) - video/audio data\n * - 0x02: Signaling - control messages including AL-FEC config\n * - 0x03: Repair - FEC repair symbols\n */\nimport {\n\tALFEC_MESSAGE_ID,\n\tFEC_CODE_RAPTORQ,\n\tFEC_CODE_XOR,\n\tPACKET_TYPE_MPU,\n\tPACKET_TYPE_REPAIR,\n\tPACKET_TYPE_SIGNALING,\n\tparseAlFecMessage,\n} from \"@blockcast/mmt-base\";\n\nexport {\n\tALFEC_MESSAGE_ID,\n\tFEC_CODE_RAPTORQ,\n\tFEC_CODE_XOR,\n\tPACKET_TYPE_MPU,\n\tPACKET_TYPE_REPAIR,\n\tPACKET_TYPE_SIGNALING,\n\tparseAlFecMessage,\n};\n\nexport type PacketClass = \"source\" | \"signaling\" | \"repair\" | \"unknown\";\n\n/** Get the MMTP packet type from raw multicast packet bytes.\n *\n * ISO/IEC 23008-1:2023 Figure 8 (V=0): byte 1 is\n * reserved(2)|packet_type(6), so signaling is 0x02 and repair is 0x03.\n * Pre-migration FFmpeg high-bits bytes (0x08/0x0c) are NOT accepted:\n * writers and readers move together in the pinned smoke train.\n */\nexport function getPacketType(mmtpPacket: Uint8Array): number {\n\tif (mmtpPacket.length < 2) return -1;\n\treturn mmtpPacket[1] & 0x3f;\n}\n\n/** Check if packet is a signaling packet (type 0x02). */\nexport function isSignalingPacket(mmtpPacket: Uint8Array): boolean {\n\treturn getPacketType(mmtpPacket) === PACKET_TYPE_SIGNALING;\n}\n\n/** Determine if packet is a source (video/audio) packet. */\nexport function isSourcePacket(mmtpPacket: Uint8Array): boolean {\n\tif (mmtpPacket.length < 2) return false;\n\tconst packetType = mmtpPacket[1] & 0x3f;\n\tconst fecType = (mmtpPacket[0] >> 3) & 0x03;\n\treturn packetType === 0x00 && fecType <= 1;\n}\n\n/** Classify MMTP packet for multicast pipeline routing. */\nexport function classifyPacket(mmtpPacket: Uint8Array): PacketClass {\n\tif (mmtpPacket.length < 2) return \"unknown\";\n\tconst packetType = mmtpPacket[1] & 0x3f;\n\tconst fecType = (mmtpPacket[0] >> 3) & 0x03;\n\tif ((mmtpPacket[0] >> 6) !== 0) return \"unknown\";\n\tswitch (packetType) {\n\t\tcase 0x00:\n\t\t\tif (mmtpPacket.length < 20) return \"unknown\";\n\t\t\tif (fecType >= 2) return \"repair\";\n\t\t\treturn \"source\";\n\t\tcase 0x02:\n\t\t\treturn \"signaling\";\n\t\tcase 0x03:\n\t\t\tif (mmtpPacket.length < 20) return \"unknown\";\n\t\t\treturn \"repair\";\n\t\tdefault:\n\t\t\treturn \"unknown\";\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["MPU_HEADER_SIZE", "MPU_LENGTH_FIELD_SIZE", "MPU_HEADER_REMAINDER_SIZE", "MPU_HEADER_SIZE"]
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-auth.d.ts","sourceRoot":"","sources":["../src/source-auth.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAA"}
|