@editframe/elements 0.16.8-beta.0 → 0.18.3-beta.0

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 (267) hide show
  1. package/README.md +30 -0
  2. package/dist/DecoderResetFrequency.test.d.ts +1 -0
  3. package/dist/DecoderResetRecovery.test.d.ts +1 -0
  4. package/dist/DelayedLoadingState.d.ts +48 -0
  5. package/dist/DelayedLoadingState.integration.test.d.ts +1 -0
  6. package/dist/DelayedLoadingState.js +113 -0
  7. package/dist/DelayedLoadingState.test.d.ts +1 -0
  8. package/dist/EF_FRAMEGEN.d.ts +10 -1
  9. package/dist/EF_FRAMEGEN.js +199 -179
  10. package/dist/EF_INTERACTIVE.js +2 -6
  11. package/dist/EF_RENDERING.js +1 -3
  12. package/dist/LoadingDebounce.test.d.ts +1 -0
  13. package/dist/LoadingIndicator.browsertest.d.ts +0 -0
  14. package/dist/ManualScrubTest.test.d.ts +1 -0
  15. package/dist/ScrubResolvedFlashing.test.d.ts +1 -0
  16. package/dist/ScrubTrackManager.d.ts +96 -0
  17. package/dist/ScrubTrackManager.test.d.ts +1 -0
  18. package/dist/VideoSeekFlashing.browsertest.d.ts +0 -0
  19. package/dist/VideoStuckDiagnostic.test.d.ts +1 -0
  20. package/dist/elements/CrossUpdateController.js +13 -15
  21. package/dist/elements/EFAudio.browsertest.d.ts +0 -0
  22. package/dist/elements/EFAudio.d.ts +22 -3
  23. package/dist/elements/EFAudio.js +60 -43
  24. package/dist/elements/EFCaptions.js +337 -373
  25. package/dist/elements/EFImage.d.ts +1 -0
  26. package/dist/elements/EFImage.js +73 -91
  27. package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +18 -0
  28. package/dist/elements/EFMedia/AssetIdMediaEngine.js +41 -0
  29. package/dist/elements/EFMedia/AssetIdMediaEngine.test.d.ts +1 -0
  30. package/dist/elements/EFMedia/AssetMediaEngine.d.ts +47 -0
  31. package/dist/elements/EFMedia/AssetMediaEngine.js +116 -0
  32. package/dist/elements/EFMedia/BaseMediaEngine.d.ts +55 -0
  33. package/dist/elements/EFMedia/BaseMediaEngine.js +96 -0
  34. package/dist/elements/EFMedia/BaseMediaEngine.test.d.ts +1 -0
  35. package/dist/elements/EFMedia/BufferedSeekingInput.browsertest.d.ts +1 -0
  36. package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +43 -0
  37. package/dist/elements/EFMedia/BufferedSeekingInput.js +159 -0
  38. package/dist/elements/EFMedia/JitMediaEngine.browsertest.d.ts +0 -0
  39. package/dist/elements/EFMedia/JitMediaEngine.d.ts +31 -0
  40. package/dist/elements/EFMedia/JitMediaEngine.js +62 -0
  41. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.d.ts +9 -0
  42. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +16 -0
  43. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +48 -0
  44. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.d.ts +3 -0
  45. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +138 -0
  46. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.d.ts +9 -0
  47. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.d.ts +4 -0
  48. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +16 -0
  49. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.d.ts +9 -0
  50. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.d.ts +3 -0
  51. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +22 -0
  52. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.d.ts +7 -0
  53. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +24 -0
  54. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +4 -0
  55. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +18 -0
  56. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.d.ts +4 -0
  57. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +16 -0
  58. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.d.ts +3 -0
  59. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +104 -0
  60. package/dist/elements/EFMedia/services/AudioElementFactory.browsertest.d.ts +1 -0
  61. package/dist/elements/EFMedia/services/AudioElementFactory.d.ts +22 -0
  62. package/dist/elements/EFMedia/services/AudioElementFactory.js +72 -0
  63. package/dist/elements/EFMedia/services/MediaSourceService.browsertest.d.ts +1 -0
  64. package/dist/elements/EFMedia/services/MediaSourceService.d.ts +47 -0
  65. package/dist/elements/EFMedia/services/MediaSourceService.js +73 -0
  66. package/dist/elements/EFMedia/shared/AudioSpanUtils.d.ts +7 -0
  67. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +54 -0
  68. package/dist/elements/EFMedia/shared/BufferUtils.d.ts +70 -0
  69. package/dist/elements/EFMedia/shared/BufferUtils.js +89 -0
  70. package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +23 -0
  71. package/dist/elements/EFMedia/shared/RenditionHelpers.browsertest.d.ts +1 -0
  72. package/dist/elements/EFMedia/shared/RenditionHelpers.d.ts +19 -0
  73. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.d.ts +1 -0
  74. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.d.ts +18 -0
  75. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +60 -0
  76. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.test.d.ts +1 -0
  77. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.d.ts +9 -0
  78. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +16 -0
  79. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +46 -0
  80. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.d.ts +9 -0
  81. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.d.ts +4 -0
  82. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.js +16 -0
  83. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.d.ts +9 -0
  84. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.d.ts +3 -0
  85. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.js +27 -0
  86. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.d.ts +7 -0
  87. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +25 -0
  88. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.d.ts +9 -0
  89. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.d.ts +4 -0
  90. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +18 -0
  91. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.d.ts +9 -0
  92. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.d.ts +4 -0
  93. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.js +16 -0
  94. package/dist/elements/EFMedia.browsertest.d.ts +1 -0
  95. package/dist/elements/EFMedia.d.ts +95 -66
  96. package/dist/elements/EFMedia.js +204 -683
  97. package/dist/elements/EFSourceMixin.js +31 -48
  98. package/dist/elements/EFTemporal.d.ts +2 -1
  99. package/dist/elements/EFTemporal.js +266 -360
  100. package/dist/elements/EFTimegroup.d.ts +14 -1
  101. package/dist/elements/EFTimegroup.js +337 -323
  102. package/dist/elements/EFVideo.browsertest.d.ts +0 -0
  103. package/dist/elements/EFVideo.d.ts +123 -4
  104. package/dist/elements/EFVideo.js +308 -111
  105. package/dist/elements/EFWaveform.js +375 -411
  106. package/dist/elements/FetchMixin.js +14 -24
  107. package/dist/elements/MediaController.d.ts +30 -0
  108. package/dist/elements/SampleBuffer.d.ts +14 -0
  109. package/dist/elements/SampleBuffer.js +52 -0
  110. package/dist/elements/TargetController.js +130 -156
  111. package/dist/elements/TimegroupController.js +17 -19
  112. package/dist/elements/durationConverter.js +15 -4
  113. package/dist/elements/parseTimeToMs.js +4 -10
  114. package/dist/elements/printTaskStatus.d.ts +2 -0
  115. package/dist/elements/updateAnimations.js +39 -59
  116. package/dist/getRenderInfo.d.ts +2 -2
  117. package/dist/getRenderInfo.js +59 -67
  118. package/dist/gui/ContextMixin.js +150 -288
  119. package/dist/gui/EFConfiguration.js +27 -43
  120. package/dist/gui/EFFilmstrip.d.ts +3 -3
  121. package/dist/gui/EFFilmstrip.js +440 -620
  122. package/dist/gui/EFFitScale.d.ts +2 -2
  123. package/dist/gui/EFFitScale.js +112 -135
  124. package/dist/gui/EFFocusOverlay.js +45 -61
  125. package/dist/gui/EFPreview.js +30 -49
  126. package/dist/gui/EFScrubber.js +78 -99
  127. package/dist/gui/EFTimeDisplay.js +49 -70
  128. package/dist/gui/EFToggleLoop.js +17 -34
  129. package/dist/gui/EFTogglePlay.js +37 -58
  130. package/dist/gui/EFWorkbench.js +66 -88
  131. package/dist/gui/TWMixin.js +2 -48
  132. package/dist/gui/TWMixin2.js +31 -0
  133. package/dist/gui/efContext.js +2 -6
  134. package/dist/gui/fetchContext.js +1 -3
  135. package/dist/gui/focusContext.js +1 -3
  136. package/dist/gui/focusedElementContext.js +2 -6
  137. package/dist/gui/playingContext.js +1 -4
  138. package/dist/gui/services/ElementConnectionManager.browsertest.d.ts +1 -0
  139. package/dist/gui/services/ElementConnectionManager.d.ts +59 -0
  140. package/dist/gui/services/ElementConnectionManager.js +128 -0
  141. package/dist/gui/services/PlaybackController.browsertest.d.ts +1 -0
  142. package/dist/gui/services/PlaybackController.d.ts +103 -0
  143. package/dist/gui/services/PlaybackController.js +290 -0
  144. package/dist/index.js +5 -30
  145. package/dist/msToTimeCode.js +11 -13
  146. package/dist/services/MediaSourceManager.d.ts +62 -0
  147. package/dist/services/MediaSourceManager.js +211 -0
  148. package/dist/style.css +2 -1
  149. package/dist/transcoding/cache/CacheManager.d.ts +73 -0
  150. package/dist/transcoding/cache/RequestDeduplicator.d.ts +29 -0
  151. package/dist/transcoding/cache/RequestDeduplicator.js +53 -0
  152. package/dist/transcoding/cache/RequestDeduplicator.test.d.ts +1 -0
  153. package/dist/transcoding/types/index.d.ts +242 -0
  154. package/dist/transcoding/utils/MediaUtils.d.ts +9 -0
  155. package/dist/transcoding/utils/UrlGenerator.d.ts +26 -0
  156. package/dist/transcoding/utils/UrlGenerator.js +45 -0
  157. package/dist/transcoding/utils/constants.d.ts +27 -0
  158. package/dist/utils/LRUCache.d.ts +34 -0
  159. package/dist/utils/LRUCache.js +115 -0
  160. package/package.json +4 -3
  161. package/src/elements/EFAudio.browsertest.ts +709 -0
  162. package/src/elements/EFAudio.ts +59 -15
  163. package/src/elements/EFCaptions.browsertest.ts +0 -1
  164. package/src/elements/EFImage.browsertest.ts +42 -1
  165. package/src/elements/EFImage.ts +23 -3
  166. package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +222 -0
  167. package/src/elements/EFMedia/AssetIdMediaEngine.ts +70 -0
  168. package/src/elements/EFMedia/AssetMediaEngine.ts +210 -0
  169. package/src/elements/EFMedia/BaseMediaEngine.test.ts +164 -0
  170. package/src/elements/EFMedia/BaseMediaEngine.ts +170 -0
  171. package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +400 -0
  172. package/src/elements/EFMedia/BufferedSeekingInput.ts +267 -0
  173. package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +165 -0
  174. package/src/elements/EFMedia/JitMediaEngine.ts +110 -0
  175. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +554 -0
  176. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +81 -0
  177. package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +241 -0
  178. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +59 -0
  179. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +23 -0
  180. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +55 -0
  181. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +35 -0
  182. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +42 -0
  183. package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +34 -0
  184. package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +23 -0
  185. package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +174 -0
  186. package/src/elements/EFMedia/services/AudioElementFactory.browsertest.ts +325 -0
  187. package/src/elements/EFMedia/services/AudioElementFactory.ts +119 -0
  188. package/src/elements/EFMedia/services/MediaSourceService.browsertest.ts +257 -0
  189. package/src/elements/EFMedia/services/MediaSourceService.ts +102 -0
  190. package/src/elements/EFMedia/shared/AudioSpanUtils.ts +128 -0
  191. package/src/elements/EFMedia/shared/BufferUtils.ts +310 -0
  192. package/src/elements/EFMedia/shared/MediaTaskUtils.ts +44 -0
  193. package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +247 -0
  194. package/src/elements/EFMedia/shared/RenditionHelpers.ts +79 -0
  195. package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +128 -0
  196. package/src/elements/EFMedia/tasks/makeMediaEngineTask.test.ts +233 -0
  197. package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +89 -0
  198. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.ts +555 -0
  199. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +79 -0
  200. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.ts +59 -0
  201. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts +23 -0
  202. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.ts +55 -0
  203. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.ts +45 -0
  204. package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +44 -0
  205. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.ts +57 -0
  206. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +32 -0
  207. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.ts +56 -0
  208. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.ts +23 -0
  209. package/src/elements/EFMedia.browsertest.ts +696 -271
  210. package/src/elements/EFMedia.ts +218 -776
  211. package/src/elements/EFTemporal.browsertest.ts +0 -1
  212. package/src/elements/EFTemporal.ts +13 -3
  213. package/src/elements/EFTimegroup.browsertest.ts +6 -3
  214. package/src/elements/EFTimegroup.ts +221 -27
  215. package/src/elements/EFVideo.browsertest.ts +758 -0
  216. package/src/elements/EFVideo.ts +418 -68
  217. package/src/elements/EFWaveform.ts +5 -5
  218. package/src/elements/MediaController.ts +98 -0
  219. package/src/elements/SampleBuffer.ts +97 -0
  220. package/src/elements/printTaskStatus.ts +16 -0
  221. package/src/elements/updateAnimations.ts +6 -0
  222. package/src/gui/ContextMixin.ts +23 -104
  223. package/src/gui/TWMixin.ts +10 -3
  224. package/src/gui/services/ElementConnectionManager.browsertest.ts +263 -0
  225. package/src/gui/services/ElementConnectionManager.ts +224 -0
  226. package/src/gui/services/PlaybackController.browsertest.ts +437 -0
  227. package/src/gui/services/PlaybackController.ts +521 -0
  228. package/src/services/MediaSourceManager.ts +333 -0
  229. package/src/transcoding/cache/CacheManager.ts +208 -0
  230. package/src/transcoding/cache/RequestDeduplicator.test.ts +170 -0
  231. package/src/transcoding/cache/RequestDeduplicator.ts +65 -0
  232. package/src/transcoding/types/index.ts +265 -0
  233. package/src/transcoding/utils/MediaUtils.ts +63 -0
  234. package/src/transcoding/utils/UrlGenerator.ts +68 -0
  235. package/src/transcoding/utils/constants.ts +36 -0
  236. package/src/utils/LRUCache.ts +153 -0
  237. package/test/EFVideo.framegen.browsertest.ts +127 -0
  238. package/test/__cache__/GET__api_v1_transcode_audio_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__32da3954ba60c96ad732020c65a08ebc/data.bin +0 -0
  239. package/test/__cache__/GET__api_v1_transcode_audio_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__32da3954ba60c96ad732020c65a08ebc/metadata.json +21 -0
  240. package/test/__cache__/GET__api_v1_transcode_audio_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__b0b2b07efcf607de8ee0f650328c32f7/data.bin +0 -0
  241. package/test/__cache__/GET__api_v1_transcode_audio_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__b0b2b07efcf607de8ee0f650328c32f7/metadata.json +21 -0
  242. package/test/__cache__/GET__api_v1_transcode_audio_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a75c2252b542e0c152c780e9a8d7b154/data.bin +0 -0
  243. package/test/__cache__/GET__api_v1_transcode_audio_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a75c2252b542e0c152c780e9a8d7b154/metadata.json +21 -0
  244. package/test/__cache__/GET__api_v1_transcode_audio_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a64ff1cfb1b52cae14df4b5dfa1e222b/data.bin +0 -0
  245. package/test/__cache__/GET__api_v1_transcode_audio_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a64ff1cfb1b52cae14df4b5dfa1e222b/metadata.json +21 -0
  246. package/test/__cache__/GET__api_v1_transcode_audio_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__91e8a522f950809b9f09f4173113b4b0/data.bin +0 -0
  247. package/test/__cache__/GET__api_v1_transcode_audio_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__91e8a522f950809b9f09f4173113b4b0/metadata.json +21 -0
  248. package/test/__cache__/GET__api_v1_transcode_audio_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__e66d2c831d951e74ad0aeaa6489795d0/data.bin +0 -0
  249. package/test/__cache__/GET__api_v1_transcode_audio_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__e66d2c831d951e74ad0aeaa6489795d0/metadata.json +21 -0
  250. package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/data.bin +0 -0
  251. package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/metadata.json +21 -0
  252. package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/data.bin +0 -0
  253. package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/metadata.json +21 -0
  254. package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/data.bin +0 -0
  255. package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/metadata.json +21 -0
  256. package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/data.bin +0 -0
  257. package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/metadata.json +21 -0
  258. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -0
  259. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +19 -0
  260. package/test/createJitTestClips.ts +425 -0
  261. package/test/recordReplayProxyPlugin.js +302 -0
  262. package/test/useAssetMSW.ts +49 -0
  263. package/test/useMSW.ts +44 -0
  264. package/types.json +1 -1
  265. package/dist/gui/TWMixin.css.js +0 -4
  266. /package/dist/elements/{TargetController.test.d.ts → TargetController.browsertest.d.ts} +0 -0
  267. /package/src/elements/{TargetController.test.ts → TargetController.browsertest.ts} +0 -0
@@ -0,0 +1,104 @@
1
+ import { EF_INTERACTIVE } from "../../../EF_INTERACTIVE.js";
2
+ import { LRUCache } from "../../../utils/LRUCache.js";
3
+ import { Task } from "@lit/task";
4
+ const DECAY_WEIGHT = .8;
5
+ function makeAudioTimeDomainAnalysisTask(element) {
6
+ const cache = new LRUCache(1e3);
7
+ return new Task(element, {
8
+ autoRun: EF_INTERACTIVE,
9
+ onError: (error) => {
10
+ console.error("byteTimeDomainTask error", error);
11
+ },
12
+ args: () => [
13
+ element.audioBufferTask.status,
14
+ element.currentSourceTimeMs,
15
+ element.fftSize,
16
+ element.fftDecay,
17
+ element.fftGain,
18
+ element.shouldInterpolateFrequencies
19
+ ],
20
+ task: async () => {
21
+ await element.audioBufferTask.taskComplete;
22
+ if (!element.audioBufferTask.value) return null;
23
+ if (element.currentSourceTimeMs < 0) return null;
24
+ const currentTimeMs = element.currentSourceTimeMs;
25
+ const analysisWindowMs = 5e3;
26
+ const fromMs = Math.max(0, currentTimeMs);
27
+ const toMs = fromMs + analysisWindowMs;
28
+ const { fetchAudioSpanningTime: fetchAudioSpan } = await import("../shared/AudioSpanUtils.js");
29
+ const audioSpan = await fetchAudioSpan(element, fromMs, toMs, new AbortController().signal);
30
+ if (!audioSpan || !audioSpan.blob) {
31
+ console.warn("Time domain analysis skipped: no audio data available");
32
+ return null;
33
+ }
34
+ const tempAudioContext = new OfflineAudioContext(2, 48e3, 48e3);
35
+ const arrayBuffer = await audioSpan.blob.arrayBuffer();
36
+ const audioBuffer = await tempAudioContext.decodeAudioData(arrayBuffer);
37
+ const startOffsetMs = audioSpan.startMs;
38
+ const smoothedKey = `${element.shouldInterpolateFrequencies}:${element.fftSize}:${element.fftDecay}:${element.fftGain}:${startOffsetMs}:${currentTimeMs}`;
39
+ const cachedData = cache.get(smoothedKey);
40
+ if (cachedData) return cachedData;
41
+ const framesData = await Promise.all(Array.from({ length: element.fftDecay }, async (_, frameIndex) => {
42
+ const frameOffset = frameIndex * (1e3 / 30);
43
+ const startTime = Math.max(0, (currentTimeMs - frameOffset - startOffsetMs) / 1e3);
44
+ const cacheKey = `${element.shouldInterpolateFrequencies}:${element.fftSize}:${element.fftGain}:${startOffsetMs}:${startTime}`;
45
+ const cachedFrame = cache.get(cacheKey);
46
+ if (cachedFrame) return cachedFrame;
47
+ let audioContext;
48
+ try {
49
+ audioContext = new OfflineAudioContext(2, 48e3 * (1 / 30), 48e3);
50
+ } catch (error) {
51
+ throw new Error(`[EFMedia.byteTimeDomainTask] Failed to create OfflineAudioContext(2, ${48e3 * (1 / 30)}, 48000) for frame ${frameIndex} at time ${startTime}s: ${error instanceof Error ? error.message : String(error)}. This is for audio time domain analysis.`);
52
+ }
53
+ const source = audioContext.createBufferSource();
54
+ source.buffer = audioBuffer;
55
+ const analyser = audioContext.createAnalyser();
56
+ analyser.fftSize = element.fftSize;
57
+ analyser.minDecibels = -90;
58
+ analyser.maxDecibels = -20;
59
+ const gainNode = audioContext.createGain();
60
+ gainNode.gain.value = element.fftGain;
61
+ source.connect(gainNode);
62
+ gainNode.connect(analyser);
63
+ analyser.connect(audioContext.destination);
64
+ source.start(0, startTime, 1 / 30);
65
+ const dataLength = analyser.fftSize / 2;
66
+ try {
67
+ await audioContext.startRendering();
68
+ const frameData = new Uint8Array(dataLength);
69
+ analyser.getByteTimeDomainData(frameData);
70
+ const points = new Uint8Array(dataLength);
71
+ for (let i = 0; i < dataLength; i++) {
72
+ const pointSamples = frameData.slice(i * (frameData.length / dataLength), (i + 1) * (frameData.length / dataLength));
73
+ const rms = Math.sqrt(pointSamples.reduce((sum, sample) => {
74
+ const normalized = (sample - 128) / 128;
75
+ return sum + normalized * normalized;
76
+ }, 0) / pointSamples.length);
77
+ const avgSign = Math.sign(pointSamples.reduce((sum, sample) => sum + (sample - 128), 0));
78
+ points[i] = Math.min(255, Math.round(128 + avgSign * rms * 128));
79
+ }
80
+ cache.set(cacheKey, points);
81
+ return points;
82
+ } finally {
83
+ source.disconnect();
84
+ analyser.disconnect();
85
+ }
86
+ }));
87
+ const frameLength = framesData[0]?.length ?? 0;
88
+ const smoothedData = new Uint8Array(frameLength);
89
+ for (let i = 0; i < frameLength; i++) {
90
+ let weightedSum = 0;
91
+ let weightSum = 0;
92
+ framesData.forEach((frame, frameIndex) => {
93
+ const decayWeight = DECAY_WEIGHT ** frameIndex;
94
+ weightedSum += (frame[i] ?? 0) * decayWeight;
95
+ weightSum += decayWeight;
96
+ });
97
+ smoothedData[i] = Math.min(255, Math.round(weightedSum / weightSum));
98
+ }
99
+ cache.set(smoothedKey, smoothedData);
100
+ return smoothedData;
101
+ }
102
+ });
103
+ }
104
+ export { makeAudioTimeDomainAnalysisTask };
@@ -0,0 +1,22 @@
1
+ import { MediaSourceService } from './MediaSourceService.js';
2
+ /**
3
+ * Factory for creating and caching MediaElementAudioSourceNode instances
4
+ * Handles the complex lifecycle and caching logic previously embedded in EFMedia
5
+ */
6
+ export declare class AudioElementFactory {
7
+ private cache;
8
+ private currentSource;
9
+ private currentAudioContext;
10
+ /**
11
+ * Create or retrieve cached MediaElementAudioSourceNode for the given AudioContext
12
+ */
13
+ createMediaElementSource(audioContext: AudioContext, mediaSourceService: MediaSourceService): Promise<MediaElementAudioSourceNode>;
14
+ /**
15
+ * Clear all cached sources (useful for testing or cleanup)
16
+ */
17
+ clearCache(): void;
18
+ /**
19
+ * Check if we have a cached source for the given AudioContext
20
+ */
21
+ hasCachedSource(audioContext: AudioContext): boolean;
22
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Factory for creating and caching MediaElementAudioSourceNode instances
3
+ * Handles the complex lifecycle and caching logic previously embedded in EFMedia
4
+ */
5
+ var AudioElementFactory = class {
6
+ constructor() {
7
+ this.cache = /* @__PURE__ */ new WeakMap();
8
+ this.currentSource = null;
9
+ this.currentAudioContext = null;
10
+ }
11
+ /**
12
+ * Create or retrieve cached MediaElementAudioSourceNode for the given AudioContext
13
+ */
14
+ async createMediaElementSource(audioContext, mediaSourceService) {
15
+ const cached = this.cache.get(audioContext);
16
+ if (cached && audioContext.state !== "closed" && this.currentAudioContext === audioContext) return cached;
17
+ if (this.currentSource && this.currentAudioContext !== audioContext) {
18
+ this.currentSource.disconnect();
19
+ if (this.currentAudioContext) this.cache.delete(this.currentAudioContext);
20
+ this.currentSource = null;
21
+ this.currentAudioContext = null;
22
+ }
23
+ await mediaSourceService.ensureInitialized();
24
+ const audioElement = mediaSourceService.getAudioElement();
25
+ if (!audioElement) throw new Error("Audio element not available from MediaSourceService");
26
+ let mediaElementSource;
27
+ try {
28
+ mediaElementSource = audioContext.createMediaElementSource(audioElement);
29
+ } catch (error) {
30
+ if (error instanceof Error && error.message.includes("already connected")) {
31
+ this.clearCache();
32
+ try {
33
+ mediaElementSource = audioContext.createMediaElementSource(audioElement);
34
+ } catch (retryError) {
35
+ console.warn("AudioElementFactory: Failed to create MediaElementSource even after clearing cache:", retryError);
36
+ throw retryError;
37
+ }
38
+ } else throw error;
39
+ }
40
+ this.currentSource = mediaElementSource;
41
+ this.currentAudioContext = audioContext;
42
+ this.cache.set(audioContext, mediaElementSource);
43
+ const cleanup = () => {
44
+ if (audioContext.state === "closed") {
45
+ this.cache.delete(audioContext);
46
+ if (this.currentAudioContext === audioContext) {
47
+ this.currentSource = null;
48
+ this.currentAudioContext = null;
49
+ }
50
+ audioContext.removeEventListener("statechange", cleanup);
51
+ }
52
+ };
53
+ audioContext.addEventListener("statechange", cleanup);
54
+ return mediaElementSource;
55
+ }
56
+ /**
57
+ * Clear all cached sources (useful for testing or cleanup)
58
+ */
59
+ clearCache() {
60
+ if (this.currentSource) this.currentSource.disconnect();
61
+ this.cache = /* @__PURE__ */ new WeakMap();
62
+ this.currentSource = null;
63
+ this.currentAudioContext = null;
64
+ }
65
+ /**
66
+ * Check if we have a cached source for the given AudioContext
67
+ */
68
+ hasCachedSource(audioContext) {
69
+ return this.cache.has(audioContext) && audioContext.state !== "closed";
70
+ }
71
+ };
72
+ export { AudioElementFactory };
@@ -0,0 +1,47 @@
1
+ export interface MediaSourceServiceOptions {
2
+ onError?: (error: Error) => void;
3
+ onReady?: () => void;
4
+ onUpdateEnd?: () => void;
5
+ timeout?: number;
6
+ }
7
+ /**
8
+ * Service for managing MediaSource lifecycle and audio element creation
9
+ * Extracted from EFMedia to improve separation of concerns and testability
10
+ */
11
+ export declare class MediaSourceService {
12
+ private mediaSourceManager;
13
+ private options;
14
+ constructor(options?: MediaSourceServiceOptions);
15
+ /**
16
+ * Initialize MediaSource if not already initialized
17
+ */
18
+ ensureInitialized(): Promise<void>;
19
+ /**
20
+ * Initialize fresh MediaSource
21
+ */
22
+ initialize(): Promise<void>;
23
+ /**
24
+ * Get audio element for MediaElementSource creation
25
+ */
26
+ getAudioElement(): HTMLAudioElement | null;
27
+ /**
28
+ * Feed audio segments to MediaSource
29
+ */
30
+ feedSegment(segmentBuffer: ArrayBuffer): Promise<void>;
31
+ /**
32
+ * Check if MediaSource is ready
33
+ */
34
+ isReady(): boolean;
35
+ /**
36
+ * Get buffered time ranges
37
+ */
38
+ getBuffered(): TimeRanges | null;
39
+ /**
40
+ * Set audio element current time
41
+ */
42
+ setCurrentTime(timeMs: number): void;
43
+ /**
44
+ * Clean up MediaSource resources
45
+ */
46
+ cleanup(): void;
47
+ }
@@ -0,0 +1,73 @@
1
+ import { MediaSourceManager } from "../../../services/MediaSourceManager.js";
2
+ /**
3
+ * Service for managing MediaSource lifecycle and audio element creation
4
+ * Extracted from EFMedia to improve separation of concerns and testability
5
+ */
6
+ var MediaSourceService = class {
7
+ constructor(options = {}) {
8
+ this.mediaSourceManager = null;
9
+ this.options = options;
10
+ }
11
+ /**
12
+ * Initialize MediaSource if not already initialized
13
+ */
14
+ async ensureInitialized() {
15
+ if (this.mediaSourceManager?.isReady()) return;
16
+ await this.initialize();
17
+ }
18
+ /**
19
+ * Initialize fresh MediaSource
20
+ */
21
+ async initialize() {
22
+ this.cleanup();
23
+ const managerOptions = {
24
+ onError: this.options.onError,
25
+ onReady: this.options.onReady,
26
+ onUpdateEnd: this.options.onUpdateEnd,
27
+ timeout: this.options.timeout
28
+ };
29
+ this.mediaSourceManager = new MediaSourceManager(managerOptions);
30
+ await this.mediaSourceManager.initialize();
31
+ }
32
+ /**
33
+ * Get audio element for MediaElementSource creation
34
+ */
35
+ getAudioElement() {
36
+ return this.mediaSourceManager?.getAudioElement() || null;
37
+ }
38
+ /**
39
+ * Feed audio segments to MediaSource
40
+ */
41
+ async feedSegment(segmentBuffer) {
42
+ await this.ensureInitialized();
43
+ if (this.mediaSourceManager) await this.mediaSourceManager.feedSegment(segmentBuffer);
44
+ }
45
+ /**
46
+ * Check if MediaSource is ready
47
+ */
48
+ isReady() {
49
+ return this.mediaSourceManager?.isReady() ?? false;
50
+ }
51
+ /**
52
+ * Get buffered time ranges
53
+ */
54
+ getBuffered() {
55
+ return this.mediaSourceManager?.getBuffered() || null;
56
+ }
57
+ /**
58
+ * Set audio element current time
59
+ */
60
+ setCurrentTime(timeMs) {
61
+ this.mediaSourceManager?.setCurrentTime(timeMs);
62
+ }
63
+ /**
64
+ * Clean up MediaSource resources
65
+ */
66
+ cleanup() {
67
+ if (this.mediaSourceManager) {
68
+ this.mediaSourceManager.cleanup();
69
+ this.mediaSourceManager = null;
70
+ }
71
+ }
72
+ };
73
+ export { MediaSourceService };
@@ -0,0 +1,7 @@
1
+ import { AudioSpan } from '../../../transcoding/types';
2
+ import { EFMedia } from '../../EFMedia';
3
+ /**
4
+ * Fetch audio spanning a time range
5
+ * Main function that orchestrates segment calculation, fetching, and blob creation
6
+ */
7
+ export declare const fetchAudioSpanningTime: (host: EFMedia, fromMs: number, toMs: number, signal: AbortSignal) => Promise<AudioSpan>;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Fetch audio segment data using MediaEngine
3
+ * Pure function with explicit dependencies
4
+ */
5
+ const fetchAudioSegmentData = async (segmentIds, mediaEngine, signal) => {
6
+ const audioRendition = mediaEngine.audioRendition;
7
+ if (!audioRendition) throw new Error("Audio rendition not available");
8
+ const segmentData = /* @__PURE__ */ new Map();
9
+ const fetchPromises = segmentIds.map(async (segmentId) => {
10
+ const arrayBuffer = await mediaEngine.fetchMediaSegment(segmentId, audioRendition, signal);
11
+ return [segmentId, arrayBuffer];
12
+ });
13
+ const fetchedSegments = await Promise.all(fetchPromises);
14
+ signal.throwIfAborted();
15
+ for (const [segmentId, arrayBuffer] of fetchedSegments) segmentData.set(segmentId, arrayBuffer);
16
+ return segmentData;
17
+ };
18
+ /**
19
+ * Create audio span blob from init segment and media segments
20
+ * Pure function for blob creation
21
+ */
22
+ const createAudioSpanBlob = (initSegment, mediaSegments) => {
23
+ const chunks = [initSegment, ...mediaSegments];
24
+ return new Blob(chunks, { type: "audio/mp4" });
25
+ };
26
+ /**
27
+ * Fetch audio spanning a time range
28
+ * Main function that orchestrates segment calculation, fetching, and blob creation
29
+ */
30
+ const fetchAudioSpanningTime = async (host, fromMs, toMs, signal) => {
31
+ if (fromMs >= toMs || fromMs < 0) throw new Error(`Invalid time range: fromMs=${fromMs}, toMs=${toMs}`);
32
+ const mediaEngine = await host.mediaEngineTask.taskComplete;
33
+ const initSegment = await host.audioInitSegmentFetchTask.taskComplete;
34
+ if (!mediaEngine?.audioRendition) throw new Error("Audio rendition not available");
35
+ if (!initSegment) throw new Error("Audio init segment is not available");
36
+ const segmentRanges = mediaEngine.calculateAudioSegmentRange(fromMs, toMs, mediaEngine.audioRendition, host.intrinsicDurationMs || 1e4);
37
+ if (segmentRanges.length === 0) throw new Error(`No segments found for time range ${fromMs}-${toMs}ms`);
38
+ const segmentIds = segmentRanges.map((r) => r.segmentId);
39
+ const segmentData = await fetchAudioSegmentData(segmentIds, mediaEngine, signal);
40
+ const orderedSegments = segmentIds.map((id) => {
41
+ const segment = segmentData.get(id);
42
+ if (!segment) throw new Error(`Missing segment data for segment ID ${id}`);
43
+ return segment;
44
+ });
45
+ const blob = createAudioSpanBlob(initSegment, orderedSegments);
46
+ const actualStartMs = Math.min(...segmentRanges.map((r) => r.startMs));
47
+ const actualEndMs = Math.max(...segmentRanges.map((r) => r.endMs));
48
+ return {
49
+ startMs: actualStartMs,
50
+ endMs: actualEndMs,
51
+ blob
52
+ };
53
+ };
54
+ export { fetchAudioSpanningTime };
@@ -0,0 +1,70 @@
1
+ import { AudioRendition, VideoRendition } from '../../../transcoding/types';
2
+ /**
3
+ * State interface for media buffering - generic for both audio and video
4
+ */
5
+ export interface MediaBufferState {
6
+ currentSeekTimeMs: number;
7
+ activeRequests: Set<number>;
8
+ cachedSegments: Set<number>;
9
+ requestQueue: number[];
10
+ }
11
+ /**
12
+ * Configuration interface for media buffering - generic for both audio and video
13
+ */
14
+ export interface MediaBufferConfig {
15
+ bufferDurationMs: number;
16
+ maxParallelFetches: number;
17
+ enableBuffering: boolean;
18
+ enableContinuousBuffering?: boolean;
19
+ }
20
+ /**
21
+ * Dependencies interface for media buffering - generic for both audio and video
22
+ */
23
+ export interface MediaBufferDependencies<T extends AudioRendition | VideoRendition> {
24
+ computeSegmentId: (timeMs: number, rendition: T) => Promise<number | undefined>;
25
+ fetchSegment: (segmentId: number, rendition: T) => Promise<ArrayBuffer>;
26
+ getRendition: () => Promise<T>;
27
+ logError: (message: string, error: any) => void;
28
+ }
29
+ /**
30
+ * Compute segment range for a time window
31
+ * Pure function - determines which segments are needed for a time range
32
+ */
33
+ export declare const computeSegmentRange: <T extends AudioRendition | VideoRendition>(startTimeMs: number, endTimeMs: number, rendition: T, computeSegmentId: (timeMs: number, rendition: T) => number | undefined) => number[];
34
+ /**
35
+ * Async version of computeSegmentRange for when computeSegmentId is async
36
+ */
37
+ export declare const computeSegmentRangeAsync: <T extends AudioRendition | VideoRendition>(startTimeMs: number, endTimeMs: number, durationMs: number, rendition: T, computeSegmentId: (timeMs: number, rendition: T) => Promise<number | undefined>) => Promise<number[]>;
38
+ /**
39
+ * Compute buffer queue based on current state and desired segments
40
+ * Pure function - determines what segments should be fetched
41
+ */
42
+ export declare const computeBufferQueue: (desiredSegments: number[], activeRequests: Set<number>, cachedSegments: Set<number>) => number[];
43
+ /**
44
+ * Handle seek time change and recompute buffer queue
45
+ * Pure function - computes new queue when seek time changes
46
+ */
47
+ export declare const handleSeekTimeChange: <T extends AudioRendition | VideoRendition>(newSeekTimeMs: number, bufferDurationMs: number, rendition: T, currentState: MediaBufferState, computeSegmentId: (timeMs: number, rendition: T) => number | undefined) => {
48
+ newQueue: number[];
49
+ overlappingRequests: number[];
50
+ };
51
+ /**
52
+ * Check if a specific segment is cached in the buffer
53
+ * Pure function for accessing buffer cache state
54
+ */
55
+ export declare const getCachedSegment: (segmentId: number, bufferState: MediaBufferState | undefined) => boolean;
56
+ /**
57
+ * Get cached segments from a list of segment IDs
58
+ * Pure function that returns which segments are available in cache
59
+ */
60
+ export declare const getCachedSegments: (segmentIds: number[], bufferState: MediaBufferState | undefined) => Set<number>;
61
+ /**
62
+ * Get missing segments from a list of segment IDs
63
+ * Pure function that returns which segments need to be fetched
64
+ */
65
+ export declare const getMissingSegments: (segmentIds: number[], bufferState: MediaBufferState | undefined) => number[];
66
+ /**
67
+ * Core media buffering logic with explicit dependencies
68
+ * Generic implementation that works for both audio and video
69
+ */
70
+ export declare const manageMediaBuffer: <T extends AudioRendition | VideoRendition>(seekTimeMs: number, config: MediaBufferConfig, currentState: MediaBufferState, durationMs: number, signal: AbortSignal, deps: MediaBufferDependencies<T>) => Promise<MediaBufferState>;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Async version of computeSegmentRange for when computeSegmentId is async
3
+ */
4
+ const computeSegmentRangeAsync = async (startTimeMs, endTimeMs, durationMs, rendition, computeSegmentId) => {
5
+ const segments = [];
6
+ const segmentDurationMs = rendition.segmentDurationMs || 1e3;
7
+ const startSegmentIndex = Math.floor(startTimeMs / segmentDurationMs);
8
+ const endSegmentIndex = Math.floor(Math.min(endTimeMs, durationMs) / segmentDurationMs);
9
+ for (let i = startSegmentIndex; i <= endSegmentIndex; i++) {
10
+ const timeMs = i * segmentDurationMs;
11
+ if (timeMs < durationMs) {
12
+ const segmentId = await computeSegmentId(timeMs, rendition);
13
+ if (segmentId !== void 0) segments.push(segmentId);
14
+ }
15
+ }
16
+ return segments.filter((id, index, arr) => arr.indexOf(id) === index);
17
+ };
18
+ /**
19
+ * Compute buffer queue based on current state and desired segments
20
+ * Pure function - determines what segments should be fetched
21
+ */
22
+ const computeBufferQueue = (desiredSegments, activeRequests, cachedSegments) => {
23
+ return desiredSegments.filter((segmentId) => !activeRequests.has(segmentId) && !cachedSegments.has(segmentId));
24
+ };
25
+ /**
26
+ * Core media buffering logic with explicit dependencies
27
+ * Generic implementation that works for both audio and video
28
+ */
29
+ const manageMediaBuffer = async (seekTimeMs, config, currentState, durationMs, signal, deps) => {
30
+ if (!config.enableBuffering) return currentState;
31
+ const rendition = await deps.getRendition();
32
+ const endTimeMs = seekTimeMs + config.bufferDurationMs;
33
+ const desiredSegments = await computeSegmentRangeAsync(seekTimeMs, endTimeMs, durationMs, rendition, deps.computeSegmentId);
34
+ const newQueue = computeBufferQueue(desiredSegments, currentState.activeRequests, currentState.cachedSegments);
35
+ const segmentsToFetch = newQueue.slice(0, config.maxParallelFetches);
36
+ const newActiveRequests = new Set(currentState.activeRequests);
37
+ const newCachedSegments = new Set(currentState.cachedSegments);
38
+ const startNextSegment = (remainingQueue) => {
39
+ if (remainingQueue.length === 0 || signal.aborted) return;
40
+ const availableSlots = config.maxParallelFetches - newActiveRequests.size;
41
+ if (availableSlots <= 0) return;
42
+ const nextSegmentId = remainingQueue[0];
43
+ if (nextSegmentId === void 0) return;
44
+ if (newActiveRequests.has(nextSegmentId) || newCachedSegments.has(nextSegmentId)) {
45
+ startNextSegment(remainingQueue.slice(1));
46
+ return;
47
+ }
48
+ newActiveRequests.add(nextSegmentId);
49
+ deps.fetchSegment(nextSegmentId, rendition).then(() => {
50
+ if (signal.aborted) return;
51
+ newActiveRequests.delete(nextSegmentId);
52
+ newCachedSegments.add(nextSegmentId);
53
+ startNextSegment(remainingQueue.slice(1));
54
+ }).catch((error) => {
55
+ if (signal.aborted) return;
56
+ newActiveRequests.delete(nextSegmentId);
57
+ deps.logError(`Failed to fetch segment ${nextSegmentId}`, error);
58
+ startNextSegment(remainingQueue.slice(1));
59
+ });
60
+ };
61
+ for (const segmentId of segmentsToFetch) {
62
+ if (signal.aborted) break;
63
+ newActiveRequests.add(segmentId);
64
+ deps.fetchSegment(segmentId, rendition).then(() => {
65
+ if (signal.aborted) return;
66
+ newActiveRequests.delete(segmentId);
67
+ newCachedSegments.add(segmentId);
68
+ if (config.enableContinuousBuffering ?? true) {
69
+ const remainingQueue = newQueue.slice(segmentsToFetch.length);
70
+ startNextSegment(remainingQueue);
71
+ }
72
+ }).catch((error) => {
73
+ if (signal.aborted) return;
74
+ newActiveRequests.delete(segmentId);
75
+ deps.logError(`Failed to fetch segment ${segmentId}`, error);
76
+ if (config.enableContinuousBuffering ?? true) {
77
+ const remainingQueue = newQueue.slice(segmentsToFetch.length);
78
+ startNextSegment(remainingQueue);
79
+ }
80
+ });
81
+ }
82
+ return {
83
+ currentSeekTimeMs: seekTimeMs,
84
+ activeRequests: newActiveRequests,
85
+ cachedSegments: newCachedSegments,
86
+ requestQueue: newQueue.slice(segmentsToFetch.length)
87
+ };
88
+ };
89
+ export { manageMediaBuffer };
@@ -0,0 +1,23 @@
1
+ import { Task } from '@lit/task';
2
+ import { AudioRendition, MediaEngine, VideoRendition } from '../../../transcoding/types';
3
+ import { BufferedSeekingInput } from '../BufferedSeekingInput';
4
+ /**
5
+ * Generic rendition type that can be either audio or video
6
+ */
7
+ export type MediaRendition = AudioRendition | VideoRendition;
8
+ /**
9
+ * Generic task type for init segment fetch
10
+ */
11
+ export type InitSegmentFetchTask = Task<readonly [MediaEngine | undefined], ArrayBuffer>;
12
+ /**
13
+ * Generic task type for segment ID calculation
14
+ */
15
+ export type SegmentIdTask = Task<readonly [MediaEngine | undefined, number], number | undefined>;
16
+ /**
17
+ * Generic task type for segment fetch
18
+ */
19
+ export type SegmentFetchTask = Task<readonly [MediaEngine | undefined, number | undefined], ArrayBuffer>;
20
+ /**
21
+ * Generic task type for input creation
22
+ */
23
+ export type InputTask = Task<readonly [ArrayBuffer, ArrayBuffer], BufferedSeekingInput>;
@@ -0,0 +1,19 @@
1
+ import { AudioRendition, MediaEngine, VideoRendition } from '../../../transcoding/types';
2
+ /**
3
+ * Get audio rendition from media engine, throwing if not available
4
+ */
5
+ export declare const getAudioRendition: (mediaEngine: MediaEngine) => AudioRendition;
6
+ /**
7
+ * Get video rendition from media engine, throwing if not available
8
+ */
9
+ export declare const getVideoRendition: (mediaEngine: MediaEngine) => VideoRendition;
10
+ /**
11
+ * Calculate which segment contains a given timestamp
12
+ * Returns 1-based segment ID, or undefined if segmentDurationMs is not available
13
+ */
14
+ export declare const computeSegmentId: (timeMs: number, rendition: AudioRendition | VideoRendition) => number | undefined;
15
+ /**
16
+ * Calculate range of segment IDs that overlap with a time range
17
+ * Returns array of 1-based segment IDs, or empty array if segmentDurationMs is not available
18
+ */
19
+ export declare const calculateSegmentRange: (startTimeMs: number, endTimeMs: number, rendition: AudioRendition | VideoRendition) => number[];
@@ -0,0 +1,18 @@
1
+ import { Task } from '@lit/task';
2
+ import { MediaEngine, VideoRendition } from '../../../transcoding/types';
3
+ import { EFMedia } from '../../EFMedia';
4
+ export declare const getLatestMediaEngine: (host: EFMedia, signal: AbortSignal) => Promise<MediaEngine>;
5
+ export declare const getVideoRendition: (mediaEngine: MediaEngine) => VideoRendition;
6
+ /**
7
+ * Core logic for creating a MediaEngine with explicit dependencies.
8
+ * Pure function that requires all dependencies to be provided.
9
+ */
10
+ export declare const createMediaEngine: (host: EFMedia) => Promise<MediaEngine>;
11
+ /**
12
+ * Handle completion of media engine task - triggers necessary updates.
13
+ * Extracted for testability.
14
+ */
15
+ export declare const handleMediaEngineComplete: (host: EFMedia) => void;
16
+ type MediaEngineTask = Task<readonly [string, string | null], MediaEngine>;
17
+ export declare const makeMediaEngineTask: (host: EFMedia) => MediaEngineTask;
18
+ export {};