@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
@@ -1,697 +1,218 @@
1
- import { Task } from "@lit/task";
2
- import { deepArrayEquals } from "@lit/task/deep-equals.js";
3
- import debug from "debug";
4
- import { css, LitElement } from "lit";
5
- import { property, state } from "lit/decorators.js";
6
- import { VideoAsset } from "@editframe/assets/EncodedAsset.js";
7
- import { MP4File } from "@editframe/assets/MP4File.js";
8
- import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
1
+ import { UrlGenerator } from "../transcoding/utils/UrlGenerator.js";
2
+ import { makeMediaEngineTask } from "./EFMedia/tasks/makeMediaEngineTask.js";
3
+ import { makeAudioBufferTask } from "./EFMedia/audioTasks/makeAudioBufferTask.js";
4
+ import { makeAudioFrequencyAnalysisTask } from "./EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js";
5
+ import { makeAudioInitSegmentFetchTask } from "./EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js";
6
+ import { makeAudioInputTask } from "./EFMedia/audioTasks/makeAudioInputTask.js";
7
+ import { makeAudioSeekTask } from "./EFMedia/audioTasks/makeAudioSeekTask.js";
8
+ import { makeAudioSegmentFetchTask } from "./EFMedia/audioTasks/makeAudioSegmentFetchTask.js";
9
+ import { makeAudioSegmentIdTask } from "./EFMedia/audioTasks/makeAudioSegmentIdTask.js";
10
+ import { makeAudioTimeDomainAnalysisTask } from "./EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js";
11
+ import { AudioElementFactory } from "./EFMedia/services/AudioElementFactory.js";
12
+ import { MediaSourceService } from "./EFMedia/services/MediaSourceService.js";
9
13
  import { EFSourceMixin } from "./EFSourceMixin.js";
10
14
  import { EFTemporal } from "./EFTemporal.js";
11
15
  import { FetchMixin } from "./FetchMixin.js";
12
16
  import { EFTargetable } from "./TargetController.js";
13
17
  import { updateAnimations } from "./updateAnimations.js";
14
- var __defProp = Object.defineProperty;
15
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
16
- var __decorateClass = (decorators, target, key, kind) => {
17
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
18
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
19
- if (decorator = decorators[i])
20
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
21
- if (kind && result) __defProp(target, key, result);
22
- return result;
23
- };
24
- const log = debug("ef:elements:EFMedia");
18
+ import { LitElement, css } from "lit";
19
+ import { property, state } from "lit/decorators.js";
20
+ import _decorate from "@oxc-project/runtime/helpers/decorate";
25
21
  const freqWeightsCache = /* @__PURE__ */ new Map();
26
- class LRUCache {
27
- constructor(maxSize) {
28
- this.cache = /* @__PURE__ */ new Map();
29
- this.maxSize = maxSize;
30
- }
31
- get(key) {
32
- const value = this.cache.get(key);
33
- if (value) {
34
- this.cache.delete(key);
35
- this.cache.set(key, value);
36
- }
37
- return value;
38
- }
39
- set(key, value) {
40
- if (this.cache.has(key)) {
41
- this.cache.delete(key);
42
- } else if (this.cache.size >= this.maxSize) {
43
- const firstKey = this.cache.keys().next().value;
44
- if (firstKey) {
45
- this.cache.delete(firstKey);
46
- }
47
- }
48
- this.cache.set(key, value);
49
- }
50
- }
22
+ var IgnorableError = class extends Error {};
51
23
  const deepGetMediaElements = (element, medias = []) => {
52
- for (const child of Array.from(element.children)) {
53
- if (child instanceof EFMedia) {
54
- medias.push(child);
55
- } else {
56
- deepGetMediaElements(child, medias);
57
- }
58
- }
59
- return medias;
24
+ for (const child of Array.from(element.children)) if (child instanceof EFMedia) medias.push(child);
25
+ else deepGetMediaElements(child, medias);
26
+ return medias;
60
27
  };
61
- const _EFMedia = class _EFMedia2 extends EFTargetable(
62
- EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
63
- assetType: "isobmff_files"
64
- })
65
- ) {
66
- constructor() {
67
- super(...arguments);
68
- this.currentTimeMs = 0;
69
- this.#assetId = null;
70
- this.trackFragmentIndexLoader = new Task(this, {
71
- args: () => [this.fragmentIndexPath(), this.fetch],
72
- task: async ([fragmentIndexPath, fetch], { signal }) => {
73
- try {
74
- const response = await fetch(fragmentIndexPath, { signal });
75
- return await response.json();
76
- } catch (error) {
77
- log("Failed to load track fragment index", error);
78
- return void 0;
79
- }
80
- },
81
- onComplete: () => {
82
- this.requestUpdate("intrinsicDurationMs");
83
- this.requestUpdate("ownCurrentTimeMs");
84
- this.rootTimegroup?.requestUpdate("ownCurrentTimeMs");
85
- this.rootTimegroup?.requestUpdate("durationMs");
86
- }
87
- });
88
- this.initSegmentsLoader = new Task(this, {
89
- autoRun: EF_INTERACTIVE,
90
- args: () => [this.trackFragmentIndexLoader.value, this.src, this.fetch],
91
- task: async ([fragmentIndex, _src, fetch], { signal }) => {
92
- if (!fragmentIndex) {
93
- return;
94
- }
95
- return await Promise.all(
96
- Object.entries(fragmentIndex).map(async ([trackId, track]) => {
97
- const start = track.initSegment.offset;
98
- const end = track.initSegment.offset + track.initSegment.size;
99
- const response = await fetch(this.fragmentTrackPath(trackId), {
100
- signal,
101
- headers: { Range: `bytes=${start}-${end - 1}` }
102
- });
103
- const buffer = await response.arrayBuffer();
104
- buffer.fileStart = 0;
105
- const mp4File = new MP4File();
106
- mp4File.appendBuffer(buffer, true);
107
- mp4File.flush();
108
- await mp4File.readyPromise;
109
- return { trackId, buffer, mp4File };
110
- })
111
- );
112
- }
113
- });
114
- this.seekTask = new Task(this, {
115
- autoRun: EF_INTERACTIVE,
116
- args: () => [
117
- this.desiredSeekTimeMs,
118
- this.trackFragmentIndexLoader.value,
119
- this.initSegmentsLoader.value
120
- ],
121
- task: async ([seekToMs, fragmentIndex, initSegments], { signal: _signal }) => {
122
- if (fragmentIndex === void 0) {
123
- return;
124
- }
125
- if (initSegments === void 0) {
126
- return;
127
- }
128
- const result = {};
129
- for (const index of Object.values(fragmentIndex)) {
130
- const track = initSegments.find((segment2) => segment2.trackId === String(index.track))?.mp4File.getInfo().tracks[0];
131
- if (!track) {
132
- throw new Error("Could not finding matching track");
133
- }
134
- const segment = index.segments.toReversed().find((segment2) => {
135
- return segment2.dts / track.timescale * 1e3 <= seekToMs;
136
- });
137
- const nextSegment = index.segments.find((segment2) => {
138
- return segment2.dts / track.timescale * 1e3 > seekToMs;
139
- });
140
- if (!segment) {
141
- return;
142
- }
143
- result[index.track] = { segment, track, nextSegment };
144
- }
145
- return result;
146
- }
147
- });
148
- this.fetchSeekTask = new Task(this, {
149
- autoRun: EF_INTERACTIVE,
150
- argsEqual: deepArrayEquals,
151
- args: () => [this.initSegmentsLoader.value, this.seekTask.value, this.fetch],
152
- task: async ([initSegments, seekResult, fetch], { signal }) => {
153
- if (!initSegments) {
154
- return;
155
- }
156
- if (!seekResult) {
157
- return;
158
- }
159
- const files = {};
160
- for (const [trackId, { segment, track, nextSegment }] of Object.entries(
161
- seekResult
162
- )) {
163
- const start = segment.offset;
164
- const end = segment.offset + segment.size;
165
- const response = await fetch(this.fragmentTrackPath(trackId), {
166
- signal,
167
- headers: { Range: `bytes=${start}-${end - 1}` }
168
- });
169
- if (nextSegment) {
170
- const nextStart = nextSegment.offset;
171
- const nextEnd = nextSegment.offset + nextSegment.size;
172
- fetch(this.fragmentTrackPath(trackId), {
173
- signal,
174
- headers: { Range: `bytes=${nextStart}-${nextEnd - 1}` }
175
- }).then(() => {
176
- log("Prefetched next segment");
177
- }).catch((error) => {
178
- log("Failed to prefetch next segment", error);
179
- });
180
- }
181
- const initSegment = Object.values(initSegments).find(
182
- (initSegment2) => initSegment2.trackId === String(track.id)
183
- );
184
- if (!initSegment) {
185
- throw new Error("Could not find matching init segment");
186
- }
187
- const initBuffer = initSegment.buffer;
188
- const mediaBuffer = await response.arrayBuffer();
189
- files[trackId] = new File([initBuffer, mediaBuffer], "video.mp4", {
190
- type: "video/mp4"
191
- });
192
- }
193
- return files;
194
- }
195
- });
196
- this.videoAssetTask = new Task(this, {
197
- autoRun: EF_INTERACTIVE,
198
- args: () => [this.fetchSeekTask.value],
199
- task: async ([files], { signal: _signal }) => {
200
- if (!files) {
201
- return;
202
- }
203
- if (!this.defaultVideoTrackId) {
204
- return;
205
- }
206
- const videoFile = files[this.defaultVideoTrackId];
207
- if (!videoFile) {
208
- return;
209
- }
210
- for (const frame of this.videoAssetTask.value?.decodedFrames || []) {
211
- frame.close();
212
- }
213
- this.videoAssetTask.value?.videoDecoder?.close();
214
- return await VideoAsset.createFromReadableStream(
215
- "video.mp4",
216
- videoFile.stream(),
217
- videoFile
218
- );
219
- }
220
- });
221
- this.desiredSeekTimeMs = 0;
222
- this.#audioContext = new OfflineAudioContext(2, 48e3 / 30, 48e3);
223
- this.audioBufferTask = new Task(this, {
224
- autoRun: EF_INTERACTIVE,
225
- args: () => [this.fetchSeekTask.value, this.seekTask.value],
226
- task: async ([files, segments], { signal: _signal }) => {
227
- if (!files) {
228
- return;
229
- }
230
- if (!segments) {
231
- return;
232
- }
233
- if (!this.defaultAudioTrackId) {
234
- return;
235
- }
236
- const segment = segments[this.defaultAudioTrackId];
237
- if (!segment) {
238
- return;
239
- }
240
- const audioFile = files[this.defaultAudioTrackId];
241
- if (!audioFile) {
242
- return;
243
- }
244
- return {
245
- buffer: await this.#audioContext.decodeAudioData(
246
- await audioFile.arrayBuffer()
247
- ),
248
- startOffsetMs: segment.segment.cts / segment.track.timescale * 1e3
249
- };
250
- }
251
- });
252
- this.#byteTimeDomainCache = new LRUCache(100);
253
- this.byteTimeDomainTask = new Task(this, {
254
- autoRun: EF_INTERACTIVE,
255
- args: () => [
256
- this.audioBufferTask.status,
257
- this.currentSourceTimeMs,
258
- this.fftSize,
259
- this.fftDecay,
260
- this.fftGain,
261
- this.shouldInterpolateFrequencies
262
- ],
263
- task: async () => {
264
- await this.audioBufferTask.taskComplete;
265
- if (!this.audioBufferTask.value) return null;
266
- if (this.currentSourceTimeMs <= 0) return null;
267
- const currentTimeMs = this.currentSourceTimeMs;
268
- const startOffsetMs = this.audioBufferTask.value.startOffsetMs;
269
- const audioBuffer = this.audioBufferTask.value.buffer;
270
- const smoothedKey = `${this.shouldInterpolateFrequencies}:${this.fftSize}:${this.fftDecay}:${this.fftGain}:${startOffsetMs}:${currentTimeMs}`;
271
- const cachedData = this.#byteTimeDomainCache.get(smoothedKey);
272
- if (cachedData) return cachedData;
273
- const framesData = await Promise.all(
274
- Array.from({ length: this.fftDecay }, async (_, frameIndex) => {
275
- const frameOffset = frameIndex * (1e3 / 30);
276
- const startTime = Math.max(
277
- 0,
278
- (currentTimeMs - frameOffset - startOffsetMs) / 1e3
279
- );
280
- const cacheKey = `${this.shouldInterpolateFrequencies}:${this.fftSize}:${this.fftGain}:${startOffsetMs}:${startTime}`;
281
- const cachedFrame = this.#byteTimeDomainCache.get(cacheKey);
282
- if (cachedFrame) return cachedFrame;
283
- const audioContext = new OfflineAudioContext(
284
- 2,
285
- 48e3 * (1 / 30),
286
- 48e3
287
- );
288
- const source = audioContext.createBufferSource();
289
- source.buffer = audioBuffer;
290
- const analyser = audioContext.createAnalyser();
291
- analyser.fftSize = this.fftSize;
292
- analyser.minDecibels = -90;
293
- analyser.maxDecibels = -20;
294
- const gainNode = audioContext.createGain();
295
- gainNode.gain.value = this.fftGain;
296
- source.connect(gainNode);
297
- gainNode.connect(analyser);
298
- analyser.connect(audioContext.destination);
299
- source.start(0, startTime, 1 / 30);
300
- const dataLength = analyser.fftSize / 2;
301
- try {
302
- await audioContext.startRendering();
303
- const frameData = new Uint8Array(dataLength);
304
- analyser.getByteTimeDomainData(frameData);
305
- const points = new Uint8Array(dataLength);
306
- for (let i = 0; i < dataLength; i++) {
307
- const pointSamples = frameData.slice(
308
- i * (frameData.length / dataLength),
309
- (i + 1) * (frameData.length / dataLength)
310
- );
311
- const rms = Math.sqrt(
312
- pointSamples.reduce((sum, sample) => {
313
- const normalized = (sample - 128) / 128;
314
- return sum + normalized * normalized;
315
- }, 0) / pointSamples.length
316
- );
317
- const avgSign = Math.sign(
318
- pointSamples.reduce((sum, sample) => sum + (sample - 128), 0)
319
- );
320
- points[i] = Math.min(255, Math.round(128 + avgSign * rms * 128));
321
- }
322
- this.#byteTimeDomainCache.set(cacheKey, points);
323
- return points;
324
- } finally {
325
- source.disconnect();
326
- analyser.disconnect();
327
- }
328
- })
329
- );
330
- const frameLength = framesData[0]?.length ?? 0;
331
- const smoothedData = new Uint8Array(frameLength);
332
- for (let i = 0; i < frameLength; i++) {
333
- let weightedSum = 0;
334
- let weightSum = 0;
335
- framesData.forEach((frame, frameIndex) => {
336
- const decayWeight = _EFMedia2.DECAY_WEIGHT ** frameIndex;
337
- weightedSum += (frame[i] ?? 0) * decayWeight;
338
- weightSum += decayWeight;
339
- });
340
- smoothedData[i] = Math.min(255, Math.round(weightedSum / weightSum));
341
- }
342
- this.#byteTimeDomainCache.set(smoothedKey, smoothedData);
343
- return smoothedData;
344
- }
345
- });
346
- this.#frequencyDataCache = new LRUCache(100);
347
- this.frequencyDataTask = new Task(this, {
348
- autoRun: EF_INTERACTIVE,
349
- args: () => [
350
- this.audioBufferTask.status,
351
- this.currentSourceTimeMs,
352
- this.fftSize,
353
- this.fftDecay,
354
- this.fftGain,
355
- this.shouldInterpolateFrequencies
356
- ],
357
- task: async () => {
358
- await this.audioBufferTask.taskComplete;
359
- if (!this.audioBufferTask.value) return null;
360
- if (this.currentSourceTimeMs <= 0) return null;
361
- const currentTimeMs = this.currentSourceTimeMs;
362
- const startOffsetMs = this.audioBufferTask.value.startOffsetMs;
363
- const audioBuffer = this.audioBufferTask.value.buffer;
364
- const smoothedKey = `${this.shouldInterpolateFrequencies}:${this.fftSize}:${this.fftDecay}:${this.fftGain}:${startOffsetMs}:${currentTimeMs}`;
365
- const cachedSmoothedData = this.#frequencyDataCache.get(smoothedKey);
366
- if (cachedSmoothedData) {
367
- return cachedSmoothedData;
368
- }
369
- const framesData = await Promise.all(
370
- Array.from({ length: this.fftDecay }, async (_, i) => {
371
- const frameOffset = i * (1e3 / 30);
372
- const startTime = Math.max(
373
- 0,
374
- (currentTimeMs - frameOffset - startOffsetMs) / 1e3
375
- );
376
- const cacheKey = `${this.shouldInterpolateFrequencies}:${this.fftSize}:${this.fftGain}:${startOffsetMs}:${startTime}`;
377
- const cachedFrame = this.#frequencyDataCache.get(cacheKey);
378
- if (cachedFrame) {
379
- return cachedFrame;
380
- }
381
- const audioContext = new OfflineAudioContext(
382
- 2,
383
- 48e3 * (1 / 30),
384
- 48e3
385
- );
386
- const analyser = audioContext.createAnalyser();
387
- analyser.fftSize = this.fftSize;
388
- analyser.minDecibels = -90;
389
- analyser.maxDecibels = -10;
390
- const gainNode = audioContext.createGain();
391
- gainNode.gain.value = this.fftGain;
392
- const filter = audioContext.createBiquadFilter();
393
- filter.type = "bandpass";
394
- filter.frequency.value = 15e3;
395
- filter.Q.value = 0.05;
396
- const audioBufferSource = audioContext.createBufferSource();
397
- audioBufferSource.buffer = audioBuffer;
398
- audioBufferSource.connect(filter);
399
- filter.connect(gainNode);
400
- gainNode.connect(analyser);
401
- analyser.connect(audioContext.destination);
402
- audioBufferSource.start(0, startTime, 1 / 30);
403
- try {
404
- await audioContext.startRendering();
405
- const frameData = new Uint8Array(this.fftSize / 2);
406
- analyser.getByteFrequencyData(frameData);
407
- this.#frequencyDataCache.set(cacheKey, frameData);
408
- return frameData;
409
- } finally {
410
- audioBufferSource.disconnect();
411
- analyser.disconnect();
412
- }
413
- })
414
- );
415
- const frameLength = framesData[0]?.length ?? 0;
416
- const smoothedData = new Uint8Array(frameLength);
417
- for (let i = 0; i < frameLength; i++) {
418
- let weightedSum = 0;
419
- let weightSum = 0;
420
- framesData.forEach((frame, frameIndex) => {
421
- const decayWeight = _EFMedia2.DECAY_WEIGHT ** frameIndex;
422
- weightedSum += frame[i] * decayWeight;
423
- weightSum += decayWeight;
424
- });
425
- smoothedData[i] = Math.min(255, Math.round(weightedSum / weightSum));
426
- }
427
- smoothedData.forEach((value, i) => {
428
- const freqWeight = this.FREQ_WEIGHTS[i];
429
- smoothedData[i] = Math.min(255, Math.round(value * freqWeight));
430
- });
431
- const slicedData = smoothedData.slice(
432
- 0,
433
- Math.floor(smoothedData.length / 2)
434
- );
435
- const processedData = this.shouldInterpolateFrequencies ? processFFTData(slicedData) : slicedData;
436
- this.#frequencyDataCache.set(smoothedKey, processedData);
437
- return processedData;
438
- }
439
- });
440
- }
441
- static {
442
- this.styles = [
443
- css`
28
+ var EFMedia = class extends EFTargetable(EFSourceMixin(EFTemporal(FetchMixin(LitElement)), { assetType: "isobmff_files" })) {
29
+ constructor(..._args) {
30
+ super(..._args);
31
+ this.mediaSourceService = new MediaSourceService({
32
+ onError: (error) => {
33
+ console.error("🎵 [EFMedia] MediaSourceService error:", error);
34
+ },
35
+ onReady: () => {}
36
+ });
37
+ this.audioElementFactory = new AudioElementFactory();
38
+ this.currentTimeMs = 0;
39
+ this.audioBufferDurationMs = 3e4;
40
+ this.maxAudioBufferFetches = 2;
41
+ this.enableAudioBuffering = true;
42
+ this.mute = false;
43
+ this.fftSize = 128;
44
+ this.fftDecay = 8;
45
+ this.fftGain = 3;
46
+ this.interpolateFrequencies = false;
47
+ this.mediaEngineTask = makeMediaEngineTask(this);
48
+ this.audioSegmentIdTask = makeAudioSegmentIdTask(this);
49
+ this.audioInitSegmentFetchTask = makeAudioInitSegmentFetchTask(this);
50
+ this.audioSegmentFetchTask = makeAudioSegmentFetchTask(this);
51
+ this.audioInputTask = makeAudioInputTask(this);
52
+ this.audioSeekTask = makeAudioSeekTask(this);
53
+ this.audioBufferTask = makeAudioBufferTask(this);
54
+ this.byteTimeDomainTask = makeAudioTimeDomainAnalysisTask(this);
55
+ this.frequencyDataTask = makeAudioFrequencyAnalysisTask(this);
56
+ this.assetId = null;
57
+ this._desiredSeekTimeMs = 0;
58
+ }
59
+ static {
60
+ this.VIDEO_SAMPLE_BUFFER_SIZE = 30;
61
+ }
62
+ static {
63
+ this.AUDIO_SAMPLE_BUFFER_SIZE = 120;
64
+ }
65
+ static get observedAttributes() {
66
+ const parentAttributes = super.observedAttributes || [];
67
+ return [
68
+ ...parentAttributes,
69
+ "mute",
70
+ "fft-size",
71
+ "fft-decay",
72
+ "fft-gain",
73
+ "interpolate-frequencies",
74
+ "asset-id",
75
+ "audio-buffer-duration",
76
+ "max-audio-buffer-fetches",
77
+ "enable-audio-buffering"
78
+ ];
79
+ }
80
+ static {
81
+ this.styles = [css`
444
82
  :host {
445
83
  display: block;
446
84
  position: relative;
447
85
  overflow: hidden;
448
86
  }
449
- `
450
- ];
451
- }
452
- #assetId;
453
- set assetId(value) {
454
- this.#assetId = value;
455
- }
456
- get assetId() {
457
- return this.#assetId || this.getAttribute("asset-id");
458
- }
459
- fragmentIndexPath() {
460
- if (this.assetId) {
461
- return `${this.apiHost}/api/v1/isobmff_files/${this.assetId}/index`;
462
- }
463
- return `/@ef-track-fragment-index/${this.src ?? ""}`;
464
- }
465
- fragmentTrackPath(trackId) {
466
- if (this.assetId) {
467
- return `${this.apiHost}/api/v1/isobmff_tracks/${this.assetId}/${trackId}`;
468
- }
469
- return `/@ef-track/${this.src ?? ""}?trackId=${trackId}`;
470
- }
471
- get defaultVideoTrackId() {
472
- return Object.values(this.trackFragmentIndexLoader.value ?? {}).find(
473
- (track) => track.type === "video"
474
- )?.track;
475
- }
476
- get defaultAudioTrackId() {
477
- return Object.values(this.trackFragmentIndexLoader.value ?? {}).find(
478
- (track) => track.type === "audio"
479
- )?.track;
480
- }
481
- async executeSeek(seekToMs) {
482
- this.desiredSeekTimeMs = seekToMs;
483
- }
484
- updated(changedProperties) {
485
- if (changedProperties.has("ownCurrentTimeMs")) {
486
- this.executeSeek(this.currentSourceTimeMs);
487
- }
488
- if (changedProperties.has("currentTime") || changedProperties.has("ownCurrentTimeMs")) {
489
- updateAnimations(this);
490
- }
491
- }
492
- get hasOwnDuration() {
493
- return true;
494
- }
495
- get intrinsicDurationMs() {
496
- if (!this.trackFragmentIndexLoader.value) {
497
- return 0;
498
- }
499
- const durations = Object.values(this.trackFragmentIndexLoader.value).map(
500
- (track) => {
501
- return track.duration / track.timescale * 1e3;
502
- }
503
- );
504
- if (durations.length === 0) {
505
- return 0;
506
- }
507
- return Math.max(...durations);
508
- }
509
- #audioContext;
510
- async fetchAudioSpanningTime(fromMs, toMs) {
511
- if (this.sourceInMs) {
512
- fromMs -= this.startTimeMs - (this.trimStartMs ?? 0) - (this.sourceInMs ?? 0);
513
- }
514
- if (this.sourceOutMs) {
515
- toMs -= this.startTimeMs - (this.trimStartMs ?? 0) - (this.sourceOutMs ?? 0);
516
- }
517
- fromMs -= this.startTimeMs - (this.trimStartMs ?? 0);
518
- toMs -= this.startTimeMs - (this.trimStartMs ?? 0);
519
- await this.trackFragmentIndexLoader.taskComplete;
520
- const audioTrackId = this.defaultAudioTrackId;
521
- if (!audioTrackId) {
522
- log("No audio track found");
523
- return;
524
- }
525
- const audioTrackIndex = this.trackFragmentIndexLoader.value?.[audioTrackId];
526
- if (!audioTrackIndex) {
527
- log("No audio track found");
528
- return;
529
- }
530
- const start = audioTrackIndex.initSegment.offset;
531
- const end = audioTrackIndex.initSegment.offset + audioTrackIndex.initSegment.size;
532
- const audioInitFragmentRequest = this.fetch(
533
- this.fragmentTrackPath(String(audioTrackId)),
534
- {
535
- headers: { Range: `bytes=${start}-${end - 1}` }
536
- }
537
- );
538
- const fragments = Object.values(audioTrackIndex.segments).filter(
539
- (segment) => {
540
- const segmentStartsBeforeEnd = segment.dts <= toMs * audioTrackIndex.timescale / 1e3;
541
- const segmentEndsAfterStart = segment.dts + segment.duration >= fromMs * audioTrackIndex.timescale / 1e3;
542
- return segmentStartsBeforeEnd && segmentEndsAfterStart;
543
- }
544
- );
545
- const firstFragment = fragments[0];
546
- if (!firstFragment) {
547
- log("No audio fragments found");
548
- return;
549
- }
550
- const lastFragment = fragments[fragments.length - 1];
551
- if (!lastFragment) {
552
- log("No audio fragments found");
553
- return;
554
- }
555
- const fragmentStart = firstFragment.offset;
556
- const fragmentEnd = lastFragment.offset + lastFragment.size;
557
- const audioFragmentRequest = this.fetch(
558
- this.fragmentTrackPath(String(audioTrackId)),
559
- {
560
- headers: { Range: `bytes=${fragmentStart}-${fragmentEnd - 1}` }
561
- }
562
- );
563
- const initResponse = await audioInitFragmentRequest;
564
- const dataResponse = await audioFragmentRequest;
565
- const initBuffer = await initResponse.arrayBuffer();
566
- const dataBuffer = await dataResponse.arrayBuffer();
567
- const audioBlob = new Blob([initBuffer, dataBuffer], {
568
- type: "audio/mp4"
569
- });
570
- return {
571
- blob: audioBlob,
572
- startMs: firstFragment.dts / audioTrackIndex.timescale * 1e3 - (this.trimStartMs ?? 0),
573
- endMs: lastFragment.dts / audioTrackIndex.timescale * 1e3 + lastFragment.duration / audioTrackIndex.timescale * 1e3 - (this.trimEndMs ?? 0)
574
- };
575
- }
576
- set fftSize(value) {
577
- const oldValue = this.fftSize;
578
- this.setAttribute("fft-size", String(value));
579
- this.requestUpdate("fft-size", oldValue);
580
- }
581
- set fftDecay(value) {
582
- const oldValue = this.fftDecay;
583
- this.setAttribute("fft-decay", String(value));
584
- this.requestUpdate("fft-decay", oldValue);
585
- }
586
- get fftSize() {
587
- return Number.parseInt(this.getAttribute("fft-size") ?? "128", 10);
588
- }
589
- get fftDecay() {
590
- return Number.parseInt(this.getAttribute("fft-decay") ?? "8", 10);
591
- }
592
- set interpolateFrequencies(value) {
593
- const oldValue = this.interpolateFrequencies;
594
- this.setAttribute("interpolate-frequencies", String(value));
595
- this.requestUpdate("interpolate-frequencies", oldValue);
596
- }
597
- get interpolateFrequencies() {
598
- return this.getAttribute("interpolate-frequencies") !== "false";
599
- }
600
- get shouldInterpolateFrequencies() {
601
- if (this.hasAttribute("interpolate-frequencies")) {
602
- return this.getAttribute("interpolate-frequencies") !== "false";
603
- }
604
- return false;
605
- }
606
- static {
607
- this.DECAY_WEIGHT = 0.7;
608
- }
609
- // Update FREQ_WEIGHTS to use the instance fftSize instead of a static value
610
- get FREQ_WEIGHTS() {
611
- if (freqWeightsCache.has(this.fftSize)) {
612
- return freqWeightsCache.get(this.fftSize);
613
- }
614
- const weights = new Float32Array(this.fftSize / 2).map((_, i) => {
615
- const frequency = i * 48e3 / this.fftSize;
616
- if (frequency < 60) return 0.3;
617
- if (frequency < 250) return 0.4;
618
- if (frequency < 500) return 0.6;
619
- if (frequency < 2e3) return 0.8;
620
- if (frequency < 4e3) return 1.2;
621
- if (frequency < 8e3) return 1.6;
622
- return 2;
623
- });
624
- freqWeightsCache.set(this.fftSize, weights);
625
- return weights;
626
- }
627
- #byteTimeDomainCache;
628
- #frequencyDataCache;
629
- set fftGain(value) {
630
- const oldValue = this.fftGain;
631
- this.setAttribute("fft-gain", String(value));
632
- this.requestUpdate("fft-gain", oldValue);
633
- }
634
- get fftGain() {
635
- return Number.parseFloat(this.getAttribute("fft-gain") ?? "3.0");
636
- }
637
- };
638
- __decorateClass([
639
- property({ type: Number })
640
- ], _EFMedia.prototype, "currentTimeMs", 2);
641
- __decorateClass([
642
- property({ type: String, attribute: "asset-id", reflect: true })
643
- ], _EFMedia.prototype, "assetId", 1);
644
- __decorateClass([
645
- state()
646
- ], _EFMedia.prototype, "desiredSeekTimeMs", 2);
647
- let EFMedia = _EFMedia;
648
- function processFFTData(fftData, zeroThresholdPercent = 0.1) {
649
- const totalBins = fftData.length;
650
- const zeroThresholdCount = Math.floor(totalBins * zeroThresholdPercent);
651
- let zeroCount = 0;
652
- let cutoffIndex = totalBins;
653
- for (let i = totalBins - 1; i >= 0; i--) {
654
- if (fftData[i] < 10) {
655
- zeroCount++;
656
- } else {
657
- if (zeroCount >= zeroThresholdCount) {
658
- cutoffIndex = i + 1;
659
- break;
660
- }
661
- }
662
- }
663
- if (cutoffIndex < zeroThresholdCount) {
664
- return fftData;
665
- }
666
- const goodData = fftData.slice(0, cutoffIndex);
667
- const resampledData = interpolateData(goodData, fftData.length);
668
- const attenuationStartIndex = Math.floor(totalBins * 0.9);
669
- for (let i = attenuationStartIndex; i < totalBins; i++) {
670
- const attenuationProgress = (i - attenuationStartIndex) / (totalBins - attenuationStartIndex) + 0.2;
671
- const attenuationFactor = Math.max(0, 1 - attenuationProgress);
672
- resampledData[i] = Math.floor(resampledData[i] * attenuationFactor);
673
- }
674
- return resampledData;
675
- }
676
- function interpolateData(data, targetSize) {
677
- const resampled = new Uint8Array(targetSize);
678
- const dataLength = data.length;
679
- for (let i = 0; i < targetSize; i++) {
680
- const ratio = i / (targetSize - 1) * (dataLength - 1);
681
- const index = Math.floor(ratio);
682
- const fraction = ratio - index;
683
- if (index >= dataLength - 1) {
684
- resampled[i] = data[dataLength - 1];
685
- } else {
686
- resampled[i] = Math.round(
687
- // biome-ignore lint/style/noNonNullAssertion: Manual bounds check
688
- data[index] * (1 - fraction) + data[index + 1] * fraction
689
- );
690
- }
691
- }
692
- return resampled;
693
- }
694
- export {
695
- EFMedia,
696
- deepGetMediaElements
87
+ `];
88
+ }
89
+ get FREQ_WEIGHTS() {
90
+ if (freqWeightsCache.has(this.fftSize)) return freqWeightsCache.get(this.fftSize);
91
+ const weights = new Float32Array(this.fftSize / 2).map((_, i) => {
92
+ const frequency = i * 48e3 / this.fftSize;
93
+ if (frequency < 60) return .3;
94
+ if (frequency < 250) return .4;
95
+ if (frequency < 500) return .6;
96
+ if (frequency < 2e3) return .8;
97
+ if (frequency < 4e3) return 1.2;
98
+ if (frequency < 8e3) return 1.6;
99
+ return 2;
100
+ });
101
+ freqWeightsCache.set(this.fftSize, weights);
102
+ return weights;
103
+ }
104
+ get shouldInterpolateFrequencies() {
105
+ return this.interpolateFrequencies;
106
+ }
107
+ get urlGenerator() {
108
+ return new UrlGenerator(() => this.apiHost ?? "");
109
+ }
110
+ get intrinsicDurationMs() {
111
+ return this.mediaEngineTask.value?.durationMs ?? 0;
112
+ }
113
+ updated(changedProperties) {
114
+ super.updated(changedProperties);
115
+ if (changedProperties.has("ownCurrentTimeMs")) this.executeSeek(this.currentSourceTimeMs);
116
+ if (changedProperties.has("currentTime") || changedProperties.has("ownCurrentTimeMs")) updateAnimations(this);
117
+ }
118
+ get hasOwnDuration() {
119
+ return true;
120
+ }
121
+ get desiredSeekTimeMs() {
122
+ return this._desiredSeekTimeMs;
123
+ }
124
+ set desiredSeekTimeMs(value) {
125
+ if (this._desiredSeekTimeMs !== value) this._desiredSeekTimeMs = value;
126
+ }
127
+ async executeSeek(seekToMs) {
128
+ this.desiredSeekTimeMs = seekToMs;
129
+ }
130
+ /**
131
+ * Main integration method for EFTimegroup audio playback
132
+ * Now powered by clean, testable utility functions
133
+ */
134
+ async fetchAudioSpanningTime(fromMs, toMs, signal = new AbortController().signal) {
135
+ await this.mediaSourceService.initialize();
136
+ const { fetchAudioSpanningTime: fetchAudioSpan } = await import("./EFMedia/shared/AudioSpanUtils.js");
137
+ return fetchAudioSpan(this, fromMs, toMs, signal);
138
+ }
139
+ /**
140
+ * Get the HTML audio element for ContextMixin integration
141
+ */
142
+ get audioElement() {
143
+ return this.mediaSourceService.getAudioElement();
144
+ }
145
+ /**
146
+ * Check if an audio segment is cached in the unified buffer system
147
+ * Now uses the same caching approach as video for consistency
148
+ */
149
+ getCachedAudioSegment(segmentId) {
150
+ return this.audioBufferTask.value?.cachedSegments.has(segmentId) ?? false;
151
+ }
152
+ /**
153
+ * Get cached audio segments from the unified buffer system
154
+ * Now uses the same caching approach as video for consistency
155
+ */
156
+ getCachedAudioSegments(segmentIds) {
157
+ const bufferState = this.audioBufferTask.value;
158
+ if (!bufferState) return /* @__PURE__ */ new Set();
159
+ return new Set(segmentIds.filter((id) => bufferState.cachedSegments.has(id)));
160
+ }
161
+ /**
162
+ * Get MediaElementAudioSourceNode for ContextMixin integration
163
+ * Uses AudioElementFactory for proper caching and lifecycle management
164
+ */
165
+ async getMediaElementSource(audioContext) {
166
+ return this.audioElementFactory.createMediaElementSource(audioContext, this.mediaSourceService);
167
+ }
168
+ disconnectedCallback() {
169
+ super.disconnectedCallback?.();
170
+ this.mediaSourceService.cleanup();
171
+ this.audioElementFactory.clearCache();
172
+ }
697
173
  };
174
+ _decorate([property({ type: Number })], EFMedia.prototype, "currentTimeMs", void 0);
175
+ _decorate([property({
176
+ type: Number,
177
+ attribute: "audio-buffer-duration"
178
+ })], EFMedia.prototype, "audioBufferDurationMs", void 0);
179
+ _decorate([property({
180
+ type: Number,
181
+ attribute: "max-audio-buffer-fetches"
182
+ })], EFMedia.prototype, "maxAudioBufferFetches", void 0);
183
+ _decorate([property({
184
+ type: Boolean,
185
+ attribute: "enable-audio-buffering"
186
+ })], EFMedia.prototype, "enableAudioBuffering", void 0);
187
+ _decorate([property({
188
+ type: Boolean,
189
+ attribute: "mute",
190
+ reflect: true
191
+ })], EFMedia.prototype, "mute", void 0);
192
+ _decorate([property({
193
+ type: Number,
194
+ attribute: "fft-size",
195
+ reflect: true
196
+ })], EFMedia.prototype, "fftSize", void 0);
197
+ _decorate([property({
198
+ type: Number,
199
+ attribute: "fft-decay",
200
+ reflect: true
201
+ })], EFMedia.prototype, "fftDecay", void 0);
202
+ _decorate([property({
203
+ type: Number,
204
+ attribute: "fft-gain",
205
+ reflect: true
206
+ })], EFMedia.prototype, "fftGain", void 0);
207
+ _decorate([property({
208
+ type: Boolean,
209
+ attribute: "interpolate-frequencies",
210
+ reflect: true
211
+ })], EFMedia.prototype, "interpolateFrequencies", void 0);
212
+ _decorate([property({
213
+ type: String,
214
+ attribute: "asset-id",
215
+ reflect: true
216
+ })], EFMedia.prototype, "assetId", void 0);
217
+ _decorate([state()], EFMedia.prototype, "_desiredSeekTimeMs", void 0);
218
+ export { EFMedia, IgnorableError, deepGetMediaElements };