@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.
Files changed (678) hide show
  1. package/README.md +432 -0
  2. package/dist/.build-stamp +0 -0
  3. package/dist/__tests__/test-utils.d.ts +71 -0
  4. package/dist/__tests__/test-utils.d.ts.map +1 -0
  5. package/dist/align.d.ts +148 -0
  6. package/dist/align.d.ts.map +1 -0
  7. package/dist/align.js +88 -0
  8. package/dist/align.js.map +7 -0
  9. package/dist/audio-init-parser.d.ts +66 -0
  10. package/dist/audio-init-parser.d.ts.map +1 -0
  11. package/dist/audio-init-parser.js +118 -0
  12. package/dist/audio-init-parser.js.map +7 -0
  13. package/dist/audio-ring-buffer.d.ts +50 -0
  14. package/dist/audio-ring-buffer.d.ts.map +1 -0
  15. package/dist/audio-ring-buffer.js +93 -0
  16. package/dist/audio-ring-buffer.js.map +7 -0
  17. package/dist/authored-timing.d.ts +32 -0
  18. package/dist/authored-timing.d.ts.map +1 -0
  19. package/dist/authored-timing.js +32 -0
  20. package/dist/authored-timing.js.map +7 -0
  21. package/dist/browser-runtime.js +17109 -0
  22. package/dist/browser-runtime.js.map +7 -0
  23. package/dist/carp-catalog.d.ts +318 -0
  24. package/dist/carp-catalog.d.ts.map +1 -0
  25. package/dist/carp-catalog.js +549 -0
  26. package/dist/carp-catalog.js.map +7 -0
  27. package/dist/catalog-fec-params.d.ts +82 -0
  28. package/dist/catalog-fec-params.d.ts.map +1 -0
  29. package/dist/catalog-fec-params.js +66 -0
  30. package/dist/catalog-fec-params.js.map +7 -0
  31. package/dist/catalog-network-source.d.ts +19 -0
  32. package/dist/catalog-network-source.d.ts.map +1 -0
  33. package/dist/catalog-network-source.js +22 -0
  34. package/dist/catalog-network-source.js.map +7 -0
  35. package/dist/catalog-validator.d.ts +18 -0
  36. package/dist/catalog-validator.d.ts.map +1 -0
  37. package/dist/catalog-validator.js +7747 -0
  38. package/dist/catalog-validator.js.map +7 -0
  39. package/dist/cmaf-block-assembler.d.ts +168 -0
  40. package/dist/cmaf-block-assembler.d.ts.map +1 -0
  41. package/dist/cmaf-block-assembler.js +1755 -0
  42. package/dist/cmaf-block-assembler.js.map +7 -0
  43. package/dist/cmaf-group-batcher.d.ts +38 -0
  44. package/dist/cmaf-group-batcher.d.ts.map +1 -0
  45. package/dist/cmaf-group-batcher.js +195 -0
  46. package/dist/cmaf-group-batcher.js.map +7 -0
  47. package/dist/cmcd-producer.d.ts +104 -0
  48. package/dist/cmcd-producer.d.ts.map +1 -0
  49. package/dist/cmcd-producer.js +207 -0
  50. package/dist/cmcd-producer.js.map +7 -0
  51. package/dist/codec-utils.d.ts +235 -0
  52. package/dist/codec-utils.d.ts.map +1 -0
  53. package/dist/codec-utils.js +1225 -0
  54. package/dist/codec-utils.js.map +7 -0
  55. package/dist/fec-codec.d.ts +32 -0
  56. package/dist/fec-codec.d.ts.map +1 -0
  57. package/dist/fec-codec.js +47 -0
  58. package/dist/fec-codec.js.map +7 -0
  59. package/dist/fec-manager.d.ts +266 -0
  60. package/dist/fec-manager.d.ts.map +1 -0
  61. package/dist/fec-manager.js +1447 -0
  62. package/dist/fec-manager.js.map +7 -0
  63. package/dist/fec-starvation-detector.d.ts +59 -0
  64. package/dist/fec-starvation-detector.d.ts.map +1 -0
  65. package/dist/fec-starvation-detector.js +75 -0
  66. package/dist/fec-starvation-detector.js.map +7 -0
  67. package/dist/fec-worker-setup.d.ts +76 -0
  68. package/dist/fec-worker-setup.d.ts.map +1 -0
  69. package/dist/fec-worker-setup.js +603 -0
  70. package/dist/fec-worker-setup.js.map +7 -0
  71. package/dist/fmp4-completion.d.ts +30 -0
  72. package/dist/fmp4-completion.d.ts.map +1 -0
  73. package/dist/fmp4-completion.js +21 -0
  74. package/dist/fmp4-completion.js.map +7 -0
  75. package/dist/fmp4-reader.d.ts +37 -0
  76. package/dist/fmp4-reader.d.ts.map +1 -0
  77. package/dist/fmp4-reader.js +100 -0
  78. package/dist/fmp4-reader.js.map +7 -0
  79. package/dist/index.d.ts +47 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +330 -0
  82. package/dist/index.js.map +7 -0
  83. package/dist/iso-bmff-timing.d.ts +47 -0
  84. package/dist/iso-bmff-timing.d.ts.map +1 -0
  85. package/dist/iso-bmff-timing.js +526 -0
  86. package/dist/iso-bmff-timing.js.map +7 -0
  87. package/dist/loc.d.ts +68 -0
  88. package/dist/loc.d.ts.map +1 -0
  89. package/dist/loc.js +143 -0
  90. package/dist/loc.js.map +7 -0
  91. package/dist/manifest-auth-plan.d.ts +30 -0
  92. package/dist/manifest-auth-plan.d.ts.map +1 -0
  93. package/dist/manifest-auth-plan.js +1267 -0
  94. package/dist/manifest-auth-plan.js.map +7 -0
  95. package/dist/media-router.d.ts +338 -0
  96. package/dist/media-router.d.ts.map +1 -0
  97. package/dist/media-router.js +802 -0
  98. package/dist/media-router.js.map +7 -0
  99. package/dist/mfu-reassembler.d.ts +264 -0
  100. package/dist/mfu-reassembler.d.ts.map +1 -0
  101. package/dist/mfu-reassembler.js +2668 -0
  102. package/dist/mfu-reassembler.js.map +7 -0
  103. package/dist/mfu-reassembly-policy.d.ts +24 -0
  104. package/dist/mfu-reassembly-policy.d.ts.map +1 -0
  105. package/dist/mfu-reassembly-policy.js +99 -0
  106. package/dist/mfu-reassembly-policy.js.map +7 -0
  107. package/dist/mmtp-container-parser.d.ts +304 -0
  108. package/dist/mmtp-container-parser.d.ts.map +1 -0
  109. package/dist/mmtp-container-parser.js +5378 -0
  110. package/dist/mmtp-container-parser.js.map +7 -0
  111. package/dist/mmtp-container-parser.no-modules.js +7853 -0
  112. package/dist/mmtp-container-parser.no-modules.js.map +7 -0
  113. package/dist/mmtp-decode-pipeline.d.ts +96 -0
  114. package/dist/mmtp-decode-pipeline.d.ts.map +1 -0
  115. package/dist/mmtp-decode-pipeline.js +5589 -0
  116. package/dist/mmtp-decode-pipeline.js.map +7 -0
  117. package/dist/mmtp-router.d.ts +383 -0
  118. package/dist/mmtp-router.d.ts.map +1 -0
  119. package/dist/mmtp-router.js +8384 -0
  120. package/dist/mmtp-router.js.map +7 -0
  121. package/dist/mmtp-to-cmaf.d.ts +166 -0
  122. package/dist/mmtp-to-cmaf.d.ts.map +1 -0
  123. package/dist/mmtp-to-cmaf.js +781 -0
  124. package/dist/mmtp-to-cmaf.js.map +7 -0
  125. package/dist/multicast-auth-catalog.d.ts +115 -0
  126. package/dist/multicast-auth-catalog.d.ts.map +1 -0
  127. package/dist/multicast-auth-catalog.js +202 -0
  128. package/dist/multicast-auth-catalog.js.map +7 -0
  129. package/dist/multicast-input.d.ts +107 -0
  130. package/dist/multicast-input.d.ts.map +1 -0
  131. package/dist/multicast-input.js +256 -0
  132. package/dist/multicast-input.js.map +7 -0
  133. package/dist/multicast-manager.d.ts +330 -0
  134. package/dist/multicast-manager.d.ts.map +1 -0
  135. package/dist/multicast-manager.js +11032 -0
  136. package/dist/multicast-manager.js.map +7 -0
  137. package/dist/multicast-transport.d.ts +62 -0
  138. package/dist/multicast-transport.d.ts.map +1 -0
  139. package/dist/multicast-transport.js +338 -0
  140. package/dist/multicast-transport.js.map +7 -0
  141. package/dist/multicast-unwrap.d.ts +57 -0
  142. package/dist/multicast-unwrap.d.ts.map +1 -0
  143. package/dist/multicast-unwrap.js +384 -0
  144. package/dist/multicast-unwrap.js.map +7 -0
  145. package/dist/no-modules.d.ts +9 -0
  146. package/dist/no-modules.d.ts.map +1 -0
  147. package/dist/no-modules.js +7819 -0
  148. package/dist/no-modules.js.map +7 -0
  149. package/dist/phase14-catalog-override.d.ts +126 -0
  150. package/dist/phase14-catalog-override.d.ts.map +1 -0
  151. package/dist/phase14-catalog-override.js +155 -0
  152. package/dist/phase14-catalog-override.js.map +7 -0
  153. package/dist/repair-fetch.d.ts +58 -0
  154. package/dist/repair-fetch.d.ts.map +1 -0
  155. package/dist/repair-fetch.js +117 -0
  156. package/dist/repair-fetch.js.map +7 -0
  157. package/dist/sample-combiner.d.ts +182 -0
  158. package/dist/sample-combiner.d.ts.map +1 -0
  159. package/dist/sample-combiner.js +571 -0
  160. package/dist/sample-combiner.js.map +7 -0
  161. package/dist/signaling.d.ts +29 -0
  162. package/dist/signaling.d.ts.map +1 -0
  163. package/dist/signaling.js +232 -0
  164. package/dist/signaling.js.map +7 -0
  165. package/dist/source-auth.d.ts +2 -0
  166. package/dist/source-auth.d.ts.map +1 -0
  167. package/dist/source-auth.js +1220 -0
  168. package/dist/source-auth.js.map +7 -0
  169. package/dist/switching-set-alignment.d.ts +61 -0
  170. package/dist/switching-set-alignment.d.ts.map +1 -0
  171. package/dist/switching-set-alignment.js +85 -0
  172. package/dist/switching-set-alignment.js.map +7 -0
  173. package/dist/timestamp-codec.d.ts +34 -0
  174. package/dist/timestamp-codec.d.ts.map +1 -0
  175. package/dist/timestamp-codec.js +456 -0
  176. package/dist/timestamp-codec.js.map +7 -0
  177. package/dist/track-pipeline-setup.d.ts +72 -0
  178. package/dist/track-pipeline-setup.d.ts.map +1 -0
  179. package/dist/track-pipeline-setup.js +306 -0
  180. package/dist/track-pipeline-setup.js.map +7 -0
  181. package/dist/track-pipeline.d.ts +121 -0
  182. package/dist/track-pipeline.d.ts.map +1 -0
  183. package/dist/track-pipeline.js +229 -0
  184. package/dist/track-pipeline.js.map +7 -0
  185. package/dist/track-session.d.ts +269 -0
  186. package/dist/track-session.d.ts.map +1 -0
  187. package/dist/track-session.js +597 -0
  188. package/dist/track-session.js.map +7 -0
  189. package/dist/transport-pool.d.ts +69 -0
  190. package/dist/transport-pool.d.ts.map +1 -0
  191. package/dist/transport-pool.js +88 -0
  192. package/dist/transport-pool.js.map +7 -0
  193. package/dist/wasm-mfu-reassembler.d.ts +81 -0
  194. package/dist/wasm-mfu-reassembler.d.ts.map +1 -0
  195. package/dist/wasm-mfu-reassembler.js +1915 -0
  196. package/dist/wasm-mfu-reassembler.js.map +7 -0
  197. package/dist/wasm-mmtp-container-parser.d.ts +10 -0
  198. package/dist/wasm-mmtp-container-parser.d.ts.map +1 -0
  199. package/dist/wasm-mmtp-container-parser.js +5635 -0
  200. package/dist/wasm-mmtp-container-parser.js.map +7 -0
  201. package/node_modules/@blockcast/fec-worker/README.md +213 -0
  202. package/node_modules/@blockcast/fec-worker/dist/.build-stamp +0 -0
  203. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.d.ts +80 -0
  204. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.d.ts.map +1 -0
  205. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.js +270 -0
  206. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.js.map +1 -0
  207. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts +252 -0
  208. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts.map +1 -0
  209. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.js +11 -0
  210. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.js.map +1 -0
  211. package/node_modules/@blockcast/fec-worker/dist/fec-worker.d.ts +14 -0
  212. package/node_modules/@blockcast/fec-worker/dist/fec-worker.d.ts.map +1 -0
  213. package/node_modules/@blockcast/fec-worker/dist/fec-worker.js +565 -0
  214. package/node_modules/@blockcast/fec-worker/dist/fec-worker.js.map +7 -0
  215. package/node_modules/@blockcast/fec-worker/dist/index.d.ts +10 -0
  216. package/node_modules/@blockcast/fec-worker/dist/index.d.ts.map +1 -0
  217. package/node_modules/@blockcast/fec-worker/dist/index.js +8 -0
  218. package/node_modules/@blockcast/fec-worker/dist/index.js.map +1 -0
  219. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.d.ts +20 -0
  220. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.d.ts.map +1 -0
  221. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.js +349 -0
  222. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.js.map +7 -0
  223. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.d.ts +104 -0
  224. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.d.ts.map +1 -0
  225. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.js +181 -0
  226. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.js.map +1 -0
  227. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.d.ts +179 -0
  228. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.d.ts.map +1 -0
  229. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.js +47 -0
  230. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.js.map +1 -0
  231. package/node_modules/@blockcast/fec-worker/dist/transfer.d.ts +9 -0
  232. package/node_modules/@blockcast/fec-worker/dist/transfer.d.ts.map +1 -0
  233. package/node_modules/@blockcast/fec-worker/dist/transfer.js +13 -0
  234. package/node_modules/@blockcast/fec-worker/dist/transfer.js.map +1 -0
  235. package/node_modules/@blockcast/fec-worker/package.json +59 -0
  236. package/node_modules/@blockcast/fec-worker/src/fec-worker-client.ts +309 -0
  237. package/node_modules/@blockcast/fec-worker/src/fec-worker-types.ts +268 -0
  238. package/node_modules/@blockcast/fec-worker/src/fec-worker.ts +1048 -0
  239. package/node_modules/@blockcast/fec-worker/src/index.ts +32 -0
  240. package/node_modules/@blockcast/fec-worker/src/shred-fec-worker.ts +558 -0
  241. package/node_modules/@blockcast/fec-worker/src/shred-worker-client.ts +222 -0
  242. package/node_modules/@blockcast/fec-worker/src/shred-worker-types.ts +194 -0
  243. package/node_modules/@blockcast/fec-worker/src/transfer.ts +12 -0
  244. package/node_modules/@blockcast/mmt-alta-parse/README.md +181 -0
  245. package/node_modules/@blockcast/mmt-alta-parse/dist/.build-stamp +0 -0
  246. package/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts +57 -0
  247. package/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts.map +1 -0
  248. package/node_modules/@blockcast/mmt-alta-parse/dist/index.js +115 -0
  249. package/node_modules/@blockcast/mmt-alta-parse/dist/index.js.map +1 -0
  250. package/node_modules/@blockcast/mmt-alta-parse/package.json +50 -0
  251. package/node_modules/@blockcast/mmt-alta-parse/src/index.ts +136 -0
  252. package/node_modules/@blockcast/mmt-base/README.md +120 -0
  253. package/node_modules/@blockcast/mmt-base/dist/.build-stamp +0 -0
  254. package/node_modules/@blockcast/mmt-base/dist/index.d.ts +2 -0
  255. package/node_modules/@blockcast/mmt-base/dist/index.d.ts.map +1 -0
  256. package/node_modules/@blockcast/mmt-base/dist/index.js +2 -0
  257. package/node_modules/@blockcast/mmt-base/dist/index.js.map +1 -0
  258. package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +275 -0
  259. package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -0
  260. package/node_modules/@blockcast/mmt-base/dist/mmtp.js +644 -0
  261. package/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -0
  262. package/node_modules/@blockcast/mmt-base/package.json +49 -0
  263. package/node_modules/@blockcast/mmt-base/src/index.ts +1 -0
  264. package/node_modules/@blockcast/mmt-base/src/mmtp.ts +898 -0
  265. package/node_modules/@blockcast/mmt-fec/README.md +270 -0
  266. package/node_modules/@blockcast/mmt-fec/dist/.build-stamp +0 -0
  267. package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts +80 -0
  268. package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts.map +1 -0
  269. package/node_modules/@blockcast/mmt-fec/dist/block-manager.js +294 -0
  270. package/node_modules/@blockcast/mmt-fec/dist/block-manager.js.map +1 -0
  271. package/node_modules/@blockcast/mmt-fec/dist/block-processor.d.ts +72 -0
  272. package/node_modules/@blockcast/mmt-fec/dist/block-processor.d.ts.map +1 -0
  273. package/node_modules/@blockcast/mmt-fec/dist/block-processor.js +192 -0
  274. package/node_modules/@blockcast/mmt-fec/dist/block-processor.js.map +1 -0
  275. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.d.ts +46 -0
  276. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.d.ts.map +1 -0
  277. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.js +96 -0
  278. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.js.map +1 -0
  279. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.d.ts +33 -0
  280. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.d.ts.map +1 -0
  281. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.js +57 -0
  282. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.js.map +1 -0
  283. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.d.ts +185 -0
  284. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.d.ts.map +1 -0
  285. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.js +273 -0
  286. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.js.map +1 -0
  287. package/node_modules/@blockcast/mmt-fec/dist/index.d.ts +22 -0
  288. package/node_modules/@blockcast/mmt-fec/dist/index.d.ts.map +1 -0
  289. package/node_modules/@blockcast/mmt-fec/dist/index.js +22 -0
  290. package/node_modules/@blockcast/mmt-fec/dist/index.js.map +1 -0
  291. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.d.ts +20 -0
  292. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.d.ts.map +1 -0
  293. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.js +28 -0
  294. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.js.map +1 -0
  295. package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts +174 -0
  296. package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts.map +1 -0
  297. package/node_modules/@blockcast/mmt-fec/dist/oti.js +256 -0
  298. package/node_modules/@blockcast/mmt-fec/dist/oti.js.map +1 -0
  299. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.d.ts +41 -0
  300. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.d.ts.map +1 -0
  301. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.js +81 -0
  302. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.js.map +1 -0
  303. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/README.md +181 -0
  304. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/.build-stamp +0 -0
  305. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts +57 -0
  306. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts.map +1 -0
  307. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.js +115 -0
  308. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.js.map +1 -0
  309. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/package.json +50 -0
  310. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/src/index.ts +136 -0
  311. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/README.md +120 -0
  312. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/.build-stamp +0 -0
  313. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.d.ts +2 -0
  314. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.d.ts.map +1 -0
  315. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.js +2 -0
  316. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.js.map +1 -0
  317. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +275 -0
  318. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -0
  319. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js +644 -0
  320. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -0
  321. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/package.json +49 -0
  322. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/index.ts +1 -0
  323. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/mmtp.ts +898 -0
  324. package/node_modules/@blockcast/mmt-fec/package.json +79 -0
  325. package/node_modules/@blockcast/mmt-fec/src/block-manager.ts +369 -0
  326. package/node_modules/@blockcast/mmt-fec/src/block-processor.ts +277 -0
  327. package/node_modules/@blockcast/mmt-fec/src/cmaf-recovery.ts +127 -0
  328. package/node_modules/@blockcast/mmt-fec/src/cmaf-symbols.ts +68 -0
  329. package/node_modules/@blockcast/mmt-fec/src/fec-block-mapper.ts +332 -0
  330. package/node_modules/@blockcast/mmt-fec/src/index.ts +77 -0
  331. package/node_modules/@blockcast/mmt-fec/src/loc-symbols.ts +34 -0
  332. package/node_modules/@blockcast/mmt-fec/src/oti.ts +319 -0
  333. package/node_modules/@blockcast/mmt-fec/src/reorder-buffer.ts +101 -0
  334. package/node_modules/@blockcast/mmt-manifest-verify/dist/.build-stamp +0 -0
  335. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.d.ts +28 -0
  336. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.d.ts.map +1 -0
  337. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.js +128 -0
  338. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.js.map +1 -0
  339. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.d.ts +4 -0
  340. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.d.ts.map +1 -0
  341. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.js +4 -0
  342. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.js.map +1 -0
  343. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.d.ts +37 -0
  344. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.d.ts.map +1 -0
  345. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.js +179 -0
  346. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.js.map +1 -0
  347. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts +90 -0
  348. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts.map +1 -0
  349. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js +462 -0
  350. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js.map +1 -0
  351. package/node_modules/@blockcast/mmt-manifest-verify/package.json +45 -0
  352. package/node_modules/@blockcast/mmt-manifest-verify/src/admission.ts +171 -0
  353. package/node_modules/@blockcast/mmt-manifest-verify/src/index.ts +3 -0
  354. package/node_modules/@blockcast/mmt-manifest-verify/src/source-auth.ts +230 -0
  355. package/node_modules/@blockcast/mmt-manifest-verify/src/verifier.ts +636 -0
  356. package/node_modules/@noble/hashes/LICENSE +21 -0
  357. package/node_modules/@noble/hashes/README.md +521 -0
  358. package/node_modules/@noble/hashes/_assert.d.ts +17 -0
  359. package/node_modules/@noble/hashes/_assert.d.ts.map +1 -0
  360. package/node_modules/@noble/hashes/_assert.js +18 -0
  361. package/node_modules/@noble/hashes/_assert.js.map +1 -0
  362. package/node_modules/@noble/hashes/_blake.d.ts +14 -0
  363. package/node_modules/@noble/hashes/_blake.d.ts.map +1 -0
  364. package/node_modules/@noble/hashes/_blake.js +50 -0
  365. package/node_modules/@noble/hashes/_blake.js.map +1 -0
  366. package/node_modules/@noble/hashes/_md.d.ts +51 -0
  367. package/node_modules/@noble/hashes/_md.d.ts.map +1 -0
  368. package/node_modules/@noble/hashes/_md.js +162 -0
  369. package/node_modules/@noble/hashes/_md.js.map +1 -0
  370. package/node_modules/@noble/hashes/_u64.d.ts +55 -0
  371. package/node_modules/@noble/hashes/_u64.d.ts.map +1 -0
  372. package/node_modules/@noble/hashes/_u64.js +90 -0
  373. package/node_modules/@noble/hashes/_u64.js.map +1 -0
  374. package/node_modules/@noble/hashes/argon2.d.ts +32 -0
  375. package/node_modules/@noble/hashes/argon2.d.ts.map +1 -0
  376. package/node_modules/@noble/hashes/argon2.js +401 -0
  377. package/node_modules/@noble/hashes/argon2.js.map +1 -0
  378. package/node_modules/@noble/hashes/blake1.d.ts +106 -0
  379. package/node_modules/@noble/hashes/blake1.d.ts.map +1 -0
  380. package/node_modules/@noble/hashes/blake1.js +459 -0
  381. package/node_modules/@noble/hashes/blake1.js.map +1 -0
  382. package/node_modules/@noble/hashes/blake2.d.ts +116 -0
  383. package/node_modules/@noble/hashes/blake2.d.ts.map +1 -0
  384. package/node_modules/@noble/hashes/blake2.js +420 -0
  385. package/node_modules/@noble/hashes/blake2.js.map +1 -0
  386. package/node_modules/@noble/hashes/blake2b.d.ts +11 -0
  387. package/node_modules/@noble/hashes/blake2b.d.ts.map +1 -0
  388. package/node_modules/@noble/hashes/blake2b.js +14 -0
  389. package/node_modules/@noble/hashes/blake2b.js.map +1 -0
  390. package/node_modules/@noble/hashes/blake2s.d.ts +20 -0
  391. package/node_modules/@noble/hashes/blake2s.d.ts.map +1 -0
  392. package/node_modules/@noble/hashes/blake2s.js +24 -0
  393. package/node_modules/@noble/hashes/blake2s.js.map +1 -0
  394. package/node_modules/@noble/hashes/blake3.d.ts +54 -0
  395. package/node_modules/@noble/hashes/blake3.d.ts.map +1 -0
  396. package/node_modules/@noble/hashes/blake3.js +255 -0
  397. package/node_modules/@noble/hashes/blake3.js.map +1 -0
  398. package/node_modules/@noble/hashes/crypto.d.ts +2 -0
  399. package/node_modules/@noble/hashes/crypto.d.ts.map +1 -0
  400. package/node_modules/@noble/hashes/crypto.js +5 -0
  401. package/node_modules/@noble/hashes/crypto.js.map +1 -0
  402. package/node_modules/@noble/hashes/cryptoNode.d.ts +2 -0
  403. package/node_modules/@noble/hashes/cryptoNode.d.ts.map +1 -0
  404. package/node_modules/@noble/hashes/cryptoNode.js +18 -0
  405. package/node_modules/@noble/hashes/cryptoNode.js.map +1 -0
  406. package/node_modules/@noble/hashes/eskdf.d.ts +47 -0
  407. package/node_modules/@noble/hashes/eskdf.d.ts.map +1 -0
  408. package/node_modules/@noble/hashes/eskdf.js +166 -0
  409. package/node_modules/@noble/hashes/eskdf.js.map +1 -0
  410. package/node_modules/@noble/hashes/esm/_assert.d.ts +17 -0
  411. package/node_modules/@noble/hashes/esm/_assert.d.ts.map +1 -0
  412. package/node_modules/@noble/hashes/esm/_assert.js +15 -0
  413. package/node_modules/@noble/hashes/esm/_assert.js.map +1 -0
  414. package/node_modules/@noble/hashes/esm/_blake.d.ts +14 -0
  415. package/node_modules/@noble/hashes/esm/_blake.d.ts.map +1 -0
  416. package/node_modules/@noble/hashes/esm/_blake.js +45 -0
  417. package/node_modules/@noble/hashes/esm/_blake.js.map +1 -0
  418. package/node_modules/@noble/hashes/esm/_md.d.ts +51 -0
  419. package/node_modules/@noble/hashes/esm/_md.d.ts.map +1 -0
  420. package/node_modules/@noble/hashes/esm/_md.js +155 -0
  421. package/node_modules/@noble/hashes/esm/_md.js.map +1 -0
  422. package/node_modules/@noble/hashes/esm/_u64.d.ts +55 -0
  423. package/node_modules/@noble/hashes/esm/_u64.d.ts.map +1 -0
  424. package/node_modules/@noble/hashes/esm/_u64.js +67 -0
  425. package/node_modules/@noble/hashes/esm/_u64.js.map +1 -0
  426. package/node_modules/@noble/hashes/esm/argon2.d.ts +32 -0
  427. package/node_modules/@noble/hashes/esm/argon2.d.ts.map +1 -0
  428. package/node_modules/@noble/hashes/esm/argon2.js +392 -0
  429. package/node_modules/@noble/hashes/esm/argon2.js.map +1 -0
  430. package/node_modules/@noble/hashes/esm/blake1.d.ts +106 -0
  431. package/node_modules/@noble/hashes/esm/blake1.d.ts.map +1 -0
  432. package/node_modules/@noble/hashes/esm/blake1.js +452 -0
  433. package/node_modules/@noble/hashes/esm/blake1.js.map +1 -0
  434. package/node_modules/@noble/hashes/esm/blake2.d.ts +116 -0
  435. package/node_modules/@noble/hashes/esm/blake2.d.ts.map +1 -0
  436. package/node_modules/@noble/hashes/esm/blake2.js +413 -0
  437. package/node_modules/@noble/hashes/esm/blake2.js.map +1 -0
  438. package/node_modules/@noble/hashes/esm/blake2b.d.ts +11 -0
  439. package/node_modules/@noble/hashes/esm/blake2b.d.ts.map +1 -0
  440. package/node_modules/@noble/hashes/esm/blake2b.js +11 -0
  441. package/node_modules/@noble/hashes/esm/blake2b.js.map +1 -0
  442. package/node_modules/@noble/hashes/esm/blake2s.d.ts +20 -0
  443. package/node_modules/@noble/hashes/esm/blake2s.d.ts.map +1 -0
  444. package/node_modules/@noble/hashes/esm/blake2s.js +21 -0
  445. package/node_modules/@noble/hashes/esm/blake2s.js.map +1 -0
  446. package/node_modules/@noble/hashes/esm/blake3.d.ts +54 -0
  447. package/node_modules/@noble/hashes/esm/blake3.d.ts.map +1 -0
  448. package/node_modules/@noble/hashes/esm/blake3.js +251 -0
  449. package/node_modules/@noble/hashes/esm/blake3.js.map +1 -0
  450. package/node_modules/@noble/hashes/esm/crypto.d.ts +2 -0
  451. package/node_modules/@noble/hashes/esm/crypto.d.ts.map +1 -0
  452. package/node_modules/@noble/hashes/esm/crypto.js +2 -0
  453. package/node_modules/@noble/hashes/esm/crypto.js.map +1 -0
  454. package/node_modules/@noble/hashes/esm/cryptoNode.d.ts +2 -0
  455. package/node_modules/@noble/hashes/esm/cryptoNode.d.ts.map +1 -0
  456. package/node_modules/@noble/hashes/esm/cryptoNode.js +15 -0
  457. package/node_modules/@noble/hashes/esm/cryptoNode.js.map +1 -0
  458. package/node_modules/@noble/hashes/esm/eskdf.d.ts +47 -0
  459. package/node_modules/@noble/hashes/esm/eskdf.d.ts.map +1 -0
  460. package/node_modules/@noble/hashes/esm/eskdf.js +160 -0
  461. package/node_modules/@noble/hashes/esm/eskdf.js.map +1 -0
  462. package/node_modules/@noble/hashes/esm/hkdf.d.ts +36 -0
  463. package/node_modules/@noble/hashes/esm/hkdf.d.ts.map +1 -0
  464. package/node_modules/@noble/hashes/esm/hkdf.js +82 -0
  465. package/node_modules/@noble/hashes/esm/hkdf.js.map +1 -0
  466. package/node_modules/@noble/hashes/esm/hmac.d.ts +35 -0
  467. package/node_modules/@noble/hashes/esm/hmac.d.ts.map +1 -0
  468. package/node_modules/@noble/hashes/esm/hmac.js +86 -0
  469. package/node_modules/@noble/hashes/esm/hmac.js.map +1 -0
  470. package/node_modules/@noble/hashes/esm/index.d.ts +2 -0
  471. package/node_modules/@noble/hashes/esm/index.d.ts.map +1 -0
  472. package/node_modules/@noble/hashes/esm/index.js +33 -0
  473. package/node_modules/@noble/hashes/esm/index.js.map +1 -0
  474. package/node_modules/@noble/hashes/esm/legacy.d.ts +71 -0
  475. package/node_modules/@noble/hashes/esm/legacy.d.ts.map +1 -0
  476. package/node_modules/@noble/hashes/esm/legacy.js +281 -0
  477. package/node_modules/@noble/hashes/esm/legacy.js.map +1 -0
  478. package/node_modules/@noble/hashes/esm/package.json +10 -0
  479. package/node_modules/@noble/hashes/esm/pbkdf2.d.ts +23 -0
  480. package/node_modules/@noble/hashes/esm/pbkdf2.d.ts.map +1 -0
  481. package/node_modules/@noble/hashes/esm/pbkdf2.js +97 -0
  482. package/node_modules/@noble/hashes/esm/pbkdf2.js.map +1 -0
  483. package/node_modules/@noble/hashes/esm/ripemd160.d.ts +13 -0
  484. package/node_modules/@noble/hashes/esm/ripemd160.d.ts.map +1 -0
  485. package/node_modules/@noble/hashes/esm/ripemd160.js +13 -0
  486. package/node_modules/@noble/hashes/esm/ripemd160.js.map +1 -0
  487. package/node_modules/@noble/hashes/esm/scrypt.d.ts +34 -0
  488. package/node_modules/@noble/hashes/esm/scrypt.d.ts.map +1 -0
  489. package/node_modules/@noble/hashes/esm/scrypt.js +228 -0
  490. package/node_modules/@noble/hashes/esm/scrypt.js.map +1 -0
  491. package/node_modules/@noble/hashes/esm/sha1.d.ts +11 -0
  492. package/node_modules/@noble/hashes/esm/sha1.d.ts.map +1 -0
  493. package/node_modules/@noble/hashes/esm/sha1.js +11 -0
  494. package/node_modules/@noble/hashes/esm/sha1.js.map +1 -0
  495. package/node_modules/@noble/hashes/esm/sha2.d.ts +159 -0
  496. package/node_modules/@noble/hashes/esm/sha2.d.ts.map +1 -0
  497. package/node_modules/@noble/hashes/esm/sha2.js +375 -0
  498. package/node_modules/@noble/hashes/esm/sha2.js.map +1 -0
  499. package/node_modules/@noble/hashes/esm/sha256.d.ts +20 -0
  500. package/node_modules/@noble/hashes/esm/sha256.d.ts.map +1 -0
  501. package/node_modules/@noble/hashes/esm/sha256.js +20 -0
  502. package/node_modules/@noble/hashes/esm/sha256.js.map +1 -0
  503. package/node_modules/@noble/hashes/esm/sha3-addons.d.ts +142 -0
  504. package/node_modules/@noble/hashes/esm/sha3-addons.d.ts.map +1 -0
  505. package/node_modules/@noble/hashes/esm/sha3-addons.js +393 -0
  506. package/node_modules/@noble/hashes/esm/sha3-addons.js.map +1 -0
  507. package/node_modules/@noble/hashes/esm/sha3.d.ts +53 -0
  508. package/node_modules/@noble/hashes/esm/sha3.d.ts.map +1 -0
  509. package/node_modules/@noble/hashes/esm/sha3.js +234 -0
  510. package/node_modules/@noble/hashes/esm/sha3.js.map +1 -0
  511. package/node_modules/@noble/hashes/esm/sha512.d.ts +26 -0
  512. package/node_modules/@noble/hashes/esm/sha512.d.ts.map +1 -0
  513. package/node_modules/@noble/hashes/esm/sha512.js +26 -0
  514. package/node_modules/@noble/hashes/esm/sha512.js.map +1 -0
  515. package/node_modules/@noble/hashes/esm/utils.d.ts +161 -0
  516. package/node_modules/@noble/hashes/esm/utils.d.ts.map +1 -0
  517. package/node_modules/@noble/hashes/esm/utils.js +281 -0
  518. package/node_modules/@noble/hashes/esm/utils.js.map +1 -0
  519. package/node_modules/@noble/hashes/hkdf.d.ts +36 -0
  520. package/node_modules/@noble/hashes/hkdf.d.ts.map +1 -0
  521. package/node_modules/@noble/hashes/hkdf.js +88 -0
  522. package/node_modules/@noble/hashes/hkdf.js.map +1 -0
  523. package/node_modules/@noble/hashes/hmac.d.ts +35 -0
  524. package/node_modules/@noble/hashes/hmac.d.ts.map +1 -0
  525. package/node_modules/@noble/hashes/hmac.js +91 -0
  526. package/node_modules/@noble/hashes/hmac.js.map +1 -0
  527. package/node_modules/@noble/hashes/index.d.ts +1 -0
  528. package/node_modules/@noble/hashes/index.d.ts.map +1 -0
  529. package/node_modules/@noble/hashes/index.js +33 -0
  530. package/node_modules/@noble/hashes/index.js.map +1 -0
  531. package/node_modules/@noble/hashes/legacy.d.ts +71 -0
  532. package/node_modules/@noble/hashes/legacy.d.ts.map +1 -0
  533. package/node_modules/@noble/hashes/legacy.js +287 -0
  534. package/node_modules/@noble/hashes/legacy.js.map +1 -0
  535. package/node_modules/@noble/hashes/package.json +266 -0
  536. package/node_modules/@noble/hashes/pbkdf2.d.ts +23 -0
  537. package/node_modules/@noble/hashes/pbkdf2.d.ts.map +1 -0
  538. package/node_modules/@noble/hashes/pbkdf2.js +101 -0
  539. package/node_modules/@noble/hashes/pbkdf2.js.map +1 -0
  540. package/node_modules/@noble/hashes/ripemd160.d.ts +13 -0
  541. package/node_modules/@noble/hashes/ripemd160.d.ts.map +1 -0
  542. package/node_modules/@noble/hashes/ripemd160.js +16 -0
  543. package/node_modules/@noble/hashes/ripemd160.js.map +1 -0
  544. package/node_modules/@noble/hashes/scrypt.d.ts +34 -0
  545. package/node_modules/@noble/hashes/scrypt.d.ts.map +1 -0
  546. package/node_modules/@noble/hashes/scrypt.js +232 -0
  547. package/node_modules/@noble/hashes/scrypt.js.map +1 -0
  548. package/node_modules/@noble/hashes/sha1.d.ts +11 -0
  549. package/node_modules/@noble/hashes/sha1.d.ts.map +1 -0
  550. package/node_modules/@noble/hashes/sha1.js +14 -0
  551. package/node_modules/@noble/hashes/sha1.js.map +1 -0
  552. package/node_modules/@noble/hashes/sha2.d.ts +159 -0
  553. package/node_modules/@noble/hashes/sha2.d.ts.map +1 -0
  554. package/node_modules/@noble/hashes/sha2.js +384 -0
  555. package/node_modules/@noble/hashes/sha2.js.map +1 -0
  556. package/node_modules/@noble/hashes/sha256.d.ts +20 -0
  557. package/node_modules/@noble/hashes/sha256.d.ts.map +1 -0
  558. package/node_modules/@noble/hashes/sha256.js +23 -0
  559. package/node_modules/@noble/hashes/sha256.js.map +1 -0
  560. package/node_modules/@noble/hashes/sha3-addons.d.ts +142 -0
  561. package/node_modules/@noble/hashes/sha3-addons.d.ts.map +1 -0
  562. package/node_modules/@noble/hashes/sha3-addons.js +402 -0
  563. package/node_modules/@noble/hashes/sha3-addons.js.map +1 -0
  564. package/node_modules/@noble/hashes/sha3.d.ts +53 -0
  565. package/node_modules/@noble/hashes/sha3.d.ts.map +1 -0
  566. package/node_modules/@noble/hashes/sha3.js +239 -0
  567. package/node_modules/@noble/hashes/sha3.js.map +1 -0
  568. package/node_modules/@noble/hashes/sha512.d.ts +26 -0
  569. package/node_modules/@noble/hashes/sha512.d.ts.map +1 -0
  570. package/node_modules/@noble/hashes/sha512.js +29 -0
  571. package/node_modules/@noble/hashes/sha512.js.map +1 -0
  572. package/node_modules/@noble/hashes/src/_assert.ts +22 -0
  573. package/node_modules/@noble/hashes/src/_blake.ts +50 -0
  574. package/node_modules/@noble/hashes/src/_md.ts +176 -0
  575. package/node_modules/@noble/hashes/src/_u64.ts +91 -0
  576. package/node_modules/@noble/hashes/src/argon2.ts +497 -0
  577. package/node_modules/@noble/hashes/src/blake1.ts +534 -0
  578. package/node_modules/@noble/hashes/src/blake2.ts +486 -0
  579. package/node_modules/@noble/hashes/src/blake2b.ts +10 -0
  580. package/node_modules/@noble/hashes/src/blake2s.ts +20 -0
  581. package/node_modules/@noble/hashes/src/blake3.ts +272 -0
  582. package/node_modules/@noble/hashes/src/crypto.ts +9 -0
  583. package/node_modules/@noble/hashes/src/cryptoNode.ts +15 -0
  584. package/node_modules/@noble/hashes/src/eskdf.ts +187 -0
  585. package/node_modules/@noble/hashes/src/hkdf.ts +88 -0
  586. package/node_modules/@noble/hashes/src/hmac.ts +94 -0
  587. package/node_modules/@noble/hashes/src/index.ts +31 -0
  588. package/node_modules/@noble/hashes/src/legacy.ts +293 -0
  589. package/node_modules/@noble/hashes/src/pbkdf2.ts +122 -0
  590. package/node_modules/@noble/hashes/src/ripemd160.ts +12 -0
  591. package/node_modules/@noble/hashes/src/scrypt.ts +257 -0
  592. package/node_modules/@noble/hashes/src/sha1.ts +10 -0
  593. package/node_modules/@noble/hashes/src/sha2.ts +402 -0
  594. package/node_modules/@noble/hashes/src/sha256.ts +24 -0
  595. package/node_modules/@noble/hashes/src/sha3-addons.ts +499 -0
  596. package/node_modules/@noble/hashes/src/sha3.ts +258 -0
  597. package/node_modules/@noble/hashes/src/sha512.ts +34 -0
  598. package/node_modules/@noble/hashes/src/utils.ts +395 -0
  599. package/node_modules/@noble/hashes/utils.d.ts +161 -0
  600. package/node_modules/@noble/hashes/utils.d.ts.map +1 -0
  601. package/node_modules/@noble/hashes/utils.js +313 -0
  602. package/node_modules/@noble/hashes/utils.js.map +1 -0
  603. package/package.json +203 -0
  604. package/schemas/catalog.schema.json +283 -0
  605. package/src/align.ts +235 -0
  606. package/src/audio-init-parser.ts +189 -0
  607. package/src/audio-ring-buffer.ts +120 -0
  608. package/src/authored-timing.ts +63 -0
  609. package/src/carp-catalog.ts +776 -0
  610. package/src/catalog-fec-params.ts +167 -0
  611. package/src/catalog-network-source.ts +49 -0
  612. package/src/catalog-validator.ts +34 -0
  613. package/src/cmaf-block-assembler.ts +1058 -0
  614. package/src/cmaf-group-batcher.ts +104 -0
  615. package/src/cmcd-producer.ts +329 -0
  616. package/src/codec-utils.ts +1539 -0
  617. package/src/fec-codec.ts +61 -0
  618. package/src/fec-manager.ts +1939 -0
  619. package/src/fec-starvation-detector.ts +128 -0
  620. package/src/fec-worker-setup.ts +177 -0
  621. package/src/fmp4-completion.ts +47 -0
  622. package/src/fmp4-reader.ts +112 -0
  623. package/src/index.ts +443 -0
  624. package/src/iso-bmff-timing.ts +688 -0
  625. package/src/loc.ts +181 -0
  626. package/src/manifest-auth-plan.ts +107 -0
  627. package/src/media-router.ts +1185 -0
  628. package/src/mfu-reassembler.ts +2842 -0
  629. package/src/mfu-reassembly-policy.ts +134 -0
  630. package/src/mmtp-container-parser.ts +1498 -0
  631. package/src/mmtp-decode-pipeline.ts +315 -0
  632. package/src/mmtp-router.ts +3027 -0
  633. package/src/mmtp-to-cmaf.ts +956 -0
  634. package/src/multicast-auth-catalog.ts +340 -0
  635. package/src/multicast-input.ts +439 -0
  636. package/src/multicast-manager.ts +1503 -0
  637. package/src/multicast-transport.ts +320 -0
  638. package/src/multicast-unwrap.ts +132 -0
  639. package/src/no-modules.ts +20 -0
  640. package/src/phase14-catalog-override.ts +336 -0
  641. package/src/repair-fetch.ts +217 -0
  642. package/src/sample-combiner.ts +846 -0
  643. package/src/signaling.ts +78 -0
  644. package/src/source-auth.ts +1 -0
  645. package/src/switching-set-alignment.ts +109 -0
  646. package/src/timestamp-codec.ts +265 -0
  647. package/src/track-pipeline-setup.ts +189 -0
  648. package/src/track-pipeline.ts +332 -0
  649. package/src/track-session.ts +778 -0
  650. package/src/transport-pool.ts +128 -0
  651. package/src/wasm-mfu-reassembler.ts +372 -0
  652. package/src/wasm-mmtp-container-parser.ts +23 -0
  653. package/test-vectors/align.json +199 -0
  654. package/test-vectors/catalog/README.md +25 -0
  655. package/test-vectors/catalog/negative/legacy-selection-params.json +15 -0
  656. package/test-vectors/catalog/negative/missing-mmtp-fields.json +12 -0
  657. package/test-vectors/catalog/negative/multicast-auth-padded-key.json +37 -0
  658. package/test-vectors/catalog/negative/multicast-auth-reused-track-format.json +53 -0
  659. package/test-vectors/catalog/negative/multicast-auth-trailing-pad-bits.json +37 -0
  660. package/test-vectors/catalog/negative/multicast-endpoint-missing-protocol-and-source.json +24 -0
  661. package/test-vectors/catalog/negative/network-source-object.json +25 -0
  662. package/test-vectors/catalog/negative/raptorq-unaligned-symbol.json +26 -0
  663. package/test-vectors/catalog/negative/repair-track-legacy-shape.json +18 -0
  664. package/test-vectors/catalog/negative/track-role-empty.json +16 -0
  665. package/test-vectors/catalog/negative/track-role-non-string.json +16 -0
  666. package/test-vectors/catalog/positive/fec-multicast.json +51 -0
  667. package/test-vectors/catalog/positive/flat-av.json +30 -0
  668. package/test-vectors/catalog/positive/multicast-auth-rotation.json +55 -0
  669. package/test-vectors/catalog/positive/ticks-and-mixed-timescales.json +39 -0
  670. package/test-vectors/catalog/positive/track-role.json +49 -0
  671. package/test-vectors/catalog/releases/moqcast-native-v16-v1/catalog.json +65 -0
  672. package/test-vectors/catalog/releases/moqcast-native-v16-v1.archive.sha256 +1 -0
  673. package/test-vectors/catalog-multicast-auth-v1.json +26 -0
  674. package/test-vectors/catalog-validation.json +148 -0
  675. package/test-vectors/catalog-validator-public-api.mjs +25 -0
  676. package/test-vectors/generate-source-auth-fixture.mjs +114 -0
  677. package/test-vectors/source-auth-v1.json +61 -0
  678. package/test-vectors/subsample-placement-v1.json +230 -0
@@ -0,0 +1,846 @@
1
+ /**
2
+ * @mmt/container - Sample-level combining of subsample data units (moqcast #37)
3
+ *
4
+ * {@link MFUReassembler} reassembles exactly one data unit -- a whole-sample
5
+ * DU, or one subsample DU of a partitioned sample. When a timed sample
6
+ * exceeds one data unit's 256-payload capacity, the origin packetizer
7
+ * partitions it into multiple subsample data units (each its own FI chain,
8
+ * its own authored base offset). This module combines those
9
+ * already-reassembled data units back into one contiguous sample.
10
+ *
11
+ * Container-blind, matching {@link MFUReassembler}'s own doctrine: it never
12
+ * parses ISOBMFF itself. The authored sample size a subsample-partitioned
13
+ * sample must total to comes from the host's own FT=1 (movie-fragment-
14
+ * metadata) parse, supplied via {@link SampleCombiner.registerAuthoredSize}.
15
+ * Completion is a protocol event -- every constituent data unit reassembled,
16
+ * byte-adjacent from zero, totaling the registered size -- never a
17
+ * timer-based guess; on lossy paths the existing per-data-unit deadline in
18
+ * {@link MFUReassembler} already bounds each constituent, so this module adds
19
+ * no second timer tier, matching moqcast #37 section 5.2.1.
20
+ *
21
+ * A whole-sample data unit whose length already equals the registered
22
+ * authored size passes through immediately, with no buffering. When
23
+ * `requireAuthoredSize` is false, an offset-zero data unit with no registered
24
+ * size at all also passes through immediately -- the pre-amendment shape, for
25
+ * a host that does not drive FT=1. When true, that same data unit instead
26
+ * buffers and waits for a size to be registered: FT=1 always publishes before
27
+ * any FT=2 sample referencing it (moqcast #37), but on a lossy path FT=1 can
28
+ * still *arrive* after an offset-zero data unit (reordering, or FT=1's own DU
29
+ * FEC-recovered late) -- treating "no size yet" as "whole sample" in that
30
+ * window would silently truncate a subsample-partitioned sample.
31
+ *
32
+ * Both `#pending` (incomplete samples) and `#authoredSizes` (registered but
33
+ * not yet consumed) are bounded. `#pending` is bounded by `maxBuffered`
34
+ * samples and `maxSegmentsPerSample` data units per sample; a full table
35
+ * evicts its oldest sample by insertion order rather than throwing, so one
36
+ * FEC-lost subsample DU cannot wedge every future sample. `#authoredSizes` is
37
+ * bounded by retiring each key the moment its sample completes, keeping only a
38
+ * bounded recent-retirement set so a late duplicate or FEC-recovered
39
+ * retransmission for that same sample is dropped rather than silently
40
+ * re-emitted or misread as a fresh whole sample.
41
+ *
42
+ * @packageDocumentation
43
+ */
44
+
45
+ import type {
46
+ MmtpSourcePath,
47
+ ReassembledMFU,
48
+ MmtpDeliveryProvenance,
49
+ } from './mfu-reassembler.js'
50
+
51
+ /** Identifies one authored sample: `(catalogTrackName, mpu, movieFragmentSequenceNumber, sampleNumber)`. */
52
+ type SampleKey = string
53
+
54
+ function sampleKey(
55
+ catalogTrackName: string | undefined,
56
+ mpuSequenceNumber: number,
57
+ movieFragmentSequenceNumber: number,
58
+ sampleNumber: number,
59
+ ): SampleKey {
60
+ return JSON.stringify([catalogTrackName ?? null, mpuSequenceNumber, movieFragmentSequenceNumber, sampleNumber])
61
+ }
62
+
63
+ /** The `catalogTrackName` a key was built from, or undefined when it had none. */
64
+ function trackNameOfKey(key: SampleKey): string | undefined {
65
+ const name = (JSON.parse(key) as [string | null, number, number, number])[0]
66
+ return name ?? undefined
67
+ }
68
+
69
+ /** One authored sample combined from its constituent data unit(s). */
70
+ export interface CombinedSample {
71
+ mpuSequenceNumber: number
72
+ movieFragmentSequenceNumber: number
73
+ sampleNumber: number
74
+ /** The full sample's media bytes, in ascending-offset order. */
75
+ data: Uint8Array
76
+ timestamp: bigint
77
+ /**
78
+ * The sample's RAP flag is the RAP flag of the FI=0 or FI=1 object of its
79
+ * offset-0 data unit (moqcast #37).
80
+ */
81
+ rapFlag: boolean
82
+ priority?: number
83
+ /** Every authoritative source-packet sequence across all constituent data units, in offset order. */
84
+ packetSequenceNumbers?: number[]
85
+ /** Subset of packetSequenceNumbers reconstructed by FEC. */
86
+ repairedPacketSequenceNumbers?: number[]
87
+ catalogTrackName?: string
88
+ /** Number of subsample data units combined (1 for a whole-sample DU or a non-timed passthrough). */
89
+ subsampleCount: number
90
+ /** MMTP fragments that formed the sample, summed across constituent data units. */
91
+ fragmentCount: number
92
+ /**
93
+ * Transport that supplied the offset-zero data unit's head fragment. Taken
94
+ * from that data unit alone -- like {@link CombinedSample.rapFlag} -- rather
95
+ * than from whichever sibling happened to complete last.
96
+ */
97
+ source?: MmtpSourcePath
98
+ /**
99
+ * Strict provenance folded across EVERY constituent data unit, and within
100
+ * each of them across every MMTP fragment. Unlike {@link CombinedSample.source},
101
+ * which is the offset-zero DU's routing tag, this is whole-sample evidence:
102
+ * only 'multicast' proves that no byte of this sample arrived another way.
103
+ */
104
+ deliveryProvenance: MmtpDeliveryProvenance
105
+ }
106
+
107
+ export const SAMPLE_COMBINE_ERROR_CODES = [
108
+ 'duplicate-subsample-offset',
109
+ 'overlapping-subsample',
110
+ 'exceeds-authored-size',
111
+ 'too-many-subsample-segments',
112
+ ] as const
113
+
114
+ export type SampleCombineErrorCode = typeof SAMPLE_COMBINE_ERROR_CODES[number]
115
+
116
+ /**
117
+ * Fail-closed rejection reasons for subsample combining. Distinct from
118
+ * {@link MfuReassemblyError}, which governs one data unit's own fragment
119
+ * chain; these govern combining already-reassembled data units into a
120
+ * sample.
121
+ */
122
+ export class SampleCombineError extends Error {
123
+ readonly name = 'SampleCombineError'
124
+
125
+ constructor(readonly code: SampleCombineErrorCode, message: string) {
126
+ super(message)
127
+ }
128
+ }
129
+
130
+ export interface SampleCombinerStats {
131
+ combinedSamples: number
132
+ passthroughSamples: number
133
+ timedOutSamples: number
134
+ /** Incomplete samples discarded to enforce `maxBuffered`. */
135
+ evictedSamples: number
136
+ }
137
+
138
+ export interface SampleCombinerOptions {
139
+ /**
140
+ * Max concurrent incomplete samples. Enforced by evicting the oldest by
141
+ * insertion order, never by throwing, so a host that never calls
142
+ * {@link SampleCombiner.cleanupTimeouts} still recovers from a permanently
143
+ * lost subsample data unit instead of wedging.
144
+ */
145
+ maxBuffered: number
146
+ /**
147
+ * When true, an offset-zero data unit with no registered authored size
148
+ * buffers and waits for one rather than passing through immediately. See
149
+ * the module doc.
150
+ */
151
+ requireAuthoredSize: boolean
152
+ /**
153
+ * Max subsample data units held for one sample at once. Bounds both memory
154
+ * and the per-insert overlap scan; a legitimate subsample-partitioned
155
+ * sample needs at most `ceil(sampleSize / (256 * maxPayload))` data units.
156
+ */
157
+ maxSegmentsPerSample: number
158
+ }
159
+
160
+ interface PendingSample {
161
+ /** Held data units keyed by their authored base offset. */
162
+ segments: Map<number, ReassembledMFU>
163
+ startedAt: number
164
+ }
165
+
166
+ /** Combines subsample data units of one sample into a contiguous whole. */
167
+ export class SampleCombiner {
168
+ #maxBuffered: number
169
+ #requireAuthoredSize: boolean
170
+ #maxSegmentsPerSample: number
171
+ #authoredSizes: Map<SampleKey, number> = new Map()
172
+ /** Map iteration is insertion-ordered, so the first key is the oldest. */
173
+ #pending: Map<SampleKey, PendingSample> = new Map()
174
+ /**
175
+ * Bounded, insertion-ordered set of recently-completed sample keys, so a
176
+ * late duplicate or FEC-recovered retransmission is dropped rather than
177
+ * re-emitted or misread as a fresh whole sample.
178
+ */
179
+ #retired: Set<SampleKey> = new Set()
180
+ #stats: SampleCombinerStats = {
181
+ combinedSamples: 0,
182
+ passthroughSamples: 0,
183
+ timedOutSamples: 0,
184
+ evictedSamples: 0,
185
+ }
186
+
187
+ constructor(options: SampleCombinerOptions) {
188
+ const { maxBuffered, requireAuthoredSize, maxSegmentsPerSample } = options
189
+ if (!Number.isInteger(maxBuffered) || maxBuffered <= 0) {
190
+ throw new Error('[SampleCombiner] maxBuffered must be a positive integer')
191
+ }
192
+ if (!Number.isInteger(maxSegmentsPerSample) || maxSegmentsPerSample <= 0) {
193
+ throw new Error('[SampleCombiner] maxSegmentsPerSample must be a positive integer')
194
+ }
195
+ this.#maxBuffered = maxBuffered
196
+ this.#requireAuthoredSize = requireAuthoredSize
197
+ this.#maxSegmentsPerSample = maxSegmentsPerSample
198
+ }
199
+
200
+ /**
201
+ * Register the authored sample size from the host's own FT=1 parse. Per
202
+ * moqcast #37, FT=1 for a movie fragment publishes before any FT=2 sample
203
+ * referencing it, so a host driving FT=1 as it arrives registers each
204
+ * sample's size before that sample's own data unit(s) arrive.
205
+ *
206
+ * On a lossy path FT=1 can still *arrive* late, after data units this
207
+ * combiner has already buffered. Registering a size therefore re-drives the
208
+ * completion check and returns the combined sample when the buffered data
209
+ * units already satisfy the newly-known size. Callers MUST consume the
210
+ * return value: for a sample carried by a single data unit there is no
211
+ * later {@link SampleCombiner.addMfu} to re-enter, so discarding it
212
+ * silently drops the sample.
213
+ *
214
+ * Registering also clears the key from the retired set. Retirement exists
215
+ * to drop data units that arrive *passively* after a sample completed — a
216
+ * late duplicate, an FEC-recovered retransmission. A host calling this
217
+ * method is instead asserting that a sample with this identity is authored
218
+ * now, which is what happens when a publisher restarts and its MPU
219
+ * sequence numbers begin again, or when MPU sequence wraps. Without this,
220
+ * such a stream would silently drop every sample whose identity collided
221
+ * with a retired one until the bounded set aged the key out.
222
+ */
223
+ registerAuthoredSize(
224
+ catalogTrackName: string | undefined,
225
+ mpuSequenceNumber: number,
226
+ movieFragmentSequenceNumber: number,
227
+ sampleNumber: number,
228
+ size: number,
229
+ ): CombinedSample | null {
230
+ const key = sampleKey(catalogTrackName, mpuSequenceNumber, movieFragmentSequenceNumber, sampleNumber)
231
+ this.#retired.delete(key)
232
+ this.#authoredSizes.set(key, size)
233
+ return this.#tryComplete(key, size)
234
+ }
235
+
236
+ /**
237
+ * Add one reassembled data unit. Returns the combined sample once every
238
+ * constituent data unit has arrived and totals the authored size.
239
+ */
240
+ addMfu(mfu: ReassembledMFU): CombinedSample | null {
241
+ if (mfu.movieFragmentSequenceNumber === undefined || mfu.sampleNumber === undefined) {
242
+ // Non-timed (Item) MFU: sample combining does not apply.
243
+ this.#stats.passthroughSamples++
244
+ return fromPassthrough(mfu)
245
+ }
246
+ const offset = mfu.sampleOffset ?? 0
247
+ const key = sampleKey(
248
+ mfu.catalogTrackName,
249
+ mfu.mpuSequenceNumber,
250
+ mfu.movieFragmentSequenceNumber,
251
+ mfu.sampleNumber,
252
+ )
253
+
254
+ if (this.#retired.has(key)) {
255
+ // Duplicate or late data unit for an already-retired sample (a
256
+ // FEC-recovered retransmission, reordering after completion, or a
257
+ // sample discarded by eviction/timeout). Drop it rather than
258
+ // re-emitting a duplicate downstream or misreading a stray fragment as
259
+ // a fresh whole sample.
260
+ return null
261
+ }
262
+
263
+ const dataLen = mfu.data.byteLength
264
+ const authoredSize = this.#authoredSizes.get(key)
265
+
266
+ if (offset === 0 && !this.#pending.has(key)) {
267
+ const passesThrough = authoredSize === undefined
268
+ ? !this.#requireAuthoredSize
269
+ : dataLen === authoredSize
270
+ if (passesThrough) {
271
+ this.#stats.passthroughSamples++
272
+ this.#retire(key)
273
+ return fromPassthrough(mfu)
274
+ }
275
+ // Either shorter than the authored total (a subsample), or awaiting a
276
+ // size under requireAuthoredSize -- buffer below.
277
+ }
278
+
279
+ // Reject BEFORE mutating any state. An earlier revision allocated the
280
+ // pending entry (evicting the oldest sample to make room) and only then
281
+ // validated, so a data unit the combiner went on to reject could destroy
282
+ // an unrelated in-flight sample and leave an empty entry in its slot.
283
+ const thisEnd = offset + dataLen
284
+ if (authoredSize !== undefined && thisEnd > authoredSize) {
285
+ throw new SampleCombineError(
286
+ 'exceeds-authored-size',
287
+ 'combined subsample data would exceed the registered authored sample size',
288
+ )
289
+ }
290
+ const existing = this.#pending.get(key)
291
+ if (existing !== undefined) {
292
+ if (existing.segments.has(offset)) {
293
+ throw new SampleCombineError(
294
+ 'duplicate-subsample-offset',
295
+ 'subsample data unit duplicates an offset already held for this sample',
296
+ )
297
+ }
298
+ if (existing.segments.size >= this.#maxSegmentsPerSample) {
299
+ throw new SampleCombineError(
300
+ 'too-many-subsample-segments',
301
+ 'a sample already holds the maximum number of subsample data units',
302
+ )
303
+ }
304
+ for (const [segOffset, seg] of existing.segments) {
305
+ const segEnd = segOffset + seg.data.byteLength
306
+ if (offset < segEnd && segOffset < thisEnd) {
307
+ throw new SampleCombineError(
308
+ 'overlapping-subsample',
309
+ "subsample data unit overlaps a preceding data unit's byte range",
310
+ )
311
+ }
312
+ }
313
+ }
314
+
315
+ let pending = existing
316
+ if (pending === undefined) {
317
+ if (this.#pending.size >= this.#maxBuffered) this.#evictOldestPending()
318
+ pending = { segments: new Map(), startedAt: Date.now() }
319
+ this.#pending.set(key, pending)
320
+ }
321
+ pending.segments.set(offset, mfu)
322
+
323
+ if (authoredSize === undefined) return null
324
+ return this.#tryComplete(key, authoredSize)
325
+ }
326
+
327
+ /**
328
+ * Emit the sample when its held data units are byte-adjacent from zero and
329
+ * total `size`. Completion is a protocol event, never a timer.
330
+ */
331
+ #tryComplete(key: SampleKey, size: number): CombinedSample | null {
332
+ const pending = this.#pending.get(key)
333
+ if (pending === undefined) return null
334
+ let expected = 0
335
+ const sortedOffsets = [...pending.segments.keys()].sort((a, b) => a - b)
336
+ for (const segOffset of sortedOffsets) {
337
+ if (segOffset !== expected) return null // gap: not yet contiguous from zero.
338
+ expected += pending.segments.get(segOffset)!.data.byteLength
339
+ }
340
+ if (expected !== size) return null // contiguous so far, short of the authored total.
341
+
342
+ this.#pending.delete(key)
343
+ this.#stats.combinedSamples++
344
+ this.#retire(key)
345
+ return fromSegments(pending.segments, sortedOffsets)
346
+ }
347
+
348
+ /**
349
+ * Retire a sample's key: free its registered authored size and remember the
350
+ * key in a bounded recency set. Called on every path that removes a sample
351
+ * -- completion, passthrough, eviction, and timeout -- so `#authoredSizes`
352
+ * cannot accumulate entries for samples that never complete, and so a later
353
+ * data unit for a discarded sample is dropped rather than starting a fresh
354
+ * buffer or being misread as a whole sample.
355
+ *
356
+ * The recency set holds `maxBuffered` keys. A duplicate delayed by more
357
+ * than that many retirements escapes it; on a reliable path there is no
358
+ * such duplicate, and on a lossy path the per-data-unit deadline in
359
+ * {@link MFUReassembler} bounds the delay well inside this window.
360
+ */
361
+ #retire(key: SampleKey): void {
362
+ this.#authoredSizes.delete(key)
363
+ this.#retired.add(key)
364
+ while (this.#retired.size > this.#maxBuffered) {
365
+ const oldest = this.#retired.values().next().value
366
+ if (oldest === undefined) break
367
+ this.#retired.delete(oldest)
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Discard the oldest pending sample by insertion order. This is the only
373
+ * backstop against one FEC-lost subsample data unit wedging
374
+ * {@link SampleCombiner.addMfu} for every future sample once `maxBuffered`
375
+ * is reached, for a host that never drives
376
+ * {@link SampleCombiner.cleanupTimeouts}.
377
+ */
378
+ #evictOldestPending(): void {
379
+ const oldest = this.#pending.keys().next().value
380
+ if (oldest === undefined) return
381
+ this.#pending.delete(oldest)
382
+ this.#stats.evictedSamples++
383
+ this.#retire(oldest)
384
+ }
385
+
386
+ /**
387
+ * Discard samples whose oldest held segment has waited past `timeoutMs`.
388
+ * Mirrors {@link MFUReassembler}'s clock-driven shape; the per-data-unit
389
+ * deadline inside {@link MFUReassembler} already bounds each constituent,
390
+ * so this is a backstop against a host that registers an authored size but
391
+ * never supplies every subsample DU.
392
+ */
393
+ cleanupTimeouts(timeoutMs: number): void {
394
+ const now = Date.now()
395
+ for (const [key, pending] of [...this.#pending]) {
396
+ if (now - pending.startedAt > timeoutMs) {
397
+ this.#pending.delete(key)
398
+ this.#stats.timedOutSamples++
399
+ this.#retire(key)
400
+ }
401
+ }
402
+ }
403
+
404
+ flush(): void {
405
+ this.#pending.clear()
406
+ this.#authoredSizes.clear()
407
+ this.#retired.clear()
408
+ }
409
+
410
+ /**
411
+ * Drop one stream's in-flight, registered-size, and retired state while
412
+ * preserving every other stream (mirrors
413
+ * {@link MFUReassembler.resetStream}).
414
+ */
415
+ resetStream(catalogTrackName: string): void {
416
+ for (const key of this.#pending.keys()) {
417
+ if (trackNameOfKey(key) === catalogTrackName) this.#pending.delete(key)
418
+ }
419
+ for (const key of this.#authoredSizes.keys()) {
420
+ if (trackNameOfKey(key) === catalogTrackName) this.#authoredSizes.delete(key)
421
+ }
422
+ for (const key of this.#retired) {
423
+ if (trackNameOfKey(key) === catalogTrackName) this.#retired.delete(key)
424
+ }
425
+ }
426
+
427
+ get stats(): SampleCombinerStats {
428
+ return { ...this.#stats }
429
+ }
430
+
431
+ get pendingCount(): number {
432
+ return this.#pending.size
433
+ }
434
+
435
+ /**
436
+ * Registered authored sizes still held. Diagnostic only: it exists so tests
437
+ * and health reporting can assert this table stays bounded, since an
438
+ * unbounded one is invisible from `pendingCount` alone.
439
+ */
440
+ get debugAuthoredSizeCount(): number {
441
+ return this.#authoredSizes.size
442
+ }
443
+
444
+ /** Retired keys still remembered. Diagnostic only, bounded by `maxBuffered`. */
445
+ get debugRetiredCount(): number {
446
+ return this.#retired.size
447
+ }
448
+ }
449
+
450
+ function fromPassthrough(mfu: ReassembledMFU): CombinedSample {
451
+ return {
452
+ mpuSequenceNumber: mfu.mpuSequenceNumber,
453
+ movieFragmentSequenceNumber: mfu.movieFragmentSequenceNumber ?? 0,
454
+ sampleNumber: mfu.sampleNumber ?? 0,
455
+ data: mfu.data,
456
+ timestamp: mfu.timestamp,
457
+ rapFlag: mfu.rapFlag,
458
+ priority: mfu.priority,
459
+ packetSequenceNumbers: mfu.packetSequenceNumbers,
460
+ repairedPacketSequenceNumbers: mfu.repairedPacketSequenceNumbers,
461
+ catalogTrackName: mfu.catalogTrackName,
462
+ subsampleCount: 1,
463
+ fragmentCount: mfu.fragmentCount,
464
+ source: mfu.source,
465
+ // One data unit in, one sample out: its provenance IS the sample's.
466
+ deliveryProvenance: mfu.deliveryProvenance
467
+ }
468
+ }
469
+
470
+ function fromSegments(
471
+ segments: Map<number, ReassembledMFU>,
472
+ sortedOffsets: number[],
473
+ ): CombinedSample {
474
+ const totalSize = sortedOffsets.reduce((sum, offset) => sum + segments.get(offset)!.data.byteLength, 0)
475
+ const data = new Uint8Array(totalSize)
476
+ let packetSequenceNumbers: number[] | undefined
477
+ let repairedPacketSequenceNumbers: number[] | undefined
478
+ let writeOffset = 0
479
+ let first: ReassembledMFU | undefined
480
+ let fragmentCount = 0
481
+ // Fold across data units the same way the reassembler folds across the
482
+ // fragments inside one: a sample is multicast-exclusive only if every
483
+ // subsample that formed it was.
484
+ let combinedProvenance: MmtpDeliveryProvenance =
485
+ sortedOffsets.length === 0 ? 'unknown' : 'multicast'
486
+ for (const offset of sortedOffsets) {
487
+ const seg = segments.get(offset)!
488
+ combinedProvenance =
489
+ combinedProvenance === 'mixed' || seg.deliveryProvenance === 'mixed'
490
+ ? 'mixed'
491
+ : combinedProvenance === 'unknown' || seg.deliveryProvenance === 'unknown'
492
+ ? 'unknown'
493
+ : 'multicast'
494
+ data.set(seg.data, writeOffset)
495
+ writeOffset += seg.data.byteLength
496
+ fragmentCount += seg.fragmentCount
497
+ if (seg.packetSequenceNumbers !== undefined) {
498
+ (packetSequenceNumbers ??= []).push(...seg.packetSequenceNumbers)
499
+ }
500
+ if (seg.repairedPacketSequenceNumbers !== undefined) {
501
+ (repairedPacketSequenceNumbers ??= []).push(...seg.repairedPacketSequenceNumbers)
502
+ }
503
+ if (first === undefined) first = seg
504
+ }
505
+ return {
506
+ mpuSequenceNumber: first!.mpuSequenceNumber,
507
+ movieFragmentSequenceNumber: first!.movieFragmentSequenceNumber!,
508
+ sampleNumber: first!.sampleNumber!,
509
+ data,
510
+ timestamp: first!.timestamp,
511
+ rapFlag: first!.rapFlag,
512
+ priority: first!.priority,
513
+ packetSequenceNumbers,
514
+ repairedPacketSequenceNumbers,
515
+ catalogTrackName: first!.catalogTrackName,
516
+ subsampleCount: segments.size,
517
+ fragmentCount,
518
+ source: first!.source,
519
+ deliveryProvenance: combinedProvenance,
520
+ }
521
+ }
522
+
523
+ // =============================================================================
524
+ // Inline Tests (vitest)
525
+ // =============================================================================
526
+
527
+ if (import.meta.vitest) {
528
+ const { describe, test, expect } = import.meta.vitest
529
+
530
+ const combiner = (overrides: Partial<SampleCombinerOptions> = {}) =>
531
+ new SampleCombiner({
532
+ maxBuffered: 10,
533
+ requireAuthoredSize: false,
534
+ maxSegmentsPerSample: 8,
535
+ ...overrides,
536
+ })
537
+
538
+ const mfu = (
539
+ mpu: number,
540
+ movie: number,
541
+ sample: number,
542
+ offset: number,
543
+ data: number[],
544
+ timestamp: bigint,
545
+ rapFlag: boolean,
546
+ deliveryProvenance: MmtpDeliveryProvenance = 'multicast',
547
+ ): ReassembledMFU => ({
548
+ mpuSequenceNumber: mpu,
549
+ data: new Uint8Array(data),
550
+ timestamp,
551
+ fragmentCount: 1,
552
+ rapFlag,
553
+ sampleNumber: sample,
554
+ movieFragmentSequenceNumber: movie,
555
+ sampleOffset: offset,
556
+ packetSequenceNumbers: [offset],
557
+ deliveryProvenance,
558
+ })
559
+
560
+ describe('SampleCombiner', () => {
561
+ test('whole-sample DU passes through immediately with no registered size', () => {
562
+ const c = combiner()
563
+ const out = c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))
564
+ expect(out).not.toBeNull()
565
+ expect(out!.data).toEqual(new Uint8Array([1, 2, 3, 4, 5]))
566
+ expect(out!.subsampleCount).toBe(1)
567
+ expect(c.pendingCount).toBe(0)
568
+ })
569
+
570
+ test('whole-sample DU passes through when it matches the registered size', () => {
571
+ const c = combiner()
572
+ c.registerAuthoredSize(undefined, 1, 9, 17, 5)
573
+ const out = c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))
574
+ expect(out?.data).toEqual(new Uint8Array([1, 2, 3, 4, 5]))
575
+ })
576
+
577
+ test('subsample data units combine once the authored size is met', () => {
578
+ const c = combiner()
579
+ c.registerAuthoredSize(undefined, 1, 9, 17, 10)
580
+
581
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()
582
+ expect(c.pendingCount).toBe(1)
583
+
584
+ const out = c.addMfu(mfu(1, 9, 17, 5, [6, 7, 8, 9, 10], 1001n, false))
585
+ expect(out?.data).toEqual(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
586
+ expect(out?.subsampleCount).toBe(2)
587
+ expect(out?.rapFlag).toBe(true) // offset-0 DU's RAP flag, per moqcast #37.
588
+ expect(out?.timestamp).toBe(1000n)
589
+ expect(c.pendingCount).toBe(0)
590
+ expect(c.stats.combinedSamples).toBe(1)
591
+ })
592
+
593
+ test('subsample data units combine out of order', () => {
594
+ const c = combiner()
595
+ c.registerAuthoredSize(undefined, 1, 9, 17, 10)
596
+
597
+ expect(c.addMfu(mfu(1, 9, 17, 5, [6, 7, 8, 9, 10], 1001n, false))).toBeNull()
598
+ const out = c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))
599
+ expect(out?.data).toEqual(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
600
+ })
601
+
602
+ test('subsample without a registered size never completes', () => {
603
+ // A non-zero-offset DU always buffers (it can never be a whole
604
+ // sample). Without a registered authored size there is nothing to
605
+ // combine against, so it -- and a sibling that arrives after it --
606
+ // stay pending rather than being guessed complete.
607
+ const c = combiner()
608
+ expect(c.addMfu(mfu(1, 9, 17, 3, [1, 2, 3], 1001n, false))).toBeNull()
609
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3], 1000n, true))).toBeNull()
610
+ expect(c.pendingCount).toBe(1)
611
+ })
612
+
613
+ test('requireAuthoredSize buffers an offset-zero DU instead of guessing complete', () => {
614
+ // A moqcast-#37-aware host opts into fail-closed buffering: on a lossy
615
+ // path FT=1 can arrive after an offset-zero data unit (reordering, or
616
+ // FT=1's own DU recovered late by FEC). Treating "no size yet" as
617
+ // "whole sample" would silently truncate a partitioned sample.
618
+ const c = combiner({ requireAuthoredSize: true })
619
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()
620
+ expect(c.pendingCount).toBe(1)
621
+
622
+ c.registerAuthoredSize(undefined, 1, 9, 17, 10)
623
+ const out = c.addMfu(mfu(1, 9, 17, 5, [6, 7, 8, 9, 10], 1001n, false))
624
+ expect(out?.data).toEqual(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
625
+ })
626
+
627
+ test('duplicate offset is rejected', () => {
628
+ const c = combiner()
629
+ c.registerAuthoredSize(undefined, 1, 9, 17, 10)
630
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()
631
+ expect(() => c.addMfu(mfu(1, 9, 17, 0, [9, 9, 9, 9, 9], 2000n, true)))
632
+ .toThrow(SampleCombineError)
633
+ })
634
+
635
+ test('overlapping subsample is rejected', () => {
636
+ const c = combiner()
637
+ c.registerAuthoredSize(undefined, 1, 9, 17, 10)
638
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()
639
+ expect(() => c.addMfu(mfu(1, 9, 17, 3, [9, 9, 9, 9, 9], 2000n, true)))
640
+ .toThrow(SampleCombineError)
641
+ })
642
+
643
+ test('exceeding the authored size is rejected', () => {
644
+ const c = combiner()
645
+ c.registerAuthoredSize(undefined, 1, 9, 17, 8)
646
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()
647
+ expect(() => c.addMfu(mfu(1, 9, 17, 5, [6, 7, 8, 9, 10], 2000n, false)))
648
+ .toThrow(SampleCombineError)
649
+ })
650
+
651
+ test('exceeding maxSegmentsPerSample is rejected', () => {
652
+ const c = combiner({ maxSegmentsPerSample: 2 })
653
+ c.registerAuthoredSize(undefined, 1, 9, 17, 100)
654
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2], 1000n, true))).toBeNull()
655
+ expect(c.addMfu(mfu(1, 9, 17, 2, [3, 4], 1001n, false))).toBeNull()
656
+ expect(() => c.addMfu(mfu(1, 9, 17, 4, [5, 6], 1002n, false)))
657
+ .toThrow(SampleCombineError)
658
+ })
659
+
660
+ test('a full combiner evicts the oldest pending sample instead of throwing', () => {
661
+ // Eviction is by insertion order, which is also the only backstop
662
+ // against one permanently-lost subsample DU wedging every future
663
+ // sample once maxBuffered incomplete samples accumulate.
664
+ const c = combiner({ maxBuffered: 2 })
665
+ c.registerAuthoredSize(undefined, 1, 9, 17, 10)
666
+ c.registerAuthoredSize(undefined, 1, 9, 18, 10)
667
+ c.registerAuthoredSize(undefined, 1, 9, 19, 10)
668
+
669
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 1, 1, 1, 1], 1000n, true))).toBeNull()
670
+ expect(c.addMfu(mfu(1, 9, 18, 0, [2, 2, 2, 2, 2], 1001n, true))).toBeNull()
671
+ expect(c.pendingCount).toBe(2)
672
+
673
+ // A third distinct incomplete sample evicts sample 17, the oldest.
674
+ expect(c.addMfu(mfu(1, 9, 19, 0, [3, 3, 3, 3, 3], 1002n, true))).toBeNull()
675
+ expect(c.pendingCount).toBe(2)
676
+ expect(c.stats.evictedSamples).toBe(1)
677
+
678
+ // The surviving samples are undisturbed and still complete normally.
679
+ expect(c.addMfu(mfu(1, 9, 18, 5, [8, 8, 8, 8, 8], 2001n, false))?.data)
680
+ .toEqual(new Uint8Array([2, 2, 2, 2, 2, 8, 8, 8, 8, 8]))
681
+ expect(c.addMfu(mfu(1, 9, 19, 5, [9, 9, 9, 9, 9], 2002n, false))?.data)
682
+ .toEqual(new Uint8Array([3, 3, 3, 3, 3, 9, 9, 9, 9, 9]))
683
+
684
+ // The combiner still accepts new work rather than being wedged.
685
+ c.registerAuthoredSize(undefined, 1, 9, 20, 10)
686
+ expect(c.addMfu(mfu(1, 9, 20, 0, [4, 4, 4, 4, 4], 3000n, true))).toBeNull()
687
+ expect(c.addMfu(mfu(1, 9, 20, 5, [7, 7, 7, 7, 7], 3001n, false))?.data)
688
+ .toEqual(new Uint8Array([4, 4, 4, 4, 4, 7, 7, 7, 7, 7]))
689
+ })
690
+
691
+ test('a completed sample frees its authored size and drops a late duplicate', () => {
692
+ const c = combiner()
693
+ c.registerAuthoredSize(undefined, 1, 9, 17, 10)
694
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()
695
+ expect(c.addMfu(mfu(1, 9, 17, 5, [6, 7, 8, 9, 10], 1001n, false))).not.toBeNull()
696
+
697
+ // A FEC-recovered retransmission of the completed sample's offset-0
698
+ // data unit must not be re-emitted as a second complete sample.
699
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 2000n, true))).toBeNull()
700
+ })
701
+
702
+ test('resetStream drops one track and preserves the others', () => {
703
+ const c = combiner()
704
+ c.registerAuthoredSize('video/720p', 1, 9, 17, 10)
705
+ c.registerAuthoredSize('audio', 1, 9, 17, 10)
706
+ const video = { ...mfu(1, 9, 17, 0, [1, 1, 1, 1, 1], 1000n, true), catalogTrackName: 'video/720p' }
707
+ const audio = { ...mfu(1, 9, 17, 0, [2, 2, 2, 2, 2], 1000n, true), catalogTrackName: 'audio' }
708
+ expect(c.addMfu(video)).toBeNull()
709
+ expect(c.addMfu(audio)).toBeNull()
710
+
711
+ c.resetStream('video/720p')
712
+ expect(c.pendingCount).toBe(1)
713
+
714
+ const audioTail = { ...mfu(1, 9, 17, 5, [3, 3, 3, 3, 3], 1001n, false), catalogTrackName: 'audio' }
715
+ expect(c.addMfu(audioTail)?.data).toEqual(new Uint8Array([2, 2, 2, 2, 2, 3, 3, 3, 3, 3]))
716
+ })
717
+
718
+ test('flush clears registered authored sizes', () => {
719
+ const c = combiner()
720
+ c.registerAuthoredSize(undefined, 1, 9, 17, 5)
721
+ c.flush()
722
+ // A now-unregistered size means an offset-zero DU passes through
723
+ // immediately again (requireAuthoredSize is false here) rather than
724
+ // waiting on a size flush() already discarded.
725
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))?.data)
726
+ .toEqual(new Uint8Array([1, 2, 3, 4, 5]))
727
+ })
728
+
729
+ test('a healthy stream accumulates no bookkeeping', () => {
730
+ // Regression: retirement ran only on completion paths, so an
731
+ // abandoned sample's registered size stayed resident forever.
732
+ const c = combiner({ maxBuffered: 4, requireAuthoredSize: true })
733
+ for (let i = 0; i < 1000; i++) {
734
+ expect(c.registerAuthoredSize(undefined, 1, 9, i, 10)).toBeNull()
735
+ expect(c.addMfu(mfu(1, 9, i, 0, [1, 1, 1, 1, 1], 1000n, true))).toBeNull()
736
+ expect(c.addMfu(mfu(1, 9, i, 5, [2, 2, 2, 2, 2], 1001n, false))).not.toBeNull()
737
+ }
738
+ expect(c.stats.combinedSamples).toBe(1000)
739
+ expect(c.pendingCount).toBe(0)
740
+ expect(c.debugAuthoredSizeCount).toBe(0)
741
+ expect(c.debugRetiredCount).toBeLessThanOrEqual(4)
742
+ })
743
+
744
+ test('samples that never complete release their authored size', () => {
745
+ const c = combiner({ maxBuffered: 4, requireAuthoredSize: true })
746
+ for (let i = 0; i < 1000; i++) {
747
+ expect(c.registerAuthoredSize(undefined, 1, 9, i, 10)).toBeNull()
748
+ expect(c.addMfu(mfu(1, 9, i, 0, [1, 1, 1, 1, 1], 1000n, true))).toBeNull()
749
+ // Deliberately never supply the tail.
750
+ }
751
+ c.cleanupTimeouts(-1) // expire everything still held
752
+ expect(c.pendingCount).toBe(0)
753
+ expect(c.debugAuthoredSizeCount).toBe(0)
754
+ })
755
+
756
+ test('a late authored size completes an already-buffered sample', () => {
757
+ // Regression: with requireAuthoredSize the completion check ran only
758
+ // inside addMfu, so a sample carried by a SINGLE data unit whose FT=1
759
+ // arrived afterwards had no later data unit to re-enter on and was
760
+ // silently lost.
761
+ const c = combiner({ requireAuthoredSize: true })
762
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 2, 3, 4, 5], 1000n, true))).toBeNull()
763
+ expect(c.pendingCount).toBe(1)
764
+
765
+ const out = c.registerAuthoredSize(undefined, 1, 9, 17, 5)
766
+ expect(out?.data).toEqual(new Uint8Array([1, 2, 3, 4, 5]))
767
+ expect(out?.subsampleCount).toBe(1)
768
+ expect(c.pendingCount).toBe(0)
769
+ })
770
+
771
+ test('a rejected data unit does not evict a live sample', () => {
772
+ // Regression: the pending slot was allocated (evicting the oldest
773
+ // sample to make room) BEFORE validation, so a data unit the combiner
774
+ // went on to reject destroyed an unrelated in-flight sample.
775
+ const c = combiner({ maxBuffered: 2 })
776
+ for (const s of [17, 18, 19]) c.registerAuthoredSize(undefined, 1, 9, s, 10)
777
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 1, 1, 1, 1], 1000n, true))).toBeNull()
778
+ expect(c.addMfu(mfu(1, 9, 18, 0, [2, 2, 2, 2, 2], 1001n, true))).toBeNull()
779
+ expect(c.pendingCount).toBe(2)
780
+
781
+ // 8 + 5 = 13 exceeds sample 19's authored size of 10.
782
+ expect(() => c.addMfu(mfu(1, 9, 19, 8, [9, 9, 9, 9, 9], 2000n, false)))
783
+ .toThrow(SampleCombineError)
784
+ expect(c.stats.evictedSamples).toBe(0)
785
+ expect(c.pendingCount).toBe(2)
786
+
787
+ // Sample 17 is untouched and still completes.
788
+ expect(c.addMfu(mfu(1, 9, 17, 5, [3, 3, 3, 3, 3], 2001n, false))?.data)
789
+ .toEqual(new Uint8Array([1, 1, 1, 1, 1, 3, 3, 3, 3, 3]))
790
+ })
791
+
792
+ test('an evicted sample is retired rather than reopened', () => {
793
+ const c = combiner({ maxBuffered: 1 })
794
+ for (const s of [17, 18]) c.registerAuthoredSize(undefined, 1, 9, s, 10)
795
+ expect(c.addMfu(mfu(1, 9, 17, 0, [1, 1, 1, 1, 1], 1000n, true))).toBeNull()
796
+ expect(c.addMfu(mfu(1, 9, 18, 0, [2, 2, 2, 2, 2], 1001n, true))).toBeNull()
797
+ expect(c.stats.evictedSamples).toBe(1)
798
+
799
+ // Sample 17's tail arrives after its eviction; it must not reopen.
800
+ expect(c.addMfu(mfu(1, 9, 17, 5, [3, 3, 3, 3, 3], 2000n, false))).toBeNull()
801
+ expect(c.pendingCount).toBe(1)
802
+ })
803
+ })
804
+
805
+ describe('sample-level delivery provenance', () => {
806
+ test('one non-multicast subsample makes the whole sample non-exclusive', () => {
807
+ // A 4K/8K sample is split across subsample DUs. If any one of them
808
+ // arrived over QUIC, the assembled sample contains bytes that never
809
+ // crossed a multicast socket, so the sample is not physical evidence
810
+ // even though every other DU was multicast.
811
+ const c = combiner()
812
+ c.registerAuthoredSize(undefined, 1, 1, 1, 4)
813
+ expect(c.addMfu(mfu(1, 1, 1, 0, [1, 2], 100n, true, 'multicast'))).toBeNull()
814
+ const done = c.addMfu(mfu(1, 1, 1, 2, [3, 4], 100n, false, 'mixed'))
815
+ expect(done).not.toBeNull()
816
+ expect(done!.subsampleCount).toBe(2)
817
+ expect(done!.deliveryProvenance).toBe('mixed')
818
+ })
819
+
820
+ test('an unattributed subsample degrades the sample to unknown', () => {
821
+ const c = combiner()
822
+ c.registerAuthoredSize(undefined, 2, 1, 1, 4)
823
+ expect(c.addMfu(mfu(2, 1, 1, 0, [1, 2], 100n, true, 'multicast'))).toBeNull()
824
+ const done = c.addMfu(mfu(2, 1, 1, 2, [3, 4], 100n, false, 'unknown'))
825
+ expect(done).not.toBeNull()
826
+ expect(done!.deliveryProvenance).toBe('unknown')
827
+ })
828
+
829
+ test('an all-multicast sample stays multicast-exclusive', () => {
830
+ const c = combiner()
831
+ c.registerAuthoredSize(undefined, 3, 1, 1, 4)
832
+ expect(c.addMfu(mfu(3, 1, 1, 0, [1, 2], 100n, true, 'multicast'))).toBeNull()
833
+ const done = c.addMfu(mfu(3, 1, 1, 2, [3, 4], 100n, false, 'multicast'))
834
+ expect(done).not.toBeNull()
835
+ expect(done!.deliveryProvenance).toBe('multicast')
836
+ })
837
+
838
+ test('a passthrough sample inherits its data unit provenance verbatim', () => {
839
+ const c = combiner()
840
+ const done = c.addMfu(mfu(4, 1, 1, 0, [1, 2], 100n, true, 'mixed'))
841
+ expect(done).not.toBeNull()
842
+ expect(done!.subsampleCount).toBe(1)
843
+ expect(done!.deliveryProvenance).toBe('mixed')
844
+ })
845
+ })
846
+ }