@blockcast/mmt-container 0.1.0 → 0.3.0-main.0bde85f7082f

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 (799) hide show
  1. package/README.md +524 -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 +152 -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 +80 -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/block-policy.d.ts +314 -0
  22. package/dist/block-policy.d.ts.map +1 -0
  23. package/dist/block-policy.js +466 -0
  24. package/dist/block-policy.js.map +7 -0
  25. package/dist/browser-runtime.js +26549 -0
  26. package/dist/browser-runtime.js.map +7 -0
  27. package/dist/carp-catalog.d.ts +429 -0
  28. package/dist/carp-catalog.d.ts.map +1 -0
  29. package/dist/carp-catalog.js +985 -0
  30. package/dist/carp-catalog.js.map +7 -0
  31. package/dist/catalog-fec-params.d.ts +275 -0
  32. package/dist/catalog-fec-params.d.ts.map +1 -0
  33. package/dist/catalog-fec-params.js +702 -0
  34. package/dist/catalog-fec-params.js.map +7 -0
  35. package/dist/catalog-network-source.d.ts +42 -0
  36. package/dist/catalog-network-source.d.ts.map +1 -0
  37. package/dist/catalog-network-source.js +47 -0
  38. package/dist/catalog-network-source.js.map +7 -0
  39. package/dist/catalog-validator.d.ts +18 -0
  40. package/dist/catalog-validator.d.ts.map +1 -0
  41. package/dist/catalog-validator.js +7747 -0
  42. package/dist/catalog-validator.js.map +7 -0
  43. package/dist/cmaf-block-assembler.d.ts +285 -0
  44. package/dist/cmaf-block-assembler.d.ts.map +1 -0
  45. package/dist/cmaf-block-assembler.js +1966 -0
  46. package/dist/cmaf-block-assembler.js.map +7 -0
  47. package/dist/cmaf-group-batcher.d.ts +38 -0
  48. package/dist/cmaf-group-batcher.d.ts.map +1 -0
  49. package/dist/cmaf-group-batcher.js +176 -0
  50. package/dist/cmaf-group-batcher.js.map +7 -0
  51. package/dist/cmcd-producer.d.ts +104 -0
  52. package/dist/cmcd-producer.d.ts.map +1 -0
  53. package/dist/cmcd-producer.js +183 -0
  54. package/dist/cmcd-producer.js.map +7 -0
  55. package/dist/codec-utils.d.ts +384 -0
  56. package/dist/codec-utils.d.ts.map +1 -0
  57. package/dist/codec-utils.js +1546 -0
  58. package/dist/codec-utils.js.map +7 -0
  59. package/dist/conceal-timeline.d.ts +146 -0
  60. package/dist/conceal-timeline.d.ts.map +1 -0
  61. package/dist/conceal-timeline.js +137 -0
  62. package/dist/conceal-timeline.js.map +7 -0
  63. package/dist/delivery-gap.d.ts +75 -0
  64. package/dist/delivery-gap.d.ts.map +1 -0
  65. package/dist/delivery-gap.js +88 -0
  66. package/dist/delivery-gap.js.map +7 -0
  67. package/dist/duplicate-ledger.d.ts +197 -0
  68. package/dist/duplicate-ledger.d.ts.map +1 -0
  69. package/dist/duplicate-ledger.js +226 -0
  70. package/dist/duplicate-ledger.js.map +7 -0
  71. package/dist/fec-codec.d.ts +32 -0
  72. package/dist/fec-codec.d.ts.map +1 -0
  73. package/dist/fec-codec.js +47 -0
  74. package/dist/fec-codec.js.map +7 -0
  75. package/dist/fec-manager.d.ts +583 -0
  76. package/dist/fec-manager.d.ts.map +1 -0
  77. package/dist/fec-manager.js +3899 -0
  78. package/dist/fec-manager.js.map +7 -0
  79. package/dist/fec-starvation-detector.d.ts +59 -0
  80. package/dist/fec-starvation-detector.d.ts.map +1 -0
  81. package/dist/fec-starvation-detector.js +60 -0
  82. package/dist/fec-starvation-detector.js.map +7 -0
  83. package/dist/fec-state.d.ts +131 -0
  84. package/dist/fec-state.d.ts.map +1 -0
  85. package/dist/fec-state.js +87 -0
  86. package/dist/fec-state.js.map +7 -0
  87. package/dist/fec-worker-setup.d.ts +94 -0
  88. package/dist/fec-worker-setup.d.ts.map +1 -0
  89. package/dist/fec-worker-setup.js +673 -0
  90. package/dist/fec-worker-setup.js.map +7 -0
  91. package/dist/fmp4-completion.d.ts +30 -0
  92. package/dist/fmp4-completion.d.ts.map +1 -0
  93. package/dist/fmp4-completion.js +21 -0
  94. package/dist/fmp4-completion.js.map +7 -0
  95. package/dist/fmp4-reader.d.ts +37 -0
  96. package/dist/fmp4-reader.d.ts.map +1 -0
  97. package/dist/fmp4-reader.js +100 -0
  98. package/dist/fmp4-reader.js.map +7 -0
  99. package/dist/index.d.ts +44 -3
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +460 -14
  102. package/dist/index.js.map +7 -1
  103. package/dist/iso-block-locator.d.ts +118 -0
  104. package/dist/iso-block-locator.d.ts.map +1 -0
  105. package/dist/iso-block-locator.js +289 -0
  106. package/dist/iso-block-locator.js.map +7 -0
  107. package/dist/iso-bmff-timing.d.ts +78 -0
  108. package/dist/iso-bmff-timing.d.ts.map +1 -0
  109. package/dist/iso-bmff-timing.js +593 -0
  110. package/dist/iso-bmff-timing.js.map +7 -0
  111. package/dist/loc.d.ts +70 -75
  112. package/dist/loc.d.ts.map +1 -1
  113. package/dist/loc.js +106 -192
  114. package/dist/loc.js.map +7 -1
  115. package/dist/manifest-auth-plan.d.ts +30 -0
  116. package/dist/manifest-auth-plan.d.ts.map +1 -0
  117. package/dist/manifest-auth-plan.js +1266 -0
  118. package/dist/manifest-auth-plan.js.map +7 -0
  119. package/dist/media-router.d.ts +262 -0
  120. package/dist/media-router.d.ts.map +1 -0
  121. package/dist/media-router.js +584 -0
  122. package/dist/media-router.js.map +7 -0
  123. package/dist/mfu-reassembler.d.ts +313 -9
  124. package/dist/mfu-reassembler.d.ts.map +1 -1
  125. package/dist/mfu-reassembler.js +3051 -285
  126. package/dist/mfu-reassembler.js.map +7 -1
  127. package/dist/mfu-reassembly-policy.d.ts +24 -0
  128. package/dist/mfu-reassembly-policy.d.ts.map +1 -0
  129. package/dist/mfu-reassembly-policy.js +99 -0
  130. package/dist/mfu-reassembly-policy.js.map +7 -0
  131. package/dist/mmtp-container-parser.d.ts +568 -0
  132. package/dist/mmtp-container-parser.d.ts.map +1 -0
  133. package/dist/mmtp-container-parser.js +6580 -0
  134. package/dist/mmtp-container-parser.js.map +7 -0
  135. package/dist/mmtp-container-parser.no-modules.js +9616 -0
  136. package/dist/mmtp-container-parser.no-modules.js.map +7 -0
  137. package/dist/mmtp-decode-pipeline.d.ts +138 -0
  138. package/dist/mmtp-decode-pipeline.d.ts.map +1 -0
  139. package/dist/mmtp-decode-pipeline.js +6814 -0
  140. package/dist/mmtp-decode-pipeline.js.map +7 -0
  141. package/dist/mmtp-router.d.ts +679 -0
  142. package/dist/mmtp-router.d.ts.map +1 -0
  143. package/dist/mmtp-router.js +11278 -0
  144. package/dist/mmtp-router.js.map +7 -0
  145. package/dist/mmtp-to-cmaf.d.ts +187 -0
  146. package/dist/mmtp-to-cmaf.d.ts.map +1 -0
  147. package/dist/mmtp-to-cmaf.js +716 -0
  148. package/dist/mmtp-to-cmaf.js.map +7 -0
  149. package/dist/multicast-auth-catalog.d.ts +115 -0
  150. package/dist/multicast-auth-catalog.d.ts.map +1 -0
  151. package/dist/multicast-auth-catalog.js +202 -0
  152. package/dist/multicast-auth-catalog.js.map +7 -0
  153. package/dist/multicast-input.d.ts +141 -0
  154. package/dist/multicast-input.d.ts.map +1 -0
  155. package/dist/multicast-input.js +390 -0
  156. package/dist/multicast-input.js.map +7 -0
  157. package/dist/multicast-manager.d.ts +669 -0
  158. package/dist/multicast-manager.d.ts.map +1 -0
  159. package/dist/multicast-manager.js +19101 -0
  160. package/dist/multicast-manager.js.map +7 -0
  161. package/dist/multicast-transport.d.ts +271 -0
  162. package/dist/multicast-transport.d.ts.map +1 -0
  163. package/dist/multicast-transport.js +2264 -0
  164. package/dist/multicast-transport.js.map +7 -0
  165. package/dist/multicast-unwrap.d.ts +57 -0
  166. package/dist/multicast-unwrap.d.ts.map +1 -0
  167. package/dist/multicast-unwrap.js +418 -0
  168. package/dist/multicast-unwrap.js.map +7 -0
  169. package/dist/no-modules.d.ts +10 -0
  170. package/dist/no-modules.d.ts.map +1 -0
  171. package/dist/no-modules.js +9491 -0
  172. package/dist/no-modules.js.map +7 -0
  173. package/dist/phase14-catalog-override.d.ts +126 -0
  174. package/dist/phase14-catalog-override.d.ts.map +1 -0
  175. package/dist/phase14-catalog-override.js +155 -0
  176. package/dist/phase14-catalog-override.js.map +7 -0
  177. package/dist/repair-fetch.d.ts +270 -0
  178. package/dist/repair-fetch.d.ts.map +1 -0
  179. package/dist/repair-fetch.js +381 -0
  180. package/dist/repair-fetch.js.map +7 -0
  181. package/dist/repair-layers.d.ts +158 -0
  182. package/dist/repair-layers.d.ts.map +1 -0
  183. package/dist/repair-layers.js +344 -0
  184. package/dist/repair-layers.js.map +7 -0
  185. package/dist/sample-combiner.d.ts +212 -0
  186. package/dist/sample-combiner.d.ts.map +1 -0
  187. package/dist/sample-combiner.js +595 -0
  188. package/dist/sample-combiner.js.map +7 -0
  189. package/dist/signaling.d.ts +29 -0
  190. package/dist/signaling.d.ts.map +1 -0
  191. package/dist/signaling.js +572 -0
  192. package/dist/signaling.js.map +7 -0
  193. package/dist/source-auth.d.ts +2 -0
  194. package/dist/source-auth.d.ts.map +1 -0
  195. package/dist/source-auth.js +1209 -0
  196. package/dist/source-auth.js.map +7 -0
  197. package/dist/switching-set-alignment.d.ts +61 -0
  198. package/dist/switching-set-alignment.d.ts.map +1 -0
  199. package/dist/switching-set-alignment.js +70 -0
  200. package/dist/switching-set-alignment.js.map +7 -0
  201. package/dist/timestamp-codec.d.ts +34 -0
  202. package/dist/timestamp-codec.d.ts.map +1 -0
  203. package/dist/timestamp-codec.js +473 -0
  204. package/dist/timestamp-codec.js.map +7 -0
  205. package/dist/track-pipeline-setup.d.ts +83 -0
  206. package/dist/track-pipeline-setup.d.ts.map +1 -0
  207. package/dist/track-pipeline-setup.js +291 -0
  208. package/dist/track-pipeline-setup.js.map +7 -0
  209. package/dist/track-pipeline.d.ts +121 -0
  210. package/dist/track-pipeline.d.ts.map +1 -0
  211. package/dist/track-pipeline.js +209 -0
  212. package/dist/track-pipeline.js.map +7 -0
  213. package/dist/track-session.d.ts +414 -0
  214. package/dist/track-session.d.ts.map +1 -0
  215. package/dist/track-session.js +754 -0
  216. package/dist/track-session.js.map +7 -0
  217. package/dist/transport-pool.d.ts +69 -0
  218. package/dist/transport-pool.d.ts.map +1 -0
  219. package/dist/transport-pool.js +74 -0
  220. package/dist/transport-pool.js.map +7 -0
  221. package/dist/wasm-mfu-reassembler.d.ts +97 -0
  222. package/dist/wasm-mfu-reassembler.d.ts.map +1 -0
  223. package/dist/wasm-mfu-reassembler.js +2133 -0
  224. package/dist/wasm-mfu-reassembler.js.map +7 -0
  225. package/dist/wasm-mmtp-container-parser.d.ts +10 -0
  226. package/dist/wasm-mmtp-container-parser.d.ts.map +1 -0
  227. package/dist/wasm-mmtp-container-parser.js +6834 -0
  228. package/dist/wasm-mmtp-container-parser.js.map +7 -0
  229. package/node_modules/@blockcast/fec-worker/README.md +223 -0
  230. package/node_modules/@blockcast/fec-worker/dist/.build-stamp +0 -0
  231. package/node_modules/@blockcast/fec-worker/dist/block-order.d.ts +38 -0
  232. package/node_modules/@blockcast/fec-worker/dist/block-order.d.ts.map +1 -0
  233. package/node_modules/@blockcast/fec-worker/dist/block-order.js +78 -0
  234. package/node_modules/@blockcast/fec-worker/dist/block-order.js.map +1 -0
  235. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.d.ts +93 -0
  236. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.d.ts.map +1 -0
  237. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.js +346 -0
  238. package/node_modules/@blockcast/fec-worker/dist/fec-worker-client.js.map +1 -0
  239. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts +380 -0
  240. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.d.ts.map +1 -0
  241. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.js +11 -0
  242. package/node_modules/@blockcast/fec-worker/dist/fec-worker-types.js.map +1 -0
  243. package/node_modules/@blockcast/fec-worker/dist/fec-worker.d.ts +14 -0
  244. package/node_modules/@blockcast/fec-worker/dist/fec-worker.d.ts.map +1 -0
  245. package/node_modules/@blockcast/fec-worker/dist/fec-worker.js +859 -0
  246. package/node_modules/@blockcast/fec-worker/dist/fec-worker.js.map +7 -0
  247. package/node_modules/@blockcast/fec-worker/dist/index.d.ts +10 -0
  248. package/node_modules/@blockcast/fec-worker/dist/index.d.ts.map +1 -0
  249. package/node_modules/@blockcast/fec-worker/dist/index.js +8 -0
  250. package/node_modules/@blockcast/fec-worker/dist/index.js.map +1 -0
  251. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.d.ts +20 -0
  252. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.d.ts.map +1 -0
  253. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.js +370 -0
  254. package/node_modules/@blockcast/fec-worker/dist/shred-fec-worker.js.map +7 -0
  255. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.d.ts +104 -0
  256. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.d.ts.map +1 -0
  257. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.js +181 -0
  258. package/node_modules/@blockcast/fec-worker/dist/shred-worker-client.js.map +1 -0
  259. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.d.ts +194 -0
  260. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.d.ts.map +1 -0
  261. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.js +62 -0
  262. package/node_modules/@blockcast/fec-worker/dist/shred-worker-types.js.map +1 -0
  263. package/node_modules/@blockcast/fec-worker/dist/transfer.d.ts +9 -0
  264. package/node_modules/@blockcast/fec-worker/dist/transfer.d.ts.map +1 -0
  265. package/node_modules/@blockcast/fec-worker/dist/transfer.js +13 -0
  266. package/node_modules/@blockcast/fec-worker/dist/transfer.js.map +1 -0
  267. package/node_modules/@blockcast/fec-worker/package.json +59 -0
  268. package/node_modules/@blockcast/fec-worker/src/block-order.ts +93 -0
  269. package/node_modules/@blockcast/fec-worker/src/fec-worker-client.ts +392 -0
  270. package/node_modules/@blockcast/fec-worker/src/fec-worker-types.ts +399 -0
  271. package/node_modules/@blockcast/fec-worker/src/fec-worker.ts +1502 -0
  272. package/node_modules/@blockcast/fec-worker/src/index.ts +35 -0
  273. package/node_modules/@blockcast/fec-worker/src/shred-fec-worker.ts +589 -0
  274. package/node_modules/@blockcast/fec-worker/src/shred-worker-client.ts +222 -0
  275. package/node_modules/@blockcast/fec-worker/src/shred-worker-types.ts +209 -0
  276. package/node_modules/@blockcast/fec-worker/src/transfer.ts +12 -0
  277. package/node_modules/@blockcast/mmt-alta-parse/README.md +181 -0
  278. package/node_modules/@blockcast/mmt-alta-parse/dist/.build-stamp +0 -0
  279. package/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts +57 -0
  280. package/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts.map +1 -0
  281. package/node_modules/@blockcast/mmt-alta-parse/dist/index.js +115 -0
  282. package/node_modules/@blockcast/mmt-alta-parse/dist/index.js.map +1 -0
  283. package/node_modules/@blockcast/mmt-alta-parse/package.json +50 -0
  284. package/node_modules/@blockcast/mmt-alta-parse/src/index.ts +136 -0
  285. package/node_modules/@blockcast/mmt-base/README.md +134 -0
  286. package/node_modules/@blockcast/mmt-base/dist/.build-stamp +0 -0
  287. package/node_modules/@blockcast/mmt-base/dist/fec-block-profile.d.ts +55 -0
  288. package/node_modules/@blockcast/mmt-base/dist/fec-block-profile.d.ts.map +1 -0
  289. package/node_modules/@blockcast/mmt-base/dist/fec-block-profile.js +128 -0
  290. package/node_modules/@blockcast/mmt-base/dist/fec-block-profile.js.map +1 -0
  291. package/node_modules/@blockcast/mmt-base/dist/index.d.ts +7 -0
  292. package/node_modules/@blockcast/mmt-base/dist/index.d.ts.map +1 -0
  293. package/node_modules/@blockcast/mmt-base/dist/index.js +7 -0
  294. package/node_modules/@blockcast/mmt-base/dist/index.js.map +1 -0
  295. package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +292 -0
  296. package/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -0
  297. package/node_modules/@blockcast/mmt-base/dist/mmtp.js +612 -0
  298. package/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -0
  299. package/node_modules/@blockcast/mmt-base/dist/net-constants.d.ts +18 -0
  300. package/node_modules/@blockcast/mmt-base/dist/net-constants.d.ts.map +1 -0
  301. package/node_modules/@blockcast/mmt-base/dist/net-constants.js +18 -0
  302. package/node_modules/@blockcast/mmt-base/dist/net-constants.js.map +1 -0
  303. package/node_modules/@blockcast/mmt-base/dist/ntp-short.d.ts +47 -0
  304. package/node_modules/@blockcast/mmt-base/dist/ntp-short.d.ts.map +1 -0
  305. package/node_modules/@blockcast/mmt-base/dist/ntp-short.js +54 -0
  306. package/node_modules/@blockcast/mmt-base/dist/ntp-short.js.map +1 -0
  307. package/node_modules/@blockcast/mmt-base/dist/serial-number.d.ts +57 -0
  308. package/node_modules/@blockcast/mmt-base/dist/serial-number.d.ts.map +1 -0
  309. package/node_modules/@blockcast/mmt-base/dist/serial-number.js +98 -0
  310. package/node_modules/@blockcast/mmt-base/dist/serial-number.js.map +1 -0
  311. package/node_modules/@blockcast/mmt-base/dist/signalling.d.ts +312 -0
  312. package/node_modules/@blockcast/mmt-base/dist/signalling.d.ts.map +1 -0
  313. package/node_modules/@blockcast/mmt-base/dist/signalling.js +637 -0
  314. package/node_modules/@blockcast/mmt-base/dist/signalling.js.map +1 -0
  315. package/node_modules/@blockcast/mmt-base/package.json +49 -0
  316. package/node_modules/@blockcast/mmt-base/src/fec-block-profile.ts +145 -0
  317. package/node_modules/@blockcast/mmt-base/src/index.ts +6 -0
  318. package/node_modules/@blockcast/mmt-base/src/mmtp.ts +892 -0
  319. package/node_modules/@blockcast/mmt-base/src/net-constants.ts +17 -0
  320. package/node_modules/@blockcast/mmt-base/src/ntp-short.ts +67 -0
  321. package/node_modules/@blockcast/mmt-base/src/serial-number.ts +107 -0
  322. package/node_modules/@blockcast/mmt-base/src/signalling.ts +862 -0
  323. package/node_modules/@blockcast/mmt-fec/README.md +271 -0
  324. package/node_modules/@blockcast/mmt-fec/dist/.build-stamp +0 -0
  325. package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts +82 -0
  326. package/node_modules/@blockcast/mmt-fec/dist/block-manager.d.ts.map +1 -0
  327. package/node_modules/@blockcast/mmt-fec/dist/block-manager.js +296 -0
  328. package/node_modules/@blockcast/mmt-fec/dist/block-manager.js.map +1 -0
  329. package/node_modules/@blockcast/mmt-fec/dist/block-processor.d.ts +106 -0
  330. package/node_modules/@blockcast/mmt-fec/dist/block-processor.d.ts.map +1 -0
  331. package/node_modules/@blockcast/mmt-fec/dist/block-processor.js +288 -0
  332. package/node_modules/@blockcast/mmt-fec/dist/block-processor.js.map +1 -0
  333. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.d.ts +46 -0
  334. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.d.ts.map +1 -0
  335. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.js +96 -0
  336. package/node_modules/@blockcast/mmt-fec/dist/cmaf-recovery.js.map +1 -0
  337. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.d.ts +33 -0
  338. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.d.ts.map +1 -0
  339. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.js +57 -0
  340. package/node_modules/@blockcast/mmt-fec/dist/cmaf-symbols.js.map +1 -0
  341. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.d.ts +205 -0
  342. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.d.ts.map +1 -0
  343. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.js +240 -0
  344. package/node_modules/@blockcast/mmt-fec/dist/fec-block-mapper.js.map +1 -0
  345. package/node_modules/@blockcast/mmt-fec/dist/index.d.ts +28 -0
  346. package/node_modules/@blockcast/mmt-fec/dist/index.d.ts.map +1 -0
  347. package/node_modules/@blockcast/mmt-fec/dist/index.js +28 -0
  348. package/node_modules/@blockcast/mmt-fec/dist/index.js.map +1 -0
  349. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.d.ts +20 -0
  350. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.d.ts.map +1 -0
  351. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.js +28 -0
  352. package/node_modules/@blockcast/mmt-fec/dist/loc-symbols.js.map +1 -0
  353. package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts +258 -0
  354. package/node_modules/@blockcast/mmt-fec/dist/oti.d.ts.map +1 -0
  355. package/node_modules/@blockcast/mmt-fec/dist/oti.js +382 -0
  356. package/node_modules/@blockcast/mmt-fec/dist/oti.js.map +1 -0
  357. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.d.ts +41 -0
  358. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.d.ts.map +1 -0
  359. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.js +81 -0
  360. package/node_modules/@blockcast/mmt-fec/dist/reorder-buffer.js.map +1 -0
  361. package/node_modules/@blockcast/mmt-fec/dist/repair-group.d.ts +82 -0
  362. package/node_modules/@blockcast/mmt-fec/dist/repair-group.d.ts.map +1 -0
  363. package/node_modules/@blockcast/mmt-fec/dist/repair-group.js +170 -0
  364. package/node_modules/@blockcast/mmt-fec/dist/repair-group.js.map +1 -0
  365. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/README.md +181 -0
  366. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/.build-stamp +0 -0
  367. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts +57 -0
  368. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.d.ts.map +1 -0
  369. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.js +115 -0
  370. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/dist/index.js.map +1 -0
  371. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/package.json +50 -0
  372. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-alta-parse/src/index.ts +136 -0
  373. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/README.md +134 -0
  374. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/.build-stamp +0 -0
  375. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/fec-block-profile.d.ts +55 -0
  376. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/fec-block-profile.d.ts.map +1 -0
  377. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/fec-block-profile.js +128 -0
  378. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/fec-block-profile.js.map +1 -0
  379. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.d.ts +7 -0
  380. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.d.ts.map +1 -0
  381. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.js +7 -0
  382. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/index.js.map +1 -0
  383. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts +292 -0
  384. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.d.ts.map +1 -0
  385. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js +612 -0
  386. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/mmtp.js.map +1 -0
  387. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/net-constants.d.ts +18 -0
  388. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/net-constants.d.ts.map +1 -0
  389. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/net-constants.js +18 -0
  390. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/net-constants.js.map +1 -0
  391. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/ntp-short.d.ts +47 -0
  392. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/ntp-short.d.ts.map +1 -0
  393. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/ntp-short.js +54 -0
  394. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/ntp-short.js.map +1 -0
  395. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/serial-number.d.ts +57 -0
  396. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/serial-number.d.ts.map +1 -0
  397. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/serial-number.js +98 -0
  398. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/serial-number.js.map +1 -0
  399. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/signalling.d.ts +312 -0
  400. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/signalling.d.ts.map +1 -0
  401. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/signalling.js +637 -0
  402. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/dist/signalling.js.map +1 -0
  403. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/package.json +49 -0
  404. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/fec-block-profile.ts +145 -0
  405. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/index.ts +6 -0
  406. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/mmtp.ts +892 -0
  407. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/net-constants.ts +17 -0
  408. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/ntp-short.ts +67 -0
  409. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/serial-number.ts +107 -0
  410. package/node_modules/@blockcast/mmt-fec/node_modules/@blockcast/mmt-base/src/signalling.ts +862 -0
  411. package/node_modules/@blockcast/mmt-fec/package.json +79 -0
  412. package/node_modules/@blockcast/mmt-fec/src/block-manager.ts +371 -0
  413. package/node_modules/@blockcast/mmt-fec/src/block-processor.ts +439 -0
  414. package/node_modules/@blockcast/mmt-fec/src/cmaf-recovery.ts +127 -0
  415. package/node_modules/@blockcast/mmt-fec/src/cmaf-symbols.ts +68 -0
  416. package/node_modules/@blockcast/mmt-fec/src/fec-block-mapper.ts +310 -0
  417. package/node_modules/@blockcast/mmt-fec/src/index.ts +94 -0
  418. package/node_modules/@blockcast/mmt-fec/src/loc-symbols.ts +34 -0
  419. package/node_modules/@blockcast/mmt-fec/src/oti.ts +463 -0
  420. package/node_modules/@blockcast/mmt-fec/src/reorder-buffer.ts +101 -0
  421. package/node_modules/@blockcast/mmt-fec/src/repair-group.ts +195 -0
  422. package/node_modules/@blockcast/mmt-manifest-verify/dist/.build-stamp +0 -0
  423. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.d.ts +28 -0
  424. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.d.ts.map +1 -0
  425. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.js +128 -0
  426. package/node_modules/@blockcast/mmt-manifest-verify/dist/admission.js.map +1 -0
  427. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.d.ts +4 -0
  428. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.d.ts.map +1 -0
  429. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.js +4 -0
  430. package/node_modules/@blockcast/mmt-manifest-verify/dist/index.js.map +1 -0
  431. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.d.ts +37 -0
  432. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.d.ts.map +1 -0
  433. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.js +179 -0
  434. package/node_modules/@blockcast/mmt-manifest-verify/dist/source-auth.js.map +1 -0
  435. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts +99 -0
  436. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.d.ts.map +1 -0
  437. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js +492 -0
  438. package/node_modules/@blockcast/mmt-manifest-verify/dist/verifier.js.map +1 -0
  439. package/node_modules/@blockcast/mmt-manifest-verify/package.json +45 -0
  440. package/node_modules/@blockcast/mmt-manifest-verify/src/admission.ts +171 -0
  441. package/node_modules/@blockcast/mmt-manifest-verify/src/index.ts +3 -0
  442. package/node_modules/@blockcast/mmt-manifest-verify/src/source-auth.ts +230 -0
  443. package/node_modules/@blockcast/mmt-manifest-verify/src/verifier.ts +669 -0
  444. package/node_modules/@noble/hashes/LICENSE +21 -0
  445. package/node_modules/@noble/hashes/README.md +521 -0
  446. package/node_modules/@noble/hashes/_assert.d.ts +17 -0
  447. package/node_modules/@noble/hashes/_assert.d.ts.map +1 -0
  448. package/node_modules/@noble/hashes/_assert.js +18 -0
  449. package/node_modules/@noble/hashes/_assert.js.map +1 -0
  450. package/node_modules/@noble/hashes/_blake.d.ts +14 -0
  451. package/node_modules/@noble/hashes/_blake.d.ts.map +1 -0
  452. package/node_modules/@noble/hashes/_blake.js +50 -0
  453. package/node_modules/@noble/hashes/_blake.js.map +1 -0
  454. package/node_modules/@noble/hashes/_md.d.ts +51 -0
  455. package/node_modules/@noble/hashes/_md.d.ts.map +1 -0
  456. package/node_modules/@noble/hashes/_md.js +162 -0
  457. package/node_modules/@noble/hashes/_md.js.map +1 -0
  458. package/node_modules/@noble/hashes/_u64.d.ts +55 -0
  459. package/node_modules/@noble/hashes/_u64.d.ts.map +1 -0
  460. package/node_modules/@noble/hashes/_u64.js +90 -0
  461. package/node_modules/@noble/hashes/_u64.js.map +1 -0
  462. package/node_modules/@noble/hashes/argon2.d.ts +32 -0
  463. package/node_modules/@noble/hashes/argon2.d.ts.map +1 -0
  464. package/node_modules/@noble/hashes/argon2.js +401 -0
  465. package/node_modules/@noble/hashes/argon2.js.map +1 -0
  466. package/node_modules/@noble/hashes/blake1.d.ts +106 -0
  467. package/node_modules/@noble/hashes/blake1.d.ts.map +1 -0
  468. package/node_modules/@noble/hashes/blake1.js +459 -0
  469. package/node_modules/@noble/hashes/blake1.js.map +1 -0
  470. package/node_modules/@noble/hashes/blake2.d.ts +116 -0
  471. package/node_modules/@noble/hashes/blake2.d.ts.map +1 -0
  472. package/node_modules/@noble/hashes/blake2.js +420 -0
  473. package/node_modules/@noble/hashes/blake2.js.map +1 -0
  474. package/node_modules/@noble/hashes/blake2b.d.ts +11 -0
  475. package/node_modules/@noble/hashes/blake2b.d.ts.map +1 -0
  476. package/node_modules/@noble/hashes/blake2b.js +14 -0
  477. package/node_modules/@noble/hashes/blake2b.js.map +1 -0
  478. package/node_modules/@noble/hashes/blake2s.d.ts +20 -0
  479. package/node_modules/@noble/hashes/blake2s.d.ts.map +1 -0
  480. package/node_modules/@noble/hashes/blake2s.js +24 -0
  481. package/node_modules/@noble/hashes/blake2s.js.map +1 -0
  482. package/node_modules/@noble/hashes/blake3.d.ts +54 -0
  483. package/node_modules/@noble/hashes/blake3.d.ts.map +1 -0
  484. package/node_modules/@noble/hashes/blake3.js +255 -0
  485. package/node_modules/@noble/hashes/blake3.js.map +1 -0
  486. package/node_modules/@noble/hashes/crypto.d.ts +2 -0
  487. package/node_modules/@noble/hashes/crypto.d.ts.map +1 -0
  488. package/node_modules/@noble/hashes/crypto.js +5 -0
  489. package/node_modules/@noble/hashes/crypto.js.map +1 -0
  490. package/node_modules/@noble/hashes/cryptoNode.d.ts +2 -0
  491. package/node_modules/@noble/hashes/cryptoNode.d.ts.map +1 -0
  492. package/node_modules/@noble/hashes/cryptoNode.js +18 -0
  493. package/node_modules/@noble/hashes/cryptoNode.js.map +1 -0
  494. package/node_modules/@noble/hashes/eskdf.d.ts +47 -0
  495. package/node_modules/@noble/hashes/eskdf.d.ts.map +1 -0
  496. package/node_modules/@noble/hashes/eskdf.js +166 -0
  497. package/node_modules/@noble/hashes/eskdf.js.map +1 -0
  498. package/node_modules/@noble/hashes/esm/_assert.d.ts +17 -0
  499. package/node_modules/@noble/hashes/esm/_assert.d.ts.map +1 -0
  500. package/node_modules/@noble/hashes/esm/_assert.js +15 -0
  501. package/node_modules/@noble/hashes/esm/_assert.js.map +1 -0
  502. package/node_modules/@noble/hashes/esm/_blake.d.ts +14 -0
  503. package/node_modules/@noble/hashes/esm/_blake.d.ts.map +1 -0
  504. package/node_modules/@noble/hashes/esm/_blake.js +45 -0
  505. package/node_modules/@noble/hashes/esm/_blake.js.map +1 -0
  506. package/node_modules/@noble/hashes/esm/_md.d.ts +51 -0
  507. package/node_modules/@noble/hashes/esm/_md.d.ts.map +1 -0
  508. package/node_modules/@noble/hashes/esm/_md.js +155 -0
  509. package/node_modules/@noble/hashes/esm/_md.js.map +1 -0
  510. package/node_modules/@noble/hashes/esm/_u64.d.ts +55 -0
  511. package/node_modules/@noble/hashes/esm/_u64.d.ts.map +1 -0
  512. package/node_modules/@noble/hashes/esm/_u64.js +67 -0
  513. package/node_modules/@noble/hashes/esm/_u64.js.map +1 -0
  514. package/node_modules/@noble/hashes/esm/argon2.d.ts +32 -0
  515. package/node_modules/@noble/hashes/esm/argon2.d.ts.map +1 -0
  516. package/node_modules/@noble/hashes/esm/argon2.js +392 -0
  517. package/node_modules/@noble/hashes/esm/argon2.js.map +1 -0
  518. package/node_modules/@noble/hashes/esm/blake1.d.ts +106 -0
  519. package/node_modules/@noble/hashes/esm/blake1.d.ts.map +1 -0
  520. package/node_modules/@noble/hashes/esm/blake1.js +452 -0
  521. package/node_modules/@noble/hashes/esm/blake1.js.map +1 -0
  522. package/node_modules/@noble/hashes/esm/blake2.d.ts +116 -0
  523. package/node_modules/@noble/hashes/esm/blake2.d.ts.map +1 -0
  524. package/node_modules/@noble/hashes/esm/blake2.js +413 -0
  525. package/node_modules/@noble/hashes/esm/blake2.js.map +1 -0
  526. package/node_modules/@noble/hashes/esm/blake2b.d.ts +11 -0
  527. package/node_modules/@noble/hashes/esm/blake2b.d.ts.map +1 -0
  528. package/node_modules/@noble/hashes/esm/blake2b.js +11 -0
  529. package/node_modules/@noble/hashes/esm/blake2b.js.map +1 -0
  530. package/node_modules/@noble/hashes/esm/blake2s.d.ts +20 -0
  531. package/node_modules/@noble/hashes/esm/blake2s.d.ts.map +1 -0
  532. package/node_modules/@noble/hashes/esm/blake2s.js +21 -0
  533. package/node_modules/@noble/hashes/esm/blake2s.js.map +1 -0
  534. package/node_modules/@noble/hashes/esm/blake3.d.ts +54 -0
  535. package/node_modules/@noble/hashes/esm/blake3.d.ts.map +1 -0
  536. package/node_modules/@noble/hashes/esm/blake3.js +251 -0
  537. package/node_modules/@noble/hashes/esm/blake3.js.map +1 -0
  538. package/node_modules/@noble/hashes/esm/crypto.d.ts +2 -0
  539. package/node_modules/@noble/hashes/esm/crypto.d.ts.map +1 -0
  540. package/node_modules/@noble/hashes/esm/crypto.js +2 -0
  541. package/node_modules/@noble/hashes/esm/crypto.js.map +1 -0
  542. package/node_modules/@noble/hashes/esm/cryptoNode.d.ts +2 -0
  543. package/node_modules/@noble/hashes/esm/cryptoNode.d.ts.map +1 -0
  544. package/node_modules/@noble/hashes/esm/cryptoNode.js +15 -0
  545. package/node_modules/@noble/hashes/esm/cryptoNode.js.map +1 -0
  546. package/node_modules/@noble/hashes/esm/eskdf.d.ts +47 -0
  547. package/node_modules/@noble/hashes/esm/eskdf.d.ts.map +1 -0
  548. package/node_modules/@noble/hashes/esm/eskdf.js +160 -0
  549. package/node_modules/@noble/hashes/esm/eskdf.js.map +1 -0
  550. package/node_modules/@noble/hashes/esm/hkdf.d.ts +36 -0
  551. package/node_modules/@noble/hashes/esm/hkdf.d.ts.map +1 -0
  552. package/node_modules/@noble/hashes/esm/hkdf.js +82 -0
  553. package/node_modules/@noble/hashes/esm/hkdf.js.map +1 -0
  554. package/node_modules/@noble/hashes/esm/hmac.d.ts +35 -0
  555. package/node_modules/@noble/hashes/esm/hmac.d.ts.map +1 -0
  556. package/node_modules/@noble/hashes/esm/hmac.js +86 -0
  557. package/node_modules/@noble/hashes/esm/hmac.js.map +1 -0
  558. package/node_modules/@noble/hashes/esm/index.d.ts +2 -0
  559. package/node_modules/@noble/hashes/esm/index.d.ts.map +1 -0
  560. package/node_modules/@noble/hashes/esm/index.js +33 -0
  561. package/node_modules/@noble/hashes/esm/index.js.map +1 -0
  562. package/node_modules/@noble/hashes/esm/legacy.d.ts +71 -0
  563. package/node_modules/@noble/hashes/esm/legacy.d.ts.map +1 -0
  564. package/node_modules/@noble/hashes/esm/legacy.js +281 -0
  565. package/node_modules/@noble/hashes/esm/legacy.js.map +1 -0
  566. package/node_modules/@noble/hashes/esm/package.json +10 -0
  567. package/node_modules/@noble/hashes/esm/pbkdf2.d.ts +23 -0
  568. package/node_modules/@noble/hashes/esm/pbkdf2.d.ts.map +1 -0
  569. package/node_modules/@noble/hashes/esm/pbkdf2.js +97 -0
  570. package/node_modules/@noble/hashes/esm/pbkdf2.js.map +1 -0
  571. package/node_modules/@noble/hashes/esm/ripemd160.d.ts +13 -0
  572. package/node_modules/@noble/hashes/esm/ripemd160.d.ts.map +1 -0
  573. package/node_modules/@noble/hashes/esm/ripemd160.js +13 -0
  574. package/node_modules/@noble/hashes/esm/ripemd160.js.map +1 -0
  575. package/node_modules/@noble/hashes/esm/scrypt.d.ts +34 -0
  576. package/node_modules/@noble/hashes/esm/scrypt.d.ts.map +1 -0
  577. package/node_modules/@noble/hashes/esm/scrypt.js +228 -0
  578. package/node_modules/@noble/hashes/esm/scrypt.js.map +1 -0
  579. package/node_modules/@noble/hashes/esm/sha1.d.ts +11 -0
  580. package/node_modules/@noble/hashes/esm/sha1.d.ts.map +1 -0
  581. package/node_modules/@noble/hashes/esm/sha1.js +11 -0
  582. package/node_modules/@noble/hashes/esm/sha1.js.map +1 -0
  583. package/node_modules/@noble/hashes/esm/sha2.d.ts +159 -0
  584. package/node_modules/@noble/hashes/esm/sha2.d.ts.map +1 -0
  585. package/node_modules/@noble/hashes/esm/sha2.js +375 -0
  586. package/node_modules/@noble/hashes/esm/sha2.js.map +1 -0
  587. package/node_modules/@noble/hashes/esm/sha256.d.ts +20 -0
  588. package/node_modules/@noble/hashes/esm/sha256.d.ts.map +1 -0
  589. package/node_modules/@noble/hashes/esm/sha256.js +20 -0
  590. package/node_modules/@noble/hashes/esm/sha256.js.map +1 -0
  591. package/node_modules/@noble/hashes/esm/sha3-addons.d.ts +142 -0
  592. package/node_modules/@noble/hashes/esm/sha3-addons.d.ts.map +1 -0
  593. package/node_modules/@noble/hashes/esm/sha3-addons.js +393 -0
  594. package/node_modules/@noble/hashes/esm/sha3-addons.js.map +1 -0
  595. package/node_modules/@noble/hashes/esm/sha3.d.ts +53 -0
  596. package/node_modules/@noble/hashes/esm/sha3.d.ts.map +1 -0
  597. package/node_modules/@noble/hashes/esm/sha3.js +234 -0
  598. package/node_modules/@noble/hashes/esm/sha3.js.map +1 -0
  599. package/node_modules/@noble/hashes/esm/sha512.d.ts +26 -0
  600. package/node_modules/@noble/hashes/esm/sha512.d.ts.map +1 -0
  601. package/node_modules/@noble/hashes/esm/sha512.js +26 -0
  602. package/node_modules/@noble/hashes/esm/sha512.js.map +1 -0
  603. package/node_modules/@noble/hashes/esm/utils.d.ts +161 -0
  604. package/node_modules/@noble/hashes/esm/utils.d.ts.map +1 -0
  605. package/node_modules/@noble/hashes/esm/utils.js +281 -0
  606. package/node_modules/@noble/hashes/esm/utils.js.map +1 -0
  607. package/node_modules/@noble/hashes/hkdf.d.ts +36 -0
  608. package/node_modules/@noble/hashes/hkdf.d.ts.map +1 -0
  609. package/node_modules/@noble/hashes/hkdf.js +88 -0
  610. package/node_modules/@noble/hashes/hkdf.js.map +1 -0
  611. package/node_modules/@noble/hashes/hmac.d.ts +35 -0
  612. package/node_modules/@noble/hashes/hmac.d.ts.map +1 -0
  613. package/node_modules/@noble/hashes/hmac.js +91 -0
  614. package/node_modules/@noble/hashes/hmac.js.map +1 -0
  615. package/node_modules/@noble/hashes/index.d.ts +1 -0
  616. package/node_modules/@noble/hashes/index.d.ts.map +1 -0
  617. package/node_modules/@noble/hashes/index.js +33 -0
  618. package/node_modules/@noble/hashes/index.js.map +1 -0
  619. package/node_modules/@noble/hashes/legacy.d.ts +71 -0
  620. package/node_modules/@noble/hashes/legacy.d.ts.map +1 -0
  621. package/node_modules/@noble/hashes/legacy.js +287 -0
  622. package/node_modules/@noble/hashes/legacy.js.map +1 -0
  623. package/node_modules/@noble/hashes/package.json +266 -0
  624. package/node_modules/@noble/hashes/pbkdf2.d.ts +23 -0
  625. package/node_modules/@noble/hashes/pbkdf2.d.ts.map +1 -0
  626. package/node_modules/@noble/hashes/pbkdf2.js +101 -0
  627. package/node_modules/@noble/hashes/pbkdf2.js.map +1 -0
  628. package/node_modules/@noble/hashes/ripemd160.d.ts +13 -0
  629. package/node_modules/@noble/hashes/ripemd160.d.ts.map +1 -0
  630. package/node_modules/@noble/hashes/ripemd160.js +16 -0
  631. package/node_modules/@noble/hashes/ripemd160.js.map +1 -0
  632. package/node_modules/@noble/hashes/scrypt.d.ts +34 -0
  633. package/node_modules/@noble/hashes/scrypt.d.ts.map +1 -0
  634. package/node_modules/@noble/hashes/scrypt.js +232 -0
  635. package/node_modules/@noble/hashes/scrypt.js.map +1 -0
  636. package/node_modules/@noble/hashes/sha1.d.ts +11 -0
  637. package/node_modules/@noble/hashes/sha1.d.ts.map +1 -0
  638. package/node_modules/@noble/hashes/sha1.js +14 -0
  639. package/node_modules/@noble/hashes/sha1.js.map +1 -0
  640. package/node_modules/@noble/hashes/sha2.d.ts +159 -0
  641. package/node_modules/@noble/hashes/sha2.d.ts.map +1 -0
  642. package/node_modules/@noble/hashes/sha2.js +384 -0
  643. package/node_modules/@noble/hashes/sha2.js.map +1 -0
  644. package/node_modules/@noble/hashes/sha256.d.ts +20 -0
  645. package/node_modules/@noble/hashes/sha256.d.ts.map +1 -0
  646. package/node_modules/@noble/hashes/sha256.js +23 -0
  647. package/node_modules/@noble/hashes/sha256.js.map +1 -0
  648. package/node_modules/@noble/hashes/sha3-addons.d.ts +142 -0
  649. package/node_modules/@noble/hashes/sha3-addons.d.ts.map +1 -0
  650. package/node_modules/@noble/hashes/sha3-addons.js +402 -0
  651. package/node_modules/@noble/hashes/sha3-addons.js.map +1 -0
  652. package/node_modules/@noble/hashes/sha3.d.ts +53 -0
  653. package/node_modules/@noble/hashes/sha3.d.ts.map +1 -0
  654. package/node_modules/@noble/hashes/sha3.js +239 -0
  655. package/node_modules/@noble/hashes/sha3.js.map +1 -0
  656. package/node_modules/@noble/hashes/sha512.d.ts +26 -0
  657. package/node_modules/@noble/hashes/sha512.d.ts.map +1 -0
  658. package/node_modules/@noble/hashes/sha512.js +29 -0
  659. package/node_modules/@noble/hashes/sha512.js.map +1 -0
  660. package/node_modules/@noble/hashes/src/_assert.ts +22 -0
  661. package/node_modules/@noble/hashes/src/_blake.ts +50 -0
  662. package/node_modules/@noble/hashes/src/_md.ts +176 -0
  663. package/node_modules/@noble/hashes/src/_u64.ts +91 -0
  664. package/node_modules/@noble/hashes/src/argon2.ts +497 -0
  665. package/node_modules/@noble/hashes/src/blake1.ts +534 -0
  666. package/node_modules/@noble/hashes/src/blake2.ts +486 -0
  667. package/node_modules/@noble/hashes/src/blake2b.ts +10 -0
  668. package/node_modules/@noble/hashes/src/blake2s.ts +20 -0
  669. package/node_modules/@noble/hashes/src/blake3.ts +272 -0
  670. package/node_modules/@noble/hashes/src/crypto.ts +9 -0
  671. package/node_modules/@noble/hashes/src/cryptoNode.ts +15 -0
  672. package/node_modules/@noble/hashes/src/eskdf.ts +187 -0
  673. package/node_modules/@noble/hashes/src/hkdf.ts +88 -0
  674. package/node_modules/@noble/hashes/src/hmac.ts +94 -0
  675. package/node_modules/@noble/hashes/src/index.ts +31 -0
  676. package/node_modules/@noble/hashes/src/legacy.ts +293 -0
  677. package/node_modules/@noble/hashes/src/pbkdf2.ts +122 -0
  678. package/node_modules/@noble/hashes/src/ripemd160.ts +12 -0
  679. package/node_modules/@noble/hashes/src/scrypt.ts +257 -0
  680. package/node_modules/@noble/hashes/src/sha1.ts +10 -0
  681. package/node_modules/@noble/hashes/src/sha2.ts +402 -0
  682. package/node_modules/@noble/hashes/src/sha256.ts +24 -0
  683. package/node_modules/@noble/hashes/src/sha3-addons.ts +499 -0
  684. package/node_modules/@noble/hashes/src/sha3.ts +258 -0
  685. package/node_modules/@noble/hashes/src/sha512.ts +34 -0
  686. package/node_modules/@noble/hashes/src/utils.ts +395 -0
  687. package/node_modules/@noble/hashes/utils.d.ts +161 -0
  688. package/node_modules/@noble/hashes/utils.d.ts.map +1 -0
  689. package/node_modules/@noble/hashes/utils.js +313 -0
  690. package/node_modules/@noble/hashes/utils.js.map +1 -0
  691. package/package.json +179 -8
  692. package/schemas/catalog.schema.json +357 -0
  693. package/src/align.ts +239 -0
  694. package/src/audio-init-parser.ts +189 -0
  695. package/src/audio-ring-buffer.ts +120 -0
  696. package/src/authored-timing.ts +63 -0
  697. package/src/block-policy.ts +903 -0
  698. package/src/carp-catalog.ts +1065 -0
  699. package/src/catalog-fec-params.ts +729 -0
  700. package/src/catalog-network-source.ts +74 -0
  701. package/src/catalog-validator.ts +34 -0
  702. package/src/cmaf-block-assembler.ts +1255 -0
  703. package/src/cmaf-group-batcher.ts +104 -0
  704. package/src/cmcd-producer.ts +329 -0
  705. package/src/codec-utils.ts +1984 -0
  706. package/src/conceal-timeline.ts +293 -0
  707. package/src/delivery-gap.ts +147 -0
  708. package/src/duplicate-ledger.ts +372 -0
  709. package/src/fec-codec.ts +61 -0
  710. package/src/fec-manager.ts +4298 -0
  711. package/src/fec-starvation-detector.ts +128 -0
  712. package/src/fec-state.ts +219 -0
  713. package/src/fec-worker-setup.ts +283 -0
  714. package/src/fmp4-completion.ts +47 -0
  715. package/src/fmp4-reader.ts +112 -0
  716. package/src/index.ts +590 -21
  717. package/src/iso-block-locator.ts +329 -0
  718. package/src/iso-bmff-timing.ts +813 -0
  719. package/src/loc.ts +128 -154
  720. package/src/manifest-auth-plan.ts +107 -0
  721. package/src/media-router.ts +841 -0
  722. package/src/mfu-reassembler.ts +3480 -155
  723. package/src/mfu-reassembly-policy.ts +134 -0
  724. package/src/mmtp-container-parser.ts +2380 -0
  725. package/src/mmtp-decode-pipeline.ts +406 -0
  726. package/src/mmtp-router.ts +4860 -0
  727. package/src/mmtp-to-cmaf.ts +977 -0
  728. package/src/multicast-auth-catalog.ts +340 -0
  729. package/src/multicast-input.ts +793 -0
  730. package/src/multicast-manager.ts +2783 -0
  731. package/src/multicast-transport.ts +1058 -0
  732. package/src/multicast-unwrap.ts +132 -0
  733. package/src/no-modules.ts +21 -0
  734. package/src/phase14-catalog-override.ts +336 -0
  735. package/src/repair-fetch.ts +772 -0
  736. package/src/repair-layers.ts +533 -0
  737. package/src/sample-combiner.ts +938 -0
  738. package/src/signaling.ts +78 -0
  739. package/src/source-auth.ts +1 -0
  740. package/src/switching-set-alignment.ts +109 -0
  741. package/src/timestamp-codec.ts +265 -0
  742. package/src/track-pipeline-setup.ts +205 -0
  743. package/src/track-pipeline.ts +332 -0
  744. package/src/track-session.ts +1010 -0
  745. package/src/transport-pool.ts +128 -0
  746. package/src/wasm-mfu-reassembler.ts +405 -0
  747. package/src/wasm-mmtp-container-parser.ts +23 -0
  748. package/test-vectors/align.json +199 -0
  749. package/test-vectors/catalog/README.md +106 -0
  750. package/test-vectors/catalog/negative/archive-origin-with-path.json +33 -0
  751. package/test-vectors/catalog/negative/archive-unknown-field.json +34 -0
  752. package/test-vectors/catalog/negative/fec-block-profile-missing.json +51 -0
  753. package/test-vectors/catalog/negative/fec-block-profile-unknown.json +52 -0
  754. package/test-vectors/catalog/negative/fec-enhancement-repair-removed.json +28 -0
  755. package/test-vectors/catalog/negative/fec-repair-layer-geometry.json +33 -0
  756. package/test-vectors/catalog/negative/fec-repair-layer-missing-symbols.json +31 -0
  757. package/test-vectors/catalog/negative/fec-repair-multiple-depends.json +32 -0
  758. package/test-vectors/catalog/negative/fec-repair-overlay-with-layer.json +34 -0
  759. package/test-vectors/catalog/negative/fec-repair-priority-out-of-band.json +24 -0
  760. package/test-vectors/catalog/negative/fec-repair-source-symbols-without-scope.json +33 -0
  761. package/test-vectors/catalog/negative/legacy-selection-params.json +15 -0
  762. package/test-vectors/catalog/negative/media-track-repair-layer.json +16 -0
  763. package/test-vectors/catalog/negative/missing-mmtp-fields.json +12 -0
  764. package/test-vectors/catalog/negative/multicast-auth-padded-key.json +37 -0
  765. package/test-vectors/catalog/negative/multicast-auth-reused-track-format.json +53 -0
  766. package/test-vectors/catalog/negative/multicast-auth-trailing-pad-bits.json +37 -0
  767. package/test-vectors/catalog/negative/multicast-endpoint-missing-protocol-and-source.json +24 -0
  768. package/test-vectors/catalog/negative/multicast-network-source-empty.json +44 -0
  769. package/test-vectors/catalog/negative/multicast-packet-id-signaling.json +26 -0
  770. package/test-vectors/catalog/negative/network-source-object.json +25 -0
  771. package/test-vectors/catalog/negative/raptorq-source-symbols-over-max.json +24 -0
  772. package/test-vectors/catalog/negative/raptorq-unaligned-symbol.json +27 -0
  773. package/test-vectors/catalog/negative/repair-track-legacy-shape.json +19 -0
  774. package/test-vectors/catalog/negative/track-role-empty.json +16 -0
  775. package/test-vectors/catalog/negative/track-role-non-string.json +16 -0
  776. package/test-vectors/catalog/positive/archive-origin.json +34 -0
  777. package/test-vectors/catalog/positive/fec-iso-ssbg1.json +52 -0
  778. package/test-vectors/catalog/positive/fec-layered-repair.json +106 -0
  779. package/test-vectors/catalog/positive/fec-multicast.json +52 -0
  780. package/test-vectors/catalog/positive/flat-av.json +30 -0
  781. package/test-vectors/catalog/positive/multicast-auth-rotation.json +55 -0
  782. package/test-vectors/catalog/positive/multicast-native-ssm-no-network-source.json +43 -0
  783. package/test-vectors/catalog/positive/ticks-and-mixed-timescales.json +39 -0
  784. package/test-vectors/catalog/positive/track-role.json +49 -0
  785. package/test-vectors/catalog/releases/moqcast-native-v16-v1/catalog.json +65 -0
  786. package/test-vectors/catalog/releases/moqcast-native-v16-v1.archive.sha256 +1 -0
  787. package/test-vectors/catalog-multicast-auth-v1.json +26 -0
  788. package/test-vectors/catalog-validation.json +732 -0
  789. package/test-vectors/catalog-validator-public-api.mjs +25 -0
  790. package/test-vectors/generate-source-auth-fixture.mjs +114 -0
  791. package/test-vectors/hevc-x265-repeat-headers-v1.json +40 -0
  792. package/test-vectors/source-auth-v1.json +61 -0
  793. package/test-vectors/source-contiguity-v1.json +131 -0
  794. package/test-vectors/subsample-placement-v1.json +230 -0
  795. package/dist/mmtp.d.ts +0 -73
  796. package/dist/mmtp.d.ts.map +0 -1
  797. package/dist/mmtp.js +0 -210
  798. package/dist/mmtp.js.map +0 -1
  799. package/src/mmtp.ts +0 -277
@@ -0,0 +1,841 @@
1
+ /**
2
+ * MediaRouter — source arbitration for MoQ ↔ multicast switching.
3
+ *
4
+ * Both moq-lib and moqtail wire their MoQ and multicast frame outputs
5
+ * through this router. The router decides which source reaches the decoder:
6
+ *
7
+ * - MoQ frames pass through while multicast is inactive.
8
+ * - Multicast video frames are suppressed until the first keyframe.
9
+ * - Once multicast has both a video keyframe and audio, takeover is requested.
10
+ * - MoQ is suppressed only after the source-switch callback completes.
11
+ * - failbackToMoq() reverses the switch immediately.
12
+ *
13
+ * Per-track setTrackSource() allows individual tracks to be wired to a
14
+ * specific transport source (video=multicast, audio=moq, overlay=amt) without
15
+ * changing the binary MoQ↔multicast switching for other tracks.
16
+ */
17
+
18
+ import { computeFecDeliveryWindowMs } from './track-session.js'
19
+
20
+ export type FrameMeta = {
21
+ timestamp: number
22
+ keyframe: boolean
23
+ packetId?: number
24
+ packetSequenceNumber?: number
25
+ source?: 'moq' | 'multicast' | 'repair'
26
+ recovered?: boolean
27
+ sourceDiscontinuity?: boolean
28
+ /**
29
+ * Raw MMTP header timestamp (RFC 5905 short NTP, 32 bits): the publisher's
30
+ * send-wall clock for the packet that carried this frame. On timed media it
31
+ * is distinct from `timestamp`, the authored media presentation time. On a
32
+ * non-timed MFU there is no authored presentation time, so `MmtpRouter`
33
+ * derives `timestamp` from this same clock and the two carry no latency
34
+ * between them. Populated from `RoutedFrameMeta.mmtpTimestamp` and
35
+ * preserved by every re-emit on this router (multicast, MoQ, and repair) so
36
+ * players can measure network ingress on the multicast legs; absent when
37
+ * the packet header could not be read.
38
+ */
39
+ mmtpTimestamp?: bigint
40
+ }
41
+ export type FrameKind = 'video' | 'audio'
42
+ export type SourceKind = 'moq' | 'multicast'
43
+
44
+ type FrameCb = (data: Uint8Array, meta: FrameMeta) => void
45
+ type SwitchCb = (source: SourceKind) => void | Promise<void>
46
+
47
+ export interface MediaRouterOptions {
48
+ /** Set false for video-only streams. Default: true. */
49
+ requireAudio?: boolean
50
+ /**
51
+ * Audio fallback timeout (ms): force multicast activation if video keyframe
52
+ * arrived but audio hasn't within this window. Catalog-derived via
53
+ * computeFecDeliveryWindowMs (the single FEC recovery-window source of truth).
54
+ * Omit to disable the independent audio-fallback timer (no magic default).
55
+ */
56
+ audioFallbackMs?: number
57
+ /**
58
+ * Number of binary-path frames to allow through during a crossfade transition.
59
+ * Derive from FEC block size (e.g., ceil(K / groupsPerBlock)). Default: 10.
60
+ */
61
+ crossfadeFrames?: number
62
+ /**
63
+ * Max pre-boundary overlay frames to buffer before dropping.
64
+ * Derive from FEC config (e.g., ceil(K * 1.5)). Default: 128.
65
+ */
66
+ maxOverlayBuffer?: number
67
+ /**
68
+ * Max concurrent in-flight Phase-13 keyframe-group repairs (relay SUBSCRIBE
69
+ * flood mitigation, T-13-01). Required once repair is wired: registering
70
+ * `onRepairRequest` without it throws — there is no default. A number is
71
+ * validated at construction. A bound derived from live measurements that
72
+ * arrive after construction (e.g. ceil(reliableRtt / keyframeCadence)) is
73
+ * passed as a reader, evaluated at each repair decision: a throw or a value
74
+ * that is not a positive safe integer skips that group's repair (fail closed
75
+ * per decision, not per session) and the next decision reads it again.
76
+ * Unused for FEC tracks, which never arm the keyframe-lost path; their QUIC
77
+ * repair is the D-28 scheduler (`wireRepairFetch`), prioritised by block
78
+ * class.
79
+ */
80
+ maxRepairInFlight?: number | (() => number)
81
+ /**
82
+ * Allow multicast takeover from a delta frame after the player has confirmed
83
+ * that MoQ already seeded the same decoder timeline with a video keyframe.
84
+ * Default false: decoder-reset paths still need multicast to provide a RAP.
85
+ */
86
+ allowDeltaMulticastTakeoverAfterMoqKeyframe?: boolean
87
+ }
88
+
89
+ /**
90
+ * A per-track source that emits frames independently of the binary MoQ/multicast path.
91
+ * Used by setTrackSource() to wire specific tracks to specific transport sources.
92
+ */
93
+ export interface TrackSource {
94
+ name: string
95
+ /**
96
+ * Register a frame callback. Returns an unsubscribe function.
97
+ * MediaRouter calls unsubscribe() when clearTrackSource() is called.
98
+ */
99
+ onFrame(cb: (data: Uint8Array, meta: FrameMeta) => void): () => void
100
+ /**
101
+ * Optional error callback for when the source fails.
102
+ * MediaRouter uses this to trigger failback to binary switching for this track.
103
+ */
104
+ onError?(cb: () => void): () => void
105
+ /** Optional dispose hook called when clearTrackSource() is called. */
106
+ dispose?(): void
107
+ }
108
+
109
+ /**
110
+ * Thrown when setTrackSource() is called for a track that already has a source
111
+ * without an intervening clearTrackSource(). Prevents silent concurrent-assignment
112
+ * races (T-02-16 mitigation).
113
+ */
114
+ export class TrackSourceConflictError extends Error {
115
+ constructor(public readonly trackName: string) {
116
+ super(`Track source already assigned for '${trackName}'; call clearTrackSource first`)
117
+ this.name = 'TrackSourceConflictError'
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Migration policy for setTrackSource() transport switching.
123
+ *
124
+ * - 'crossfade': Overlap old (binary) and new source briefly (CROSSFADE_WINDOW_FRAMES),
125
+ * then suppress the binary path. Default for audio.
126
+ * - 'drop': Cut to new source immediately. Binary path suppressed at once.
127
+ * Suitable for latency-critical tracks.
128
+ * - 'wait': Defer migration until first FEC block boundary (same as overlay=true).
129
+ * Default for video — avoids decoder reset mid-block.
130
+ */
131
+ export type MigrationPolicy = 'crossfade' | 'drop' | 'wait'
132
+
133
+ /** Default crossfade window — override via MediaRouterOptions.crossfadeFrames. */
134
+ const DEFAULT_CROSSFADE_FRAMES = 10
135
+
136
+ /** Options passed to setTrackSource(). */
137
+ export interface SetTrackSourceOptions {
138
+ /**
139
+ * If true, this source is an overlay track that must wait for the first FEC
140
+ * block boundary signal (via notifyFecBlockBoundary()) before emitting frames.
141
+ * Frames arriving before the first boundary are buffered up to MAX_OVERLAY_BUFFER.
142
+ *
143
+ * Backwards compat: equivalent to policy: 'wait'.
144
+ */
145
+ overlay?: boolean
146
+ /**
147
+ * Migration policy for the transport switch. Overrides `overlay` when provided.
148
+ * See MigrationPolicy for semantics.
149
+ */
150
+ policy?: MigrationPolicy
151
+ }
152
+
153
+ /** Default overlay buffer cap — override via MediaRouterOptions.maxOverlayBuffer. */
154
+ const DEFAULT_MAX_OVERLAY_BUFFER = 128
155
+
156
+ /** Internal per-track source record. */
157
+ interface TrackSourceRecord {
158
+ source: TrackSource
159
+ unsubscribeFrame: () => void
160
+ unsubscribeError?: () => void
161
+ emitCount: number
162
+ }
163
+
164
+ export class MediaRouter {
165
+ #active: SourceKind = 'moq'
166
+ #multicastVideoKeyed = false
167
+ #multicastAudioReceived = false
168
+ #moqVideoKeyframeEmitted = false
169
+ #requireAudio: boolean
170
+ #suppressed = false // true after multicast confirmed — suppresses MoQ
171
+ #audioFallbackTimer: ReturnType<typeof setTimeout> | null = null
172
+
173
+ // Configurable constants (from catalog/FEC config, not magic numbers)
174
+ readonly #audioFallbackMs: number
175
+ readonly #crossfadeFrames: number
176
+ readonly #maxOverlayBuffer: number
177
+ readonly #allowDeltaMulticastTakeoverAfterMoqKeyframe: boolean
178
+
179
+ // ── Keyframe repair state ────────────────────────────────────────
180
+ /** Groups currently being repaired — idempotent guard per Pitfall 2 (T-13-01 mitigation) */
181
+ #repairInFlight = new Set<number>()
182
+ /** Max concurrent repairs — prevents relay SUBSCRIBE flood (T-13-01 mitigation). A reader is evaluated per decision. */
183
+ readonly #maxRepairInFlight: number | (() => number) | null
184
+ /** Callback to request MoQ subscribe for a specific group (wired by player) */
185
+ #onRepairRequest: ((expectedGroupId: number, trackName: string) => void) | null = null
186
+
187
+ #onVideoFrame: FrameCb | null = null
188
+ #onAudioFrame: FrameCb | null = null
189
+ #onOverlayFrame: FrameCb | null = null
190
+ #onSourceSwitch: SwitchCb | null = null
191
+ #sourceSwitchReady: Promise<void> | null = null
192
+ #sourceSwitchToken = 0
193
+ #pendingMulticastToken: number | null = null
194
+ #pendingMulticastVideo: { data: Uint8Array; meta: FrameMeta } | null = null
195
+ #pendingMulticastAudio: { data: Uint8Array; meta: FrameMeta } | null = null
196
+
197
+ // Per-track source state
198
+ #trackSources = new Map<string, TrackSourceRecord>()
199
+
200
+ // Track type registry: trackName → { type, source }.
201
+ // Init data / inline signaling is authoritative until catalog updates.
202
+ // Priority: 'init' > 'catalog' > 'name' (backward compat fallback).
203
+ #trackTypes = new Map<string, { type: FrameKind; source: 'catalog' | 'init' }>()
204
+
205
+ // Crossfade state: maps trackName → remaining binary-path frames allowed during window
206
+ #crossfadeCounters = new Map<string, number>()
207
+
208
+ // Overlay alignment state
209
+ #overlayBoundaryReached = false
210
+ #overlayBuffer: Array<{ data: Uint8Array; meta: FrameMeta }> = []
211
+
212
+ // ── Phase 14: deltaActive state machine (D-11..D-14) ─────────────
213
+ // No timers — state transitions driven entirely by notifyDeltaBlock() callbacks.
214
+ // All thresholds derived from catalog fields or throw at configureDelta() time.
215
+ #deltaConfigured = false
216
+ #deltaActive: boolean = true
217
+ #deltaWindow: boolean[] = [] // ring buffer: true = block failed
218
+ #deltaWindowSize: number = 0
219
+ #deltaFailThresholdRatio: number = 0 // P/K
220
+ #deltaRecoverThresholdRatio: number = 0 // (P/K)/2 — hysteresis (D-13)
221
+ #deltaProbeIntervalMs: number = 0
222
+ #lastProbeAt: number = 0
223
+ #onDeltaFallbackCb: (() => void) | null = null
224
+ #onDeltaRecoverCb: (() => void) | null = null
225
+
226
+ constructor(options?: MediaRouterOptions) {
227
+ this.#requireAudio = options?.requireAudio ?? true
228
+ // Catalog-derived — the caller passes an audioFallbackMs computed from the
229
+ // FEC recovery window (computeFecDeliveryWindowMs). No magic default: when
230
+ // absent, the independent audio-fallback timer is disabled (0) and
231
+ // activation waits for real audio arrival.
232
+ this.#audioFallbackMs = options?.audioFallbackMs ?? 0
233
+ this.#crossfadeFrames = options?.crossfadeFrames ?? DEFAULT_CROSSFADE_FRAMES
234
+ this.#maxOverlayBuffer = options?.maxOverlayBuffer ?? DEFAULT_MAX_OVERLAY_BUFFER
235
+ const maxRepairInFlight = options?.maxRepairInFlight
236
+ if (
237
+ maxRepairInFlight !== undefined &&
238
+ typeof maxRepairInFlight !== 'function' &&
239
+ (!Number.isSafeInteger(maxRepairInFlight) || maxRepairInFlight < 1)
240
+ ) {
241
+ throw new Error(
242
+ `[MediaRouter] maxRepairInFlight=${maxRepairInFlight} must be a positive integer`,
243
+ )
244
+ }
245
+ this.#maxRepairInFlight = maxRepairInFlight ?? null
246
+ this.#allowDeltaMulticastTakeoverAfterMoqKeyframe =
247
+ options?.allowDeltaMulticastTakeoverAfterMoqKeyframe ?? false
248
+ }
249
+
250
+ onVideoFrame(cb: FrameCb) { this.#onVideoFrame = cb }
251
+ onAudioFrame(cb: FrameCb) { this.#onAudioFrame = cb }
252
+ onOverlayFrame(cb: FrameCb) { this.#onOverlayFrame = cb }
253
+ onSourceSwitch(cb: SwitchCb) { this.#onSourceSwitch = cb }
254
+
255
+ get activeSource(): SourceKind { return this.#active }
256
+
257
+ // ── Keyframe repair API ──────────────────────────────────────────
258
+
259
+ /** Register callback for keyframe repair requests. Player wires this to issue MoQ SUBSCRIBE. */
260
+ onRepairRequest(cb: (expectedGroupId: number, trackName: string) => void): void {
261
+ if (this.#maxRepairInFlight === null) {
262
+ throw new Error(
263
+ '[MediaRouter] onRepairRequest requires an explicit maxRepairInFlight option',
264
+ )
265
+ }
266
+ this.#onRepairRequest = cb
267
+ }
268
+
269
+ /**
270
+ * Request repair for a lost keyframe group. Only fires when activeSource is 'multicast'.
271
+ * Idempotent per groupId — duplicate calls for the same group are suppressed.
272
+ * A reader `maxRepairInFlight` is evaluated here; without a valid value the
273
+ * group is skipped and a later call reads it again.
274
+ * @param expectedGroupId - The group ID expected but not received
275
+ * @param trackName - Track name for the SUBSCRIBE (e.g. 'video'). Default: 'video'.
276
+ */
277
+ repairLostGroup(expectedGroupId: number, trackName = 'video'): void {
278
+ if (this.#active !== 'multicast') return // only repair on multicast path
279
+ if (this.#maxRepairInFlight === null) return // repair is not wired
280
+ if (this.#repairInFlight.has(expectedGroupId)) return // idempotent
281
+ let maxRepairInFlight: number
282
+ try {
283
+ maxRepairInFlight =
284
+ typeof this.#maxRepairInFlight === 'function'
285
+ ? this.#maxRepairInFlight()
286
+ : this.#maxRepairInFlight
287
+ } catch (error) {
288
+ console.warn(
289
+ `[MediaRouter] maxRepairInFlight unmeasured, skipping repair for group ${expectedGroupId}:`,
290
+ error,
291
+ )
292
+ return
293
+ }
294
+ if (!Number.isSafeInteger(maxRepairInFlight) || maxRepairInFlight < 1) {
295
+ console.warn(
296
+ `[MediaRouter] maxRepairInFlight=${maxRepairInFlight} is not a positive integer, skipping repair for group ${expectedGroupId}`,
297
+ )
298
+ return
299
+ }
300
+ if (this.#repairInFlight.size >= maxRepairInFlight) {
301
+ console.warn(
302
+ `[MediaRouter] max repair in flight (${maxRepairInFlight}), dropping repair for group ${expectedGroupId}`,
303
+ )
304
+ return
305
+ }
306
+ this.#repairInFlight.add(expectedGroupId)
307
+ this.#onRepairRequest?.(expectedGroupId, trackName)
308
+ }
309
+
310
+ /**
311
+ * Feed a recovered keyframe frame from the repair path.
312
+ * Bypasses source arbitration entirely — goes directly to decoder callbacks.
313
+ * Does NOT change activeSource. Does NOT trigger failbackToMoq.
314
+ */
315
+ feedRepair(data: Uint8Array, meta: FrameMeta, kind: FrameKind): void {
316
+ // Repair only makes sense when multicast is active.
317
+ // Silently drop if MoQ became active (race with failbackToMoq) to avoid
318
+ // injecting stale-timestamp frames into the MoQ decoder path (WR-02).
319
+ if (this.#active !== 'multicast') return
320
+ const routedMeta = { ...meta, source: 'repair' as const, recovered: true }
321
+ if (kind === 'video') this.#onVideoFrame?.(data, routedMeta)
322
+ else this.#onAudioFrame?.(data, routedMeta)
323
+ }
324
+
325
+ /**
326
+ * Clear repair-in-flight state for a group (called after repair completes or times out).
327
+ */
328
+ clearRepairInFlight(groupId: number): void {
329
+ this.#repairInFlight.delete(groupId)
330
+ }
331
+
332
+ // ── Phase 14: deltaActive state machine API ──────────────────────
333
+
334
+ /**
335
+ * Configure the delta-track fallback state machine from catalog parameters.
336
+ *
337
+ * D-11: Thresholds derive from fec.sourceSymbols, fec.repairSymbols, framerate.
338
+ * D-13: Probe interval derives from deltaProbeIntervalMs or interleaveDepthMs*2.
339
+ * CLAUDE.md: error on bad init — throws if required inputs are absent.
340
+ *
341
+ * Calling again resets deltaActive=true and clears the window buffer (stream restart).
342
+ */
343
+ configureDelta(cfg: {
344
+ framerate: number
345
+ sourceSymbols: number
346
+ repairSymbols: number
347
+ deltaFailWindowBlocks?: number
348
+ deltaProbeIntervalMs?: number
349
+ interleaveDepthMs?: number
350
+ }): void {
351
+ if (typeof cfg.framerate !== 'number' || !Number.isFinite(cfg.framerate) || cfg.framerate <= 0) {
352
+ throw new Error('[MediaRouter] configureDelta: framerate required and must be > 0')
353
+ }
354
+ if (typeof cfg.sourceSymbols !== 'number' || cfg.sourceSymbols <= 0) {
355
+ throw new Error('[MediaRouter] configureDelta: sourceSymbols (K_delta) required and must be > 0')
356
+ }
357
+ if (typeof cfg.repairSymbols !== 'number' || cfg.repairSymbols <= 0) {
358
+ throw new Error('[MediaRouter] configureDelta: repairSymbols (P_delta) required and must be > 0')
359
+ }
360
+ if (cfg.deltaProbeIntervalMs === undefined && cfg.interleaveDepthMs === undefined) {
361
+ throw new Error(
362
+ '[MediaRouter] configureDelta: either deltaProbeIntervalMs or interleaveDepthMs required for probe interval derivation'
363
+ )
364
+ }
365
+
366
+ // Derivations — no magic floors, no hardcoded defaults (CLAUDE.md).
367
+ this.#deltaWindowSize = cfg.deltaFailWindowBlocks ?? Math.ceil(cfg.framerate)
368
+ this.#deltaFailThresholdRatio = cfg.repairSymbols / cfg.sourceSymbols
369
+ this.#deltaRecoverThresholdRatio = this.#deltaFailThresholdRatio / 2
370
+ // Without an explicit probe interval, use one complete signaled block span.
371
+ this.#deltaProbeIntervalMs = cfg.deltaProbeIntervalMs ?? computeFecDeliveryWindowMs({
372
+ interleaveDepthMs: cfg.interleaveDepthMs!,
373
+ sourceSymbols: cfg.sourceSymbols,
374
+ })
375
+
376
+ // Reset state — useful for stream restart.
377
+ this.#deltaActive = true
378
+ this.#deltaWindow = []
379
+ this.#lastProbeAt = 0
380
+ this.#deltaConfigured = true
381
+ }
382
+
383
+ /**
384
+ * Notify the state machine of a completed FEC block for the delta track.
385
+ *
386
+ * @param failed - true if the block was unrecoverable (FEC failure)
387
+ * @param nowMs - caller-injected monotonic ms (no internal timer — D-13, CLAUDE.md)
388
+ *
389
+ * If configureDelta() has not been called, this is a silent no-op (pre-catalog state).
390
+ */
391
+ notifyDeltaBlock(failed: boolean, nowMs: number): void {
392
+ if (!this.#deltaConfigured) return
393
+
394
+ // Maintain sliding window — ring buffer semantics.
395
+ this.#deltaWindow.push(failed)
396
+ if (this.#deltaWindow.length > this.#deltaWindowSize) {
397
+ this.#deltaWindow.shift()
398
+ }
399
+
400
+ // Window not yet full — insufficient data for decision.
401
+ if (this.#deltaWindow.length < this.#deltaWindowSize) return
402
+
403
+ const failedCount = this.#deltaWindow.filter(x => x).length
404
+ const ratio = failedCount / this.#deltaWindowSize
405
+
406
+ if (this.#deltaActive) {
407
+ // Fallback transition: active → inactive (T-14-03: fires exactly once)
408
+ if (ratio > this.#deltaFailThresholdRatio) {
409
+ this.#deltaActive = false
410
+ this.#lastProbeAt = nowMs
411
+ this.#onDeltaFallbackCb?.()
412
+ }
413
+ } else {
414
+ // Recovery transition: inactive → active (after probe interval + low ratio)
415
+ if (
416
+ (nowMs - this.#lastProbeAt) >= this.#deltaProbeIntervalMs &&
417
+ ratio < this.#deltaRecoverThresholdRatio
418
+ ) {
419
+ this.#deltaActive = true
420
+ this.#lastProbeAt = nowMs
421
+ this.#onDeltaRecoverCb?.()
422
+ }
423
+ }
424
+ }
425
+
426
+ /** Register callback fired when delta track degrades past threshold (D-12). */
427
+ onDeltaFallback(cb: () => void): void {
428
+ this.#onDeltaFallbackCb = cb
429
+ }
430
+
431
+ /** Register callback fired when delta track recovers below recovery threshold (D-13). */
432
+ onDeltaRecover(cb: () => void): void {
433
+ this.#onDeltaRecoverCb = cb
434
+ }
435
+
436
+ /** Whether the delta track is currently considered healthy (true = active). */
437
+ get deltaActive(): boolean {
438
+ return this.#deltaActive
439
+ }
440
+
441
+ // ── Test-visible accessors for threshold verification ────────────
442
+ // These expose internal derived values for test assertions (Tests 3,4,5,6,7).
443
+ // Prefixed with 'delta' to namespace clearly within the public API surface.
444
+
445
+ /** Derived window size — exposed for test assertions (Test 3, 4). */
446
+ get deltaWindowSize(): number { return this.#deltaWindowSize }
447
+ /** Derived fail threshold ratio (P/K) — exposed for test assertions (Test 6). */
448
+ get deltaFailThresholdRatio(): number { return this.#deltaFailThresholdRatio }
449
+ /** Derived recovery threshold ratio ((P/K)/2) — exposed for test assertions (Test 7). */
450
+ get deltaRecoverThresholdRatio(): number { return this.#deltaRecoverThresholdRatio }
451
+ /** Derived probe interval ms — exposed for test assertions (Test 5a). */
452
+ get deltaProbeIntervalMs(): number { return this.#deltaProbeIntervalMs }
453
+
454
+ /**
455
+ * Register a track name → type mapping from catalog.
456
+ * Catalog is the default authority. Init data / inline signaling
457
+ * takes precedence until the next catalog update.
458
+ */
459
+ registerTrackType(trackName: string, type: FrameKind): void {
460
+ // Catalog overwrites any previous registration (including init).
461
+ this.#trackTypes.set(trackName, { type, source: 'catalog' })
462
+ }
463
+
464
+ /**
465
+ * Register a track name → type from init data / inline signaling (MMTP FT=0).
466
+ * Authoritative until the next catalog update per §5.3.
467
+ * Does NOT overwrite an existing catalog registration.
468
+ */
469
+ registerTrackTypeFromInit(trackName: string, type: FrameKind): void {
470
+ const existing = this.#trackTypes.get(trackName)
471
+ if (existing?.source === 'catalog') return // catalog already set — don't downgrade
472
+ this.#trackTypes.set(trackName, { type, source: 'init' })
473
+ }
474
+
475
+ /**
476
+ * Assign a per-track source. Frames from this source bypass the binary
477
+ * MoQ↔multicast switching for this track only.
478
+ *
479
+ * Throws TrackSourceConflictError if a source is already assigned for this
480
+ * track without a clearTrackSource() in between.
481
+ */
482
+ setTrackSource(trackName: string, source: TrackSource, opts?: SetTrackSourceOptions): void {
483
+ if (this.#trackSources.has(trackName)) {
484
+ throw new TrackSourceConflictError(trackName)
485
+ }
486
+
487
+ // Resolve effective policy. opts.policy takes precedence; overlay=true is legacy 'wait'.
488
+ const effectivePolicy: MigrationPolicy | undefined =
489
+ opts?.policy ?? (opts?.overlay ? 'wait' : undefined)
490
+
491
+ // For crossfade: open the binary-path window immediately so the first per-track frame
492
+ // triggers the window (counter starts before the frame callback is wired).
493
+ if (effectivePolicy === 'crossfade') {
494
+ this.#crossfadeCounters.set(trackName, this.#crossfadeFrames)
495
+ }
496
+
497
+ const record: TrackSourceRecord = {
498
+ source,
499
+ unsubscribeFrame: () => {},
500
+ emitCount: 0,
501
+ }
502
+
503
+ // Wire the frame callback
504
+ record.unsubscribeFrame = source.onFrame((data, meta) => {
505
+ record.emitCount++
506
+ if (effectivePolicy === 'wait') {
507
+ this.#handleOverlayFrame(data, meta)
508
+ } else {
509
+ // 'drop', 'crossfade', or undefined: emit immediately
510
+ this.#emitForTrack(trackName, data, meta)
511
+ }
512
+ })
513
+
514
+ // Wire the optional error callback — failback to binary switching
515
+ if (source.onError) {
516
+ record.unsubscribeError = source.onError(() => {
517
+ this.clearTrackSource(trackName)
518
+ })
519
+ }
520
+
521
+ this.#trackSources.set(trackName, record)
522
+ }
523
+
524
+ /**
525
+ * Remove the per-track source for the given track.
526
+ * Binary switching resumes for this track after this call.
527
+ */
528
+ clearTrackSource(trackName: string): void {
529
+ const record = this.#trackSources.get(trackName)
530
+ if (!record) return
531
+
532
+ record.unsubscribeFrame()
533
+ record.unsubscribeError?.()
534
+ record.source.dispose?.()
535
+ this.#trackSources.delete(trackName)
536
+
537
+ // Clean up crossfade window if one was active for this track
538
+ this.#crossfadeCounters.delete(trackName)
539
+
540
+ // Reset overlay buffer if removing a non-media track (overlay/unknown)
541
+ const reg = this.#trackTypes.get(trackName)
542
+ const isMedia = reg?.type === 'video' || reg?.type === 'audio' ||
543
+ (reg === undefined && (trackName === 'video' || trackName === 'audio'))
544
+ if (!isMedia) {
545
+ this.#overlayBoundaryReached = false
546
+ this.#overlayBuffer = []
547
+ }
548
+ }
549
+
550
+ /**
551
+ * Signal that a FEC block boundary has been reached on the base track.
552
+ * Overlay tracks waiting for alignment flush their buffered frames now.
553
+ */
554
+ notifyFecBlockBoundary(): void {
555
+ if (this.#overlayBoundaryReached) return
556
+ this.#overlayBoundaryReached = true
557
+
558
+ // Flush buffered overlay frames
559
+ const buffered = this.#overlayBuffer.splice(0)
560
+ for (const { data, meta } of buffered) {
561
+ this.#onOverlayFrame?.(data, meta)
562
+ }
563
+ }
564
+
565
+ /**
566
+ * Return the number of frames emitted from the per-track source for a given
567
+ * track. Used in test-mode to verify per-track routing histogram.
568
+ * Returns 0 if no per-track source is active for the track.
569
+ */
570
+ trackSourceEmitCount(trackName: string): number {
571
+ return this.#trackSources.get(trackName)?.emitCount ?? 0
572
+ }
573
+
574
+ /** Feed a frame from the MoQ path. Suppressed when multicast is active OR a per-track source owns this track. */
575
+ feedMoq(data: Uint8Array, meta: FrameMeta, kind: FrameKind) {
576
+ // Per-track source takes precedence; allow through during crossfade window
577
+ if (this.#trackSources.has(kind)) {
578
+ const remaining = this.#crossfadeCounters.get(kind)
579
+ if (remaining && remaining > 0) {
580
+ // Decrement crossfade counter and allow this frame through
581
+ const next = remaining - 1
582
+ if (next === 0) {
583
+ this.#crossfadeCounters.delete(kind)
584
+ } else {
585
+ this.#crossfadeCounters.set(kind, next)
586
+ }
587
+ // Fall through to emit below (no return)
588
+ } else {
589
+ return // suppressed — no crossfade window active
590
+ }
591
+ }
592
+ if (this.#suppressed) return
593
+ // Audio suppression is handled by SessionManager onSuppress callback —
594
+ // do NOT independently suppress based on multicastAudioReceived.
595
+ // The state machine decides when to switch; the router just routes.
596
+ const routedMeta = { ...meta, source: 'moq' as const }
597
+ if (kind === 'video') this.#onVideoFrame?.(data, routedMeta)
598
+ else this.#onAudioFrame?.(data, routedMeta)
599
+ }
600
+
601
+ /** Feed a frame from the multicast path. Video waits for keyframe before activating. */
602
+ feedMulticast(data: Uint8Array, meta: FrameMeta, kind: FrameKind) {
603
+ // Per-track source takes precedence; allow through during crossfade window
604
+ if (this.#trackSources.has(kind)) {
605
+ const remaining = this.#crossfadeCounters.get(kind)
606
+ if (remaining && remaining > 0) {
607
+ const next = remaining - 1
608
+ if (next === 0) {
609
+ this.#crossfadeCounters.delete(kind)
610
+ } else {
611
+ this.#crossfadeCounters.set(kind, next)
612
+ }
613
+ // Fall through to emit below (no return)
614
+ } else {
615
+ return // suppressed
616
+ }
617
+ }
618
+
619
+ if (kind === 'video') {
620
+ if (!this.#multicastVideoKeyed) {
621
+ const moqSeededDelta =
622
+ !meta.keyframe &&
623
+ this.#allowDeltaMulticastTakeoverAfterMoqKeyframe &&
624
+ this.#moqVideoKeyframeEmitted
625
+ if (!meta.keyframe && !moqSeededDelta) return // drop until first safe decode point
626
+ this.#multicastVideoKeyed = true
627
+ const pendingMeta: FrameMeta = { ...meta, source: 'multicast' }
628
+ if (!moqSeededDelta) pendingMeta.sourceDiscontinuity = true
629
+ this.#pendingMulticastVideo = {
630
+ data: data.slice(),
631
+ meta: pendingMeta,
632
+ }
633
+ // If audio is required but hasn't arrived yet, start a fallback timer.
634
+ // Audio FEC blocks may recover after video — don't block activation forever.
635
+ // Only arms when a catalog-derived audioFallbackMs was supplied (>0).
636
+ if (this.#requireAudio && this.#audioFallbackMs > 0 && !this.#multicastAudioReceived && !this.#audioFallbackTimer) {
637
+ this.#audioFallbackTimer = setTimeout(() => {
638
+ if (!this.#multicastAudioReceived && this.#active !== 'multicast') {
639
+ this.#multicastAudioReceived = true // force
640
+ // Also release the MoQ-audio-warmup gate so the fallback actually
641
+ // activates — otherwise #tryActivateMulticast would still bail.
642
+ this.#moqAudioWarmed = true
643
+ this.#tryActivateMulticast()
644
+ }
645
+ }, this.#audioFallbackMs)
646
+ }
647
+ } else if (this.#active !== 'multicast') {
648
+ // Do not feed video into the multicast decoder while the source switch
649
+ // is still pending. Keep the newest keyframe as the post-activation
650
+ // decoder opener and drop deltas until takeover commits.
651
+ if (meta.keyframe) {
652
+ this.#pendingMulticastVideo = {
653
+ data: data.slice(),
654
+ meta: { ...meta, source: 'multicast', sourceDiscontinuity: true },
655
+ }
656
+ }
657
+ this.#tryActivateMulticast()
658
+ return
659
+ }
660
+ if (this.#active === 'multicast') this.#onVideoFrame?.(data, { ...meta, source: 'multicast' })
661
+ this.#tryActivateMulticast()
662
+ } else {
663
+ this.#multicastAudioReceived = true
664
+ if (this.#audioFallbackTimer) {
665
+ clearTimeout(this.#audioFallbackTimer)
666
+ this.#audioFallbackTimer = null
667
+ }
668
+ // BLO-3035 layer 5: in a multicast-first scenario (no MoQ unicast audio
669
+ // source) `notifyMoqAudioEmit()` is never called and the audio-fallback
670
+ // timer's force-set is bypassed (the timer's inner `!multicastAudioReceived`
671
+ // check returns early because audio already arrived). Without this gate
672
+ // `#moqAudioWarmed` stays false forever and `#tryActivateMulticast` never
673
+ // fires `onSourceSwitch('multicast')` — the player can't know to emit
674
+ // `__MULTICAST_TAKEOVER_TIME`. Treat the arrival of multicast audio as
675
+ // sufficient evidence to release the warmup gate. For the MoQ→multicast
676
+ // handoff case `notifyMoqAudioEmit()` will already have set this flag, so
677
+ // the assignment is idempotent.
678
+ if (!this.#moqAudioWarmed) this.#moqAudioWarmed = true
679
+ // Activate BEFORE delivering the frame — the source switch callback
680
+ // (e.g. ring buffer reset) must fire before the first multicast audio
681
+ // frame reaches the backend. Otherwise the NTP timestamp hits the
682
+ // MoQ-era ring buffer base → overflow → silence gap.
683
+ this.#tryActivateMulticast()
684
+ // Only emit multicast audio AFTER takeover succeeds. Before takeover,
685
+ // MoQ audio is still flowing through feedMoq → #onAudioFrame; emitting
686
+ // multicast audio too would double-feed the backend (2x audio frames,
687
+ // pitch wobble and distortion). Post-takeover, feedMoq is suppressed
688
+ // (#suppressed=true) so only multicast audio reaches the backend.
689
+ if (this.#active === 'multicast') {
690
+ this.#onAudioFrame?.(data, { ...meta, source: 'multicast' })
691
+ } else if (this.#pendingMulticastToken !== null) {
692
+ this.#pendingMulticastAudio = { data: data.slice(), meta: { ...meta, source: 'multicast' } }
693
+ }
694
+ }
695
+ }
696
+
697
+ /**
698
+ * MoQ unicast audio warmup gate. When audio is required, multicast takeover
699
+ * waits until the MoQ unicast audio decoder has emitted at least one frame
700
+ * (so downstream samples-before-takeover counters observe nonzero) or until
701
+ * the existing audio-fallback timer forces the flag true.
702
+ */
703
+ #moqAudioWarmed = false
704
+
705
+ /** Called by the player when the MoQ unicast audio decoder emits first frame. */
706
+ public notifyMoqAudioEmit(): void {
707
+ if (this.#moqAudioWarmed) return
708
+ this.#moqAudioWarmed = true
709
+ this.#tryActivateMulticast()
710
+ }
711
+
712
+ /**
713
+ * Called by the player after a MoQ video keyframe has reached the active
714
+ * decoder path. Used only by MSE/MMTP continuity switching; decoder-reset
715
+ * paths leave allowDeltaMulticastTakeoverAfterMoqKeyframe disabled.
716
+ */
717
+ public notifyMoqVideoKeyframeEmit(): void {
718
+ this.#moqVideoKeyframeEmitted = true
719
+ this.#tryActivateMulticast()
720
+ }
721
+
722
+ #tryActivateMulticast() {
723
+ if (this.#active === 'multicast') return
724
+ if (this.#pendingMulticastToken !== null) return
725
+ if (!this.#multicastVideoKeyed) return
726
+ if (this.#requireAudio && !this.#multicastAudioReceived) return
727
+ if (this.#requireAudio && !this.#moqAudioWarmed) return
728
+ const token = ++this.#sourceSwitchToken
729
+ const maybeReady = this.#onSourceSwitch?.('multicast')
730
+ if (!maybeReady || typeof (maybeReady as Promise<void>).then !== 'function') {
731
+ this.#commitMulticastActivation(token)
732
+ return
733
+ }
734
+ const ready = Promise.resolve(maybeReady)
735
+ this.#pendingMulticastToken = token
736
+ this.#sourceSwitchReady = ready
737
+ void ready.then(
738
+ () => this.#commitMulticastActivation(token),
739
+ err => this.#rejectMulticastActivation(token, err),
740
+ ).finally(() => {
741
+ if (this.#sourceSwitchReady === ready) this.#sourceSwitchReady = null
742
+ })
743
+ }
744
+
745
+ #commitMulticastActivation(token: number) {
746
+ if (token !== this.#sourceSwitchToken) return
747
+ this.#active = 'multicast'
748
+ this.#suppressed = true
749
+ this.#pendingMulticastToken = null
750
+ const video = this.#pendingMulticastVideo
751
+ this.#pendingMulticastVideo = null
752
+ const audio = this.#pendingMulticastAudio
753
+ this.#pendingMulticastAudio = null
754
+ if (video) this.#onVideoFrame?.(video.data, video.meta)
755
+ if (audio) this.#onAudioFrame?.(audio.data, audio.meta)
756
+ }
757
+
758
+ #rejectMulticastActivation(token: number, err: unknown) {
759
+ if (token !== this.#sourceSwitchToken) return
760
+ if (this.#pendingMulticastToken === token) this.#pendingMulticastToken = null
761
+ this.#pendingMulticastVideo = null
762
+ this.#pendingMulticastAudio = null
763
+ console.warn('[MediaRouter] onSourceSwitch(multicast) failed', err)
764
+ }
765
+
766
+ /** Switch back to MoQ immediately (called on multicast failback). */
767
+ failbackToMoq() {
768
+ const hadPendingMulticast = this.#pendingMulticastToken !== null
769
+ if (this.#active === 'moq' && !hadPendingMulticast) return // already on MoQ, no-op
770
+ ++this.#sourceSwitchToken
771
+ this.#active = 'moq'
772
+ this.#suppressed = false
773
+ this.#pendingMulticastToken = null
774
+ this.#pendingMulticastVideo = null
775
+ this.#pendingMulticastAudio = null
776
+ this.#sourceSwitchReady = null
777
+ this.#multicastVideoKeyed = false
778
+ this.#multicastAudioReceived = false
779
+ this.#moqVideoKeyframeEmitted = false
780
+ // A pending audio-fallback timer belongs to the abandoned takeover attempt.
781
+ // Left running it would force-set the audio flags against the next attempt's
782
+ // fresh state (BLO-9413 failback coherence — every takeover-era flag/timer
783
+ // unwinds on this edge).
784
+ if (this.#audioFallbackTimer) {
785
+ clearTimeout(this.#audioFallbackTimer)
786
+ this.#audioFallbackTimer = null
787
+ }
788
+ this.#onSourceSwitch?.('moq')
789
+ }
790
+
791
+ /** Dispose timers and per-track sources. Call on teardown to prevent
792
+ * stale timer callbacks firing into garbage-collected closures (WR-03). */
793
+ dispose(): void {
794
+ if (this.#audioFallbackTimer) {
795
+ clearTimeout(this.#audioFallbackTimer)
796
+ this.#audioFallbackTimer = null
797
+ }
798
+ for (const [name] of this.#trackSources) {
799
+ this.clearTrackSource(name)
800
+ }
801
+ }
802
+
803
+ // ── Private helpers ──────────────────────────────────────────────────────
804
+
805
+ /** Emit a frame on the correct per-track callback using the type registry.
806
+ * Falls back to name match if no type registered (backward compat). */
807
+ #emitForTrack(trackName: string, data: Uint8Array, meta: FrameMeta): void {
808
+ // Prefer explicit type registry (catalog or init data)
809
+ const reg = this.#trackTypes.get(trackName)
810
+ if (reg?.type === 'video') {
811
+ this.#onVideoFrame?.(data, meta)
812
+ } else if (reg?.type === 'audio') {
813
+ this.#onAudioFrame?.(data, meta)
814
+ } else if (reg !== undefined) {
815
+ // Registered but unknown type — overlay
816
+ this.#onOverlayFrame?.(data, meta)
817
+ } else {
818
+ // Not registered — fall back to name match (backward compat for tests/legacy)
819
+ if (trackName === 'video') this.#onVideoFrame?.(data, meta)
820
+ else if (trackName === 'audio') this.#onAudioFrame?.(data, meta)
821
+ else this.#onOverlayFrame?.(data, meta)
822
+ }
823
+ }
824
+
825
+ /** Handle an overlay frame: buffer until first FEC block boundary, then pass through. */
826
+ #handleOverlayFrame(data: Uint8Array, meta: FrameMeta): void {
827
+ if (this.#overlayBoundaryReached) {
828
+ this.#onOverlayFrame?.(data, meta)
829
+ return
830
+ }
831
+
832
+ // Buffer until boundary — enforcing cap for T-02-17 DoS mitigation
833
+ if (this.#overlayBuffer.length >= this.#maxOverlayBuffer) {
834
+ console.warn(
835
+ `[MediaRouter] overlay buffer full (${this.#maxOverlayBuffer} frames); dropping frame ts=${meta.timestamp}`
836
+ )
837
+ return
838
+ }
839
+ this.#overlayBuffer.push({ data, meta })
840
+ }
841
+ }