@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,778 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TrackSession — per-track transport state machine.
|
|
3
|
+
* SessionManager — orchestrates all sessions + TransportPool.
|
|
4
|
+
*
|
|
5
|
+
* Implements Patent Claim 9 (draft-ramadan-moq-fec APPLICATION-1):
|
|
6
|
+
* (a) subscribe unicast
|
|
7
|
+
* (b) simultaneously join multicast
|
|
8
|
+
* (c) render from unicast during join
|
|
9
|
+
* (d) activate multicast on RAP, suppress unicast
|
|
10
|
+
* (e) cross-transport FEC repair during transition
|
|
11
|
+
* (f) hysteresis before switching away from multicast
|
|
12
|
+
* (g) re-subscribe unicast on sustained failure
|
|
13
|
+
*
|
|
14
|
+
* PIM: manages transport state without inspecting packet contents.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
TransportPool,
|
|
19
|
+
type Subscription,
|
|
20
|
+
type SubscriptionMode,
|
|
21
|
+
type AcquireOptions,
|
|
22
|
+
type DirectSocketHealth,
|
|
23
|
+
type TransportPoolOptions,
|
|
24
|
+
} from './transport-pool.js'
|
|
25
|
+
import { deriveFecInterleaveDepth } from '@blockcast/mmt-fec'
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Types
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
export type TrackState =
|
|
32
|
+
| 'idle'
|
|
33
|
+
| 'unicast'
|
|
34
|
+
| 'unicast-fallback'
|
|
35
|
+
| 'joining'
|
|
36
|
+
| 'multicast'
|
|
37
|
+
| 'amt'
|
|
38
|
+
| 'failing'
|
|
39
|
+
|
|
40
|
+
export interface TrackSessionConfig {
|
|
41
|
+
trackName: string
|
|
42
|
+
trackType: 'video' | 'audio'
|
|
43
|
+
packetId: number
|
|
44
|
+
/** FEC interleave depth from catalog (ms). Used for hysteresis timer. */
|
|
45
|
+
fecInterleaveMs: number
|
|
46
|
+
/** FEC K from catalog. Used for audio worklet latency calculation. */
|
|
47
|
+
fecK: number
|
|
48
|
+
/** FEC repair symbols per block (P). NOT symbol size. */
|
|
49
|
+
fecRepairCount: number
|
|
50
|
+
/** FEC symbol size in bytes (T). Required for WASM decoder OTI. */
|
|
51
|
+
fecSymbolSize: number
|
|
52
|
+
/** MoQ repair track name from catalog FEC config. */
|
|
53
|
+
repairTrackName?: string
|
|
54
|
+
/** Frame samples from initData parsing (audio-init-parser.ts). */
|
|
55
|
+
frameSamples?: number
|
|
56
|
+
/** Audio sample rate from catalog. */
|
|
57
|
+
sampleRate?: number
|
|
58
|
+
/** Ordered transport preference: best first. */
|
|
59
|
+
preferredTransports: SubscriptionMode[]
|
|
60
|
+
/** Subscription key for multicast/AMT: "(S,G,port)". */
|
|
61
|
+
multicastKey?: string
|
|
62
|
+
/** MoQ track name for unicast subscription. */
|
|
63
|
+
moqTrackName?: string
|
|
64
|
+
/** AMT relay address (if AMT is in preference chain). */
|
|
65
|
+
amtRelay?: string
|
|
66
|
+
/** MoQ relay URL (for WebTransport subscription). */
|
|
67
|
+
moqRelayUrl?: string
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// PIM callbacks (protocol-independent — transport state only)
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
export interface SessionManagerCallbacks {
|
|
75
|
+
/** Fired on every transport state transition. */
|
|
76
|
+
onStateChange?(trackName: string, from: TrackState, to: TrackState): void
|
|
77
|
+
/** Fired to suppress/unsuppress unicast for this track (transport arbitration). */
|
|
78
|
+
onSuppress?(trackName: string, suppressed: boolean): void
|
|
79
|
+
/**
|
|
80
|
+
* Fired when a track sat in `joining` for SessionManager.takeoverDeadlineMs
|
|
81
|
+
* without a RAP (BLO-9413/D9). The session has already returned to `unicast`
|
|
82
|
+
* (nothing was suppressed, so nothing to restore) — the host should abandon
|
|
83
|
+
* the multicast attempt (e.g. MediaRouter.failbackToMoq()) so the router
|
|
84
|
+
* stops waiting for a keyframe that is never coming.
|
|
85
|
+
*/
|
|
86
|
+
onTakeoverTimeout?(trackName: string): void
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// MMTP application-layer extension (FEC lifecycle, media resets)
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* MMTP track events (discriminated union).
|
|
95
|
+
* Each protocol layer defines its own event union — MMTP events cover
|
|
96
|
+
* media resets, latency, and FEC lifecycle.
|
|
97
|
+
*/
|
|
98
|
+
export type MmtpTrackEvent =
|
|
99
|
+
| { type: 'reset' }
|
|
100
|
+
| { type: 'latency'; latencyMs: number }
|
|
101
|
+
| { type: 'fec-setup' }
|
|
102
|
+
| { type: 'fec-teardown' }
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* MMTP application-layer extension of SessionManagerCallbacks.
|
|
106
|
+
* Single onTrackEvent dispatches all MMTP-specific events.
|
|
107
|
+
* PIM consumers use the base SessionManagerCallbacks (no onTrackEvent).
|
|
108
|
+
*
|
|
109
|
+
* IWA can define its own subinterface with its own TrackEvent union
|
|
110
|
+
* (e.g., IwaTrackEvent for socket health, AMT state) using the same pattern.
|
|
111
|
+
*/
|
|
112
|
+
export interface MmtpSessionCallbacks extends SessionManagerCallbacks {
|
|
113
|
+
onTrackEvent?(trackName: string, event: MmtpTrackEvent, config: TrackSessionConfig): void
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Loss-hysteresis window covering the signaled interleave window plus jitter.
|
|
118
|
+
*
|
|
119
|
+
* This path lacks media cadence, so it intentionally does not estimate a full
|
|
120
|
+
* source-plus-repair production horizon. FECManager uses
|
|
121
|
+
* computeFecDeliveryWindowMs with media cadence when configuring block
|
|
122
|
+
* inactivity deadlines.
|
|
123
|
+
*
|
|
124
|
+
* `fecK` no longer feeds the math; it is still validated as a catalog
|
|
125
|
+
* well-formedness guard and kept in the signature for positional API compat
|
|
126
|
+
* (removal is a follow-up with the next cross-repo pin bump).
|
|
127
|
+
*/
|
|
128
|
+
export function computeFecLossWindowMs(fecInterleaveMs: number, fecK: number, jitterBufferMs?: number): number {
|
|
129
|
+
return computeFecDeliveryWindowMs({
|
|
130
|
+
interleaveDepthMs: fecInterleaveMs,
|
|
131
|
+
sourceSymbols: fecK,
|
|
132
|
+
jitterBufferMs,
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface FecDeliveryWindowConfig {
|
|
137
|
+
interleaveDepthMs: number
|
|
138
|
+
sourceSymbols: number
|
|
139
|
+
repairSymbols?: number
|
|
140
|
+
symbolSize?: number
|
|
141
|
+
mediaUnitsPerSecond?: number
|
|
142
|
+
bandwidthBps?: number
|
|
143
|
+
/**
|
|
144
|
+
* Jitter + one-way-delay + reorder budget in ms (draft-ramadan-moq-fec §9),
|
|
145
|
+
* sourced from the catalog `jitterBufferMs`. Added on top of the max-of-spans
|
|
146
|
+
* core; it is NOT a multiplier. See the margin-policy note in the function.
|
|
147
|
+
*/
|
|
148
|
+
jitterBufferMs?: number
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Catalog-derived silence window that covers interleave geometry plus the time
|
|
153
|
+
* required to produce or serialize a complete source+repair block. The catalog
|
|
154
|
+
* field remains D media units; this function does not feed mapper geometry.
|
|
155
|
+
*/
|
|
156
|
+
export function computeFecDeliveryWindowMs(
|
|
157
|
+
config: FecDeliveryWindowConfig,
|
|
158
|
+
): number {
|
|
159
|
+
const fecInterleaveMs = config.interleaveDepthMs
|
|
160
|
+
const fecK = config.sourceSymbols
|
|
161
|
+
if (fecInterleaveMs <= 0) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`[TrackSession] fecInterleaveMs=${fecInterleaveMs}. ` +
|
|
164
|
+
`Derive a positive FEC interleave window from the stream catalog.`
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
if (fecK <= 0) {
|
|
168
|
+
throw new Error(
|
|
169
|
+
`[TrackSession] fecK=${fecK}. ` +
|
|
170
|
+
`Derive a positive FEC source-symbol count from the stream catalog.`
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const spansMs = [fecInterleaveMs]
|
|
175
|
+
if (config.mediaUnitsPerSecond && config.mediaUnitsPerSecond > 0) {
|
|
176
|
+
const mediaUnitMs = 1000 / config.mediaUnitsPerSecond
|
|
177
|
+
// interleaveDepthMs is integer catalog signaling while media-unit duration
|
|
178
|
+
// is often fractional (for example 4/30s = 133.33ms). Recover D using the
|
|
179
|
+
// producer's nearest-ms quantization, then cover every source and repair
|
|
180
|
+
// round-robin cycle. A decoder cannot recover a partial MFU until the
|
|
181
|
+
// repair tail arrives, so a K-only deadline expires the source fragments
|
|
182
|
+
// before the final repair symbols that complete them.
|
|
183
|
+
const interleaveUnits = deriveFecInterleaveDepth(fecInterleaveMs, mediaUnitMs)
|
|
184
|
+
const deliverySymbols = fecK + Math.max(0, config.repairSymbols ?? 0)
|
|
185
|
+
spansMs.push(deliverySymbols * interleaveUnits * mediaUnitMs)
|
|
186
|
+
}
|
|
187
|
+
if (
|
|
188
|
+
config.symbolSize &&
|
|
189
|
+
config.symbolSize > 0 &&
|
|
190
|
+
config.bandwidthBps &&
|
|
191
|
+
config.bandwidthBps > 0
|
|
192
|
+
) {
|
|
193
|
+
const repairSymbols = Math.max(0, config.repairSymbols ?? 0)
|
|
194
|
+
spansMs.push(
|
|
195
|
+
((fecK + repairSymbols) * config.symbolSize * 8 * 1000) /
|
|
196
|
+
config.bandwidthBps,
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// draft-ramadan-moq-fec §9: the recovery timeout is a DERIVED budget —
|
|
201
|
+
// max(interleave span, source+repair production horizon, block serialization) PLUS
|
|
202
|
+
// an ADDITIVE margin for jitter + one-way delay + reorder. It MUST NOT be a
|
|
203
|
+
// fixed multiple of the interleave span (this replaces the retired `* 3` /
|
|
204
|
+
// `* 2` safety factors). The margin is the catalog `jitterBufferMs`.
|
|
205
|
+
//
|
|
206
|
+
// MARGIN-POLICY (operator sign-off — see PR): no catalog currently emits
|
|
207
|
+
// `jitterBufferMs`. Rather than throw (which would break every existing
|
|
208
|
+
// catalog) or invent a magic constant, the default margin is the un-rounded
|
|
209
|
+
// interleave window — the spec's natural reorder-budget bound and already a
|
|
210
|
+
// catalog value. Emit `jitterBufferMs` in the catalog to set it explicitly.
|
|
211
|
+
const coreMs = Math.max(...spansMs)
|
|
212
|
+
const marginMs =
|
|
213
|
+
config.jitterBufferMs !== undefined && config.jitterBufferMs >= 0
|
|
214
|
+
? config.jitterBufferMs
|
|
215
|
+
: fecInterleaveMs
|
|
216
|
+
return Math.ceil(coreMs) + Math.ceil(marginMs)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Convert the shared FEC delivery deadline into an integer media timescale. */
|
|
220
|
+
export function computeFecDeliveryWindowMediaUnits(
|
|
221
|
+
config: FecDeliveryWindowConfig,
|
|
222
|
+
timestampTimescale: number,
|
|
223
|
+
): number {
|
|
224
|
+
if (!Number.isFinite(timestampTimescale) || timestampTimescale <= 0) {
|
|
225
|
+
throw new Error(
|
|
226
|
+
`[TrackSession] timestampTimescale=${timestampTimescale}. ` +
|
|
227
|
+
'Derive a positive media timescale from the container.',
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
const deliveryWindow = Math.ceil(
|
|
231
|
+
computeFecDeliveryWindowMs(config) * timestampTimescale / 1000,
|
|
232
|
+
)
|
|
233
|
+
if (!Number.isSafeInteger(deliveryWindow)) {
|
|
234
|
+
throw new Error('[TrackSession] FEC delivery window exceeds the media timestamp range.')
|
|
235
|
+
}
|
|
236
|
+
return deliveryWindow
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
// TrackSession
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
|
|
243
|
+
export class TrackSession {
|
|
244
|
+
readonly config: TrackSessionConfig
|
|
245
|
+
#state: TrackState = 'idle'
|
|
246
|
+
#subscription: Subscription | null = null
|
|
247
|
+
#hysteresisTimer: ReturnType<typeof setTimeout> | null = null
|
|
248
|
+
#joinDeadlineTimer: ReturnType<typeof setTimeout> | null = null
|
|
249
|
+
#previousPrimary: SubscriptionMode | null = null
|
|
250
|
+
#manager: SessionManager
|
|
251
|
+
// Single suppression authority flag (BLO-9413 failback coherence): every
|
|
252
|
+
// suppress this session fires is recorded here, and every path that leaves
|
|
253
|
+
// a suppressed state unwinds through #unsuppress(). Before this flag,
|
|
254
|
+
// unsubscribe() only un-suppressed from multicast/amt — a session torn down
|
|
255
|
+
// from `failing` (exactly where a starving track sits) was re-subscribed to
|
|
256
|
+
// unicast with the host's media still muted: MoQ playing into a dead sink.
|
|
257
|
+
#suppressFired = false
|
|
258
|
+
|
|
259
|
+
constructor(config: TrackSessionConfig, manager: SessionManager) {
|
|
260
|
+
this.config = config
|
|
261
|
+
this.#manager = manager
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// -----------------------------------------------------------------------
|
|
265
|
+
// State
|
|
266
|
+
// -----------------------------------------------------------------------
|
|
267
|
+
|
|
268
|
+
get state(): TrackState { return this.#state }
|
|
269
|
+
get subscription(): Subscription | null { return this.#subscription }
|
|
270
|
+
|
|
271
|
+
/** True while this session's onSuppress(true) is outstanding (no matching
|
|
272
|
+
* onSuppress(false) yet). Test/assertion surface for failback coherence. */
|
|
273
|
+
get isSuppressed(): boolean { return this.#suppressFired }
|
|
274
|
+
|
|
275
|
+
/** Current active transport mode, or null if idle. */
|
|
276
|
+
get transport(): SubscriptionMode | null {
|
|
277
|
+
switch (this.#state) {
|
|
278
|
+
case 'multicast': return 'multicast'
|
|
279
|
+
case 'amt': return 'amt'
|
|
280
|
+
case 'unicast': return 'moq'
|
|
281
|
+
case 'unicast-fallback': return 'moq' // SSM bridge absent — MoQ unicast is the only source
|
|
282
|
+
case 'joining': return 'moq' // MoQ still primary during join
|
|
283
|
+
case 'failing': return this.#previousPrimary
|
|
284
|
+
default: return null
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// -----------------------------------------------------------------------
|
|
289
|
+
// Computed (no magic numbers)
|
|
290
|
+
// -----------------------------------------------------------------------
|
|
291
|
+
|
|
292
|
+
/** Audio worklet latency: max(fecInterleaveMs, frameDurationMs * fecK).
|
|
293
|
+
* Returns undefined if frame duration unknown (no initData). */
|
|
294
|
+
get audioLatencyMs(): number | undefined {
|
|
295
|
+
const fd = this.frameDurationMs
|
|
296
|
+
if (fd === undefined) {
|
|
297
|
+
return this.config.fecInterleaveMs > 0 ? this.config.fecInterleaveMs : undefined
|
|
298
|
+
}
|
|
299
|
+
return Math.max(this.config.fecInterleaveMs, fd * this.config.fecK)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Frame duration in ms, derived from frameSamples + sampleRate. */
|
|
303
|
+
get frameDurationMs(): number | undefined {
|
|
304
|
+
const { frameSamples, sampleRate } = this.config
|
|
305
|
+
if (!frameSamples || !sampleRate || sampleRate <= 0) return undefined
|
|
306
|
+
return (frameSamples / sampleRate) * 1000
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// -----------------------------------------------------------------------
|
|
310
|
+
// Transitions (Patent Claim 9)
|
|
311
|
+
// -----------------------------------------------------------------------
|
|
312
|
+
|
|
313
|
+
/** idle → unicast: player subscribes to this track. */
|
|
314
|
+
subscribe(): void {
|
|
315
|
+
if (this.#state !== 'idle') return
|
|
316
|
+
this.#transition('unicast')
|
|
317
|
+
|
|
318
|
+
// Emit audio latency on first subscribe
|
|
319
|
+
if (this.config.trackType === 'audio') {
|
|
320
|
+
const latency = this.audioLatencyMs
|
|
321
|
+
if (latency !== undefined) {
|
|
322
|
+
this.#manager.mmtp?.onTrackEvent?.(this.config.trackName, { type: 'latency', latencyMs: latency }, this.config)
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/** unicast → joining: multicast/AMT capability detected, join in progress. */
|
|
328
|
+
joinStarted(): void {
|
|
329
|
+
if (this.#state !== 'unicast') return
|
|
330
|
+
this.#transition('joining')
|
|
331
|
+
// FEC decoders must be ready before multicast data arrives (Claim 9e: cross-transport repair)
|
|
332
|
+
this.#manager.mmtp?.onTrackEvent?.(this.config.trackName, { type: 'fec-setup' }, this.config)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* any non-fallback state → unicast-fallback. Used when the SSM bridge is
|
|
337
|
+
* absent (vanilla Chromium / no extension) and the host falls back to a
|
|
338
|
+
* MoQ unicast subscription per track. Terminal-ish: activateMulticast,
|
|
339
|
+
* failbackAll, and transportFailed are no-ops while in this state.
|
|
340
|
+
*
|
|
341
|
+
* Fires fec-setup so the per-track repair worker spins up — repair packets
|
|
342
|
+
* still flow over the MoQ repair-track subscription, so FEC source+repair
|
|
343
|
+
* can converge as in the multicast path.
|
|
344
|
+
*
|
|
345
|
+
* Audio latency is NOT re-emitted here: subscribe() already fires latency
|
|
346
|
+
* once on the idle → unicast edge, and enterUnicastFallback is only ever
|
|
347
|
+
* reached from a non-idle state (SessionManager skips idle sessions).
|
|
348
|
+
*/
|
|
349
|
+
enterUnicastFallback(): void {
|
|
350
|
+
if (this.#state === 'unicast-fallback') return
|
|
351
|
+
this.#clearHysteresis()
|
|
352
|
+
this.#transition('unicast-fallback')
|
|
353
|
+
// Suppress the redundant unicast media decoder. On the no-bridge path the
|
|
354
|
+
// host feeds MoQ-unicast source packets into MulticastManager (the render
|
|
355
|
+
// consumer); a second base-media subscribe (the @moq/watch decoder) would
|
|
356
|
+
// split the single connection's QUIC flow-control budget and stall delivery
|
|
357
|
+
// (BLO-8969). Fire suppress here, on the fallback edge, so the decoder is
|
|
358
|
+
// gated off before it subscribes rather than after the relay forward task
|
|
359
|
+
// has already wedged.
|
|
360
|
+
this.#suppress()
|
|
361
|
+
this.#manager.mmtp?.onTrackEvent?.(this.config.trackName, { type: 'fec-setup' }, this.config)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* unicast-fallback → unicast. Called when the SSM bridge appears mid-session
|
|
366
|
+
* (extension installed after fallback engaged). Host first aborts the fallback
|
|
367
|
+
* drainers, then transitions sessions back to unicast so the regular
|
|
368
|
+
* multicast/AMT preference chain can take over via joinStarted().
|
|
369
|
+
*/
|
|
370
|
+
exitUnicastFallback(): void {
|
|
371
|
+
if (this.#state !== 'unicast-fallback') return
|
|
372
|
+
this.#transition('unicast')
|
|
373
|
+
// Un-suppress the unicast decoder: the bridge appeared mid-session, so the
|
|
374
|
+
// host tears down the fallback drainers and the regular preference chain
|
|
375
|
+
// (joinStarted -> joining -> rapReceived) will re-suppress on multicast RAP.
|
|
376
|
+
this.#unsuppress()
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* joining → multicast or amt: RAP received on the joined transport (Claim 9d).
|
|
381
|
+
* Resets audio worklet, then suppresses MoQ.
|
|
382
|
+
*/
|
|
383
|
+
rapReceived(mode: 'multicast' | 'amt'): void {
|
|
384
|
+
if (this.#state !== 'joining') return
|
|
385
|
+
this.#previousPrimary = mode
|
|
386
|
+
this.#transition(mode)
|
|
387
|
+
if (this.config.trackType === 'audio') {
|
|
388
|
+
this.#manager.mmtp?.onTrackEvent?.(this.config.trackName, { type: 'reset' }, this.config)
|
|
389
|
+
}
|
|
390
|
+
this.#suppress()
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/** multicast/amt → failing: loss detected, start hysteresis timer (Claim 9f). */
|
|
394
|
+
lossDetected(): void {
|
|
395
|
+
if (this.#state !== 'multicast' && this.#state !== 'amt') return
|
|
396
|
+
this.#previousPrimary = this.#state as SubscriptionMode
|
|
397
|
+
this.#transition('failing')
|
|
398
|
+
|
|
399
|
+
// Hysteresis timer: sustained loss before failback (Claim 9f). The window
|
|
400
|
+
// covers a complete FEC block plus safety margin: the catalog interleave
|
|
401
|
+
// value IS the block span (interleaveDepthMs, §5.1), scaled by the same
|
|
402
|
+
// safety factor FECManager uses for its block timeout.
|
|
403
|
+
const hysteresisMs = computeFecLossWindowMs(this.config.fecInterleaveMs, this.config.fecK)
|
|
404
|
+
this.#hysteresisTimer = setTimeout(() => {
|
|
405
|
+
this.hysteresisExpired()
|
|
406
|
+
}, hysteresisMs)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/** failing → previous primary: loss recovered within hysteresis window. */
|
|
410
|
+
lossRecovered(): void {
|
|
411
|
+
if (this.#state !== 'failing') return
|
|
412
|
+
this.#clearHysteresis()
|
|
413
|
+
if (this.#previousPrimary) {
|
|
414
|
+
this.#transition(this.#previousPrimary as TrackState)
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Transport failed (AMT relay down, multicast interface gone).
|
|
420
|
+
* Try next transport in preference chain.
|
|
421
|
+
*/
|
|
422
|
+
transportFailed(): void {
|
|
423
|
+
this.#clearHysteresis()
|
|
424
|
+
// Unicast-fallback is terminal — the host owns the subscription and
|
|
425
|
+
// SessionManager transport machinery does not arbitrate it.
|
|
426
|
+
if (this.#state === 'unicast-fallback') return
|
|
427
|
+
const current = this.#previousPrimary ?? this.transport
|
|
428
|
+
const prefs = this.config.preferredTransports
|
|
429
|
+
const currentIdx = current ? prefs.indexOf(current) : -1
|
|
430
|
+
const nextMode = prefs[currentIdx + 1]
|
|
431
|
+
|
|
432
|
+
if (nextMode) {
|
|
433
|
+
// Failover to next in chain
|
|
434
|
+
if (nextMode === 'moq') {
|
|
435
|
+
this.#transition('unicast')
|
|
436
|
+
this.#unsuppress()
|
|
437
|
+
if (this.config.trackType === 'audio') {
|
|
438
|
+
this.#manager.mmtp?.onTrackEvent?.(this.config.trackName, { type: 'reset' }, this.config)
|
|
439
|
+
}
|
|
440
|
+
} else {
|
|
441
|
+
// Next is multicast or AMT — start joining. `joining` means MoQ is
|
|
442
|
+
// primary again (see transport getter) — if the failed transport had
|
|
443
|
+
// suppressed unicast, restore it for the join window or the viewer
|
|
444
|
+
// watches black video until the next RAP (which may never come).
|
|
445
|
+
this.#transition('joining')
|
|
446
|
+
this.#unsuppress()
|
|
447
|
+
}
|
|
448
|
+
} else {
|
|
449
|
+
// End of chain — fall back to unicast (Claim 9g)
|
|
450
|
+
this.#transition('unicast')
|
|
451
|
+
this.#unsuppress()
|
|
452
|
+
if (this.config.trackType === 'audio') {
|
|
453
|
+
this.#manager.mmtp?.onTrackEvent?.(this.config.trackName, { type: 'reset' }, this.config)
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/** Hysteresis expired → failback to next transport (Claim 9g). */
|
|
459
|
+
hysteresisExpired(): void {
|
|
460
|
+
if (this.#state !== 'failing') return
|
|
461
|
+
this.#clearHysteresis()
|
|
462
|
+
this.transportFailed()
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/** → idle: player unsubscribes / tab close / cleanup. */
|
|
466
|
+
unsubscribe(): void {
|
|
467
|
+
this.#clearHysteresis()
|
|
468
|
+
if (this.#state !== 'idle') {
|
|
469
|
+
this.#transition('idle')
|
|
470
|
+
// Unwind any outstanding suppression regardless of which state we left.
|
|
471
|
+
// The old `wasActive` check (multicast/amt only) leaked suppression when
|
|
472
|
+
// tearing down from `failing` or `unicast-fallback` — failbackAll()'s
|
|
473
|
+
// unsubscribe→subscribe cycle then re-entered unicast with the host's
|
|
474
|
+
// media still muted (BLO-9413 freeze: "failing back" logged, video dead).
|
|
475
|
+
this.#unsuppress()
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/** True when SessionManager.enterUnicastFallback put this track into the
|
|
480
|
+
* host-driven unicast subscription mode. Host can iterate sessions to
|
|
481
|
+
* decide whether to keep its fallback drainer alive across MediaRouter
|
|
482
|
+
* arbitration events. */
|
|
483
|
+
get isUnicastFallback(): boolean {
|
|
484
|
+
return this.#state === 'unicast-fallback'
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
dispose(): void {
|
|
488
|
+
this.#clearHysteresis()
|
|
489
|
+
this.#clearJoinDeadline()
|
|
490
|
+
this.#state = 'idle'
|
|
491
|
+
this.#subscription = null
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// -----------------------------------------------------------------------
|
|
495
|
+
// Internal
|
|
496
|
+
// -----------------------------------------------------------------------
|
|
497
|
+
|
|
498
|
+
#transition(to: TrackState): void {
|
|
499
|
+
const from = this.#state
|
|
500
|
+
if (from === to) return
|
|
501
|
+
this.#state = to
|
|
502
|
+
// Takeover deadline (BLO-9413/D9): every entry into `joining` arms it
|
|
503
|
+
// (joinStarted AND transportFailed-failover both route through here);
|
|
504
|
+
// every exit cancels it. Without this, a transport that accepts the
|
|
505
|
+
// subscribe but never delivers a RAP parks the session in `joining`
|
|
506
|
+
// forever (observed live in the Phase-0 headless repro).
|
|
507
|
+
if (from === 'joining') this.#clearJoinDeadline()
|
|
508
|
+
if (to === 'joining') this.#armJoinDeadline()
|
|
509
|
+
// FEC teardown: leaving FEC-active states → non-FEC state
|
|
510
|
+
const fecActive = (s: TrackState) =>
|
|
511
|
+
s === 'joining' ||
|
|
512
|
+
s === 'multicast' ||
|
|
513
|
+
s === 'amt' ||
|
|
514
|
+
s === 'failing' ||
|
|
515
|
+
s === 'unicast-fallback'
|
|
516
|
+
if (fecActive(from) && !fecActive(to)) {
|
|
517
|
+
this.#manager.mmtp?.onTrackEvent?.(this.config.trackName, { type: 'fec-teardown' }, this.config)
|
|
518
|
+
}
|
|
519
|
+
this.#manager.callbacks?.onStateChange?.(this.config.trackName, from, to)
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
#clearHysteresis(): void {
|
|
523
|
+
if (this.#hysteresisTimer !== null) {
|
|
524
|
+
clearTimeout(this.#hysteresisTimer)
|
|
525
|
+
this.#hysteresisTimer = null
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
#armJoinDeadline(): void {
|
|
530
|
+
this.#clearJoinDeadline()
|
|
531
|
+
const deadlineMs = this.#manager.takeoverDeadlineMs
|
|
532
|
+
if (deadlineMs <= 0) return // disabled
|
|
533
|
+
this.#joinDeadlineTimer = setTimeout(() => {
|
|
534
|
+
this.#joinDeadlineTimer = null
|
|
535
|
+
if (this.#state !== 'joining') return
|
|
536
|
+
// No RAP within the deadline: return to unicast. MoQ was never
|
|
537
|
+
// suppressed in `joining`, so there is nothing to restore — this edge
|
|
538
|
+
// must stay silent on onSuppress (asserted in tests).
|
|
539
|
+
this.#transition('unicast')
|
|
540
|
+
this.#manager.callbacks?.onTakeoverTimeout?.(this.config.trackName)
|
|
541
|
+
}, deadlineMs)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
#clearJoinDeadline(): void {
|
|
545
|
+
if (this.#joinDeadlineTimer !== null) {
|
|
546
|
+
clearTimeout(this.#joinDeadlineTimer)
|
|
547
|
+
this.#joinDeadlineTimer = null
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/** Fire onSuppress(true) exactly once per suppression epoch. */
|
|
552
|
+
#suppress(): void {
|
|
553
|
+
if (this.#suppressFired) return
|
|
554
|
+
this.#suppressFired = true
|
|
555
|
+
this.#manager.callbacks?.onSuppress?.(this.config.trackName, true)
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/** Unwind an outstanding suppression; no-op when none is outstanding. */
|
|
559
|
+
#unsuppress(): void {
|
|
560
|
+
if (!this.#suppressFired) return
|
|
561
|
+
this.#suppressFired = false
|
|
562
|
+
this.#manager.callbacks?.onSuppress?.(this.config.trackName, false)
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// ---------------------------------------------------------------------------
|
|
567
|
+
// SessionManager
|
|
568
|
+
// ---------------------------------------------------------------------------
|
|
569
|
+
|
|
570
|
+
export class SessionManager {
|
|
571
|
+
readonly pool: TransportPool
|
|
572
|
+
readonly sessions = new Map<string, TrackSession>()
|
|
573
|
+
callbacks: SessionManagerCallbacks | null = null
|
|
574
|
+
/**
|
|
575
|
+
* Takeover deadline (BLO-9413/D9): max time a session may sit in `joining`
|
|
576
|
+
* without a RAP before returning to `unicast` and firing onTakeoverTimeout.
|
|
577
|
+
* MoQ is never suppressed during `joining`, so expiry is a silent abandon —
|
|
578
|
+
* playback never glitches. Hosts tune per stream (e.g. GOP length); 0
|
|
579
|
+
* disables.
|
|
580
|
+
*/
|
|
581
|
+
takeoverDeadlineMs = 5000
|
|
582
|
+
|
|
583
|
+
/** Narrow to MMTP callbacks (onTrackEvent). Safe — optional chaining handles PIM-only consumers. */
|
|
584
|
+
get mmtp(): MmtpSessionCallbacks | null {
|
|
585
|
+
return this.callbacks as MmtpSessionCallbacks | null
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
constructor(poolOptions?: TransportPoolOptions) {
|
|
589
|
+
this.pool = new TransportPool(poolOptions)
|
|
590
|
+
|
|
591
|
+
// Wire pool failure → per-track failover
|
|
592
|
+
this.pool.onSubscriptionFailed(sub => {
|
|
593
|
+
for (const trackName of sub.consumers) {
|
|
594
|
+
const session = this.sessions.get(trackName)
|
|
595
|
+
if (session) session.transportFailed()
|
|
596
|
+
}
|
|
597
|
+
})
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// -----------------------------------------------------------------------
|
|
601
|
+
// Track management
|
|
602
|
+
// -----------------------------------------------------------------------
|
|
603
|
+
|
|
604
|
+
/** Add a track session from catalog config. */
|
|
605
|
+
addTrack(config: TrackSessionConfig): TrackSession {
|
|
606
|
+
if (this.sessions.has(config.trackName)) {
|
|
607
|
+
throw new Error(`[SessionManager] Track "${config.trackName}" already exists`)
|
|
608
|
+
}
|
|
609
|
+
const session = new TrackSession(config, this)
|
|
610
|
+
this.sessions.set(config.trackName, session)
|
|
611
|
+
return session
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/** Remove a track session. Releases subscription with grace period. */
|
|
615
|
+
removeTrack(trackName: string): void {
|
|
616
|
+
const session = this.sessions.get(trackName)
|
|
617
|
+
if (!session) return
|
|
618
|
+
session.unsubscribe()
|
|
619
|
+
|
|
620
|
+
// Release pool subscription
|
|
621
|
+
const subKey = session.config.multicastKey ?? session.config.moqTrackName
|
|
622
|
+
if (subKey) this.pool.releaseSubscription(subKey, trackName)
|
|
623
|
+
|
|
624
|
+
session.dispose()
|
|
625
|
+
this.sessions.delete(trackName)
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// -----------------------------------------------------------------------
|
|
629
|
+
// Atomic multi-track operations
|
|
630
|
+
// -----------------------------------------------------------------------
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* All tracks with multicast RAP → multicast state (atomic).
|
|
634
|
+
* Called when MediaRouter fires onSourceSwitch('multicast').
|
|
635
|
+
* Prevents split-brain between video and audio.
|
|
636
|
+
*
|
|
637
|
+
* A takeover deadline can return a track from `joining` to `unicast` while
|
|
638
|
+
* the multicast socket keeps delivering packets. If a valid RAP arrives
|
|
639
|
+
* later, allow that late-RAP edge to suppress unicast and promote multicast.
|
|
640
|
+
*/
|
|
641
|
+
activateMulticast(): void {
|
|
642
|
+
for (const [, session] of this.sessions) {
|
|
643
|
+
if (session.state === 'unicast') {
|
|
644
|
+
session.joinStarted()
|
|
645
|
+
}
|
|
646
|
+
if (session.state === 'joining') {
|
|
647
|
+
session.rapReceived('multicast')
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* All tracks with AMT RAP → amt state (atomic).
|
|
654
|
+
*/
|
|
655
|
+
activateAmt(): void {
|
|
656
|
+
for (const [, session] of this.sessions) {
|
|
657
|
+
if (session.state === 'unicast') {
|
|
658
|
+
session.joinStarted()
|
|
659
|
+
}
|
|
660
|
+
if (session.state === 'joining') {
|
|
661
|
+
session.rapReceived('amt')
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* All tracks → unicast (failback, atomic).
|
|
668
|
+
* Called when MulticastManager fires onFailback().
|
|
669
|
+
* unicast-fallback sessions are skipped — the host owns those subscriptions
|
|
670
|
+
* and they must drain uninterrupted across transport-state events.
|
|
671
|
+
*
|
|
672
|
+
* Coherence invariant (BLO-9413): after this returns, every non-fallback
|
|
673
|
+
* session is `unicast` (or `idle`) AND unsuppressed — unsubscribe() unwinds
|
|
674
|
+
* any outstanding suppression regardless of the state it tears down from
|
|
675
|
+
* (`failing` included; see TrackSession.#suppressFired).
|
|
676
|
+
*/
|
|
677
|
+
failbackAll(): void {
|
|
678
|
+
for (const [, session] of this.sessions) {
|
|
679
|
+
if (
|
|
680
|
+
session.state !== 'idle' &&
|
|
681
|
+
session.state !== 'unicast' &&
|
|
682
|
+
session.state !== 'unicast-fallback'
|
|
683
|
+
) {
|
|
684
|
+
session.unsubscribe()
|
|
685
|
+
session.subscribe() // re-enter unicast
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* All tracks → unicast-fallback (atomic).
|
|
692
|
+
* Called by the host when the multicast gateway is absent and
|
|
693
|
+
* the player will subscribe to source tracks over MoQ unicast and feed
|
|
694
|
+
* packets via MulticastManager.feedUnicastSource() (or manager.router
|
|
695
|
+
* directly). Sessions in this state stay terminal until the host calls
|
|
696
|
+
* unsubscribe() / disposes the SessionManager.
|
|
697
|
+
*/
|
|
698
|
+
enterUnicastFallback(): void {
|
|
699
|
+
for (const [, session] of this.sessions) {
|
|
700
|
+
if (session.state === 'idle') continue
|
|
701
|
+
session.enterUnicastFallback()
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* True if any session is currently in unicast-fallback. Hosts use this to
|
|
707
|
+
* gate `multicastTrack.close()` on failback events — closing the shared
|
|
708
|
+
* broadcast would kill the host's fallback drainers.
|
|
709
|
+
*/
|
|
710
|
+
hasActiveFallback(): boolean {
|
|
711
|
+
for (const [, session] of this.sessions) {
|
|
712
|
+
if (session.isUnicastFallback) return true
|
|
713
|
+
}
|
|
714
|
+
return false
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* All fallback tracks → unicast (atomic).
|
|
719
|
+
* Called when the SSM bridge appears mid-session and the host has aborted
|
|
720
|
+
* the fallback drainers. The session re-enters the regular preference chain
|
|
721
|
+
* via joinStarted() (issued by the host immediately after).
|
|
722
|
+
*/
|
|
723
|
+
exitUnicastFallback(): void {
|
|
724
|
+
for (const [, session] of this.sessions) {
|
|
725
|
+
if (session.isUnicastFallback) session.exitUnicastFallback()
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// -----------------------------------------------------------------------
|
|
730
|
+
// Cleanup lifecycle
|
|
731
|
+
// -----------------------------------------------------------------------
|
|
732
|
+
|
|
733
|
+
/** Tab closed — release all subscriptions for this tab (grace period). */
|
|
734
|
+
tabClosed(tabId: string): void {
|
|
735
|
+
// All tracks owned by this tab → idle
|
|
736
|
+
for (const [trackName, session] of this.sessions) {
|
|
737
|
+
session.unsubscribe()
|
|
738
|
+
this.pool.releaseAllForConsumer(trackName)
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/** Bridge WebTransport connection dropped — same as tab close. */
|
|
743
|
+
bridgeDisconnected(): void {
|
|
744
|
+
this.tabClosed('bridge')
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Track selection changed (user or ABR).
|
|
749
|
+
* Old track released (grace period), new track subscribed.
|
|
750
|
+
*/
|
|
751
|
+
trackSelectionChanged(oldTrackName: string, newConfig: TrackSessionConfig): void {
|
|
752
|
+
this.removeTrack(oldTrackName)
|
|
753
|
+
const session = this.addTrack(newConfig)
|
|
754
|
+
session.subscribe()
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// -----------------------------------------------------------------------
|
|
758
|
+
// Query
|
|
759
|
+
// -----------------------------------------------------------------------
|
|
760
|
+
|
|
761
|
+
/** Get a track session by name. */
|
|
762
|
+
getTrack(trackName: string): TrackSession | undefined {
|
|
763
|
+
return this.sessions.get(trackName)
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// -----------------------------------------------------------------------
|
|
767
|
+
// Cleanup
|
|
768
|
+
// -----------------------------------------------------------------------
|
|
769
|
+
|
|
770
|
+
dispose(): void {
|
|
771
|
+
for (const [, session] of this.sessions) {
|
|
772
|
+
session.dispose()
|
|
773
|
+
}
|
|
774
|
+
this.sessions.clear()
|
|
775
|
+
this.pool.dispose()
|
|
776
|
+
this.callbacks = null
|
|
777
|
+
}
|
|
778
|
+
}
|