@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
@@ -47,7 +47,6 @@ describe("sourcein and sourceout", () => {
47
47
  const element = document.createElement("ten-seconds");
48
48
  element.sourceInMs = 5_000;
49
49
  element.sourceOutMs = 1_000;
50
- console.log(element.sourceInMs, element.sourceOutMs, element.durationMs);
51
50
  expect(element.durationMs).toBe(0);
52
51
  });
53
52
  });
@@ -1,11 +1,10 @@
1
1
  import { consume, createContext } from "@lit/context";
2
+ import { Task } from "@lit/task";
2
3
  import type { LitElement, PropertyValueMap, ReactiveController } from "lit";
3
4
  import { property, state } from "lit/decorators.js";
4
- import type { EFTimegroup } from "./EFTimegroup.js";
5
-
6
- import { Task } from "@lit/task";
7
5
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
8
6
  import { durationConverter } from "./durationConverter.js";
7
+ import type { EFTimegroup } from "./EFTimegroup.js";
9
8
 
10
9
  export const timegroupContext = createContext<EFTimegroup>(
11
10
  Symbol("timeGroupContext"),
@@ -292,6 +291,10 @@ const resetStartTimeMsCache = () => {
292
291
  };
293
292
  resetStartTimeMsCache();
294
293
 
294
+ export const flushStartTimeMsCache = () => {
295
+ startTimeMsCache = new WeakMap();
296
+ };
297
+
295
298
  export const EFTemporal = <T extends Constructor<LitElement>>(
296
299
  superClass: T,
297
300
  ) => {
@@ -536,12 +539,19 @@ export const EFTemporal = <T extends Constructor<LitElement>>(
536
539
  const ownIndex = siblingTemorals?.indexOf(
537
540
  this as InstanceType<Constructor<TemporalMixinInterface> & T>,
538
541
  );
542
+ if (ownIndex === -1) {
543
+ return 0;
544
+ }
539
545
  if (ownIndex === 0) {
540
546
  startTimeMsCache.set(this, parentTimegroup.startTimeMs);
541
547
  return parentTimegroup.startTimeMs;
542
548
  }
543
549
  const previous = siblingTemorals?.[(ownIndex ?? 0) - 1];
544
550
  if (!previous) {
551
+ console.error("Previous temporal element not found", {
552
+ ownIndex,
553
+ siblingTemorals,
554
+ });
545
555
  throw new Error("Previous temporal element not found");
546
556
  }
547
557
  startTimeMsCache.set(
@@ -1,8 +1,8 @@
1
1
  import {
2
- LitElement,
3
- type TemplateResult,
4
2
  html,
3
+ LitElement,
5
4
  render as litRender,
5
+ type TemplateResult,
6
6
  } from "lit";
7
7
  import { assert, beforeEach, describe, test } from "vitest";
8
8
  import { EFTimegroup } from "./EFTimegroup.js";
@@ -353,7 +353,7 @@ describe("setting currentTime", () => {
353
353
  document.body.appendChild(timegroup);
354
354
  assert.isNull(localStorage.getItem(timegroup.storageKey));
355
355
  timegroup.currentTime = 5_000;
356
- assert.equal(localStorage.getItem(timegroup.storageKey), "5000");
356
+ assert.equal(localStorage.getItem(timegroup.storageKey), "10"); // Clamped to duration
357
357
  timegroup.remove();
358
358
  });
359
359
 
@@ -392,6 +392,9 @@ describe("setting currentTime", () => {
392
392
  assert.equal(a.ownCurrentTimeMs, 2_500);
393
393
  assert.equal(b.ownCurrentTimeMs, 0);
394
394
 
395
+ // Wait for frame update to complete before next assignment
396
+ await new Promise((resolve) => setTimeout(resolve, 10));
397
+
395
398
  root.currentTimeMs = 7_500;
396
399
 
397
400
  assert.equal(a.ownCurrentTimeMs, 5_000);
@@ -1,19 +1,21 @@
1
1
  import { provide } from "@lit/context";
2
- import { Task } from "@lit/task";
2
+ import { Task, TaskStatus } from "@lit/task";
3
3
  import debug from "debug";
4
- import { LitElement, type PropertyValueMap, css, html } from "lit";
4
+ import { css, html, LitElement, type PropertyValueMap } from "lit";
5
5
  import { customElement, property } from "lit/decorators.js";
6
6
 
7
7
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
8
8
  import { isContextMixin } from "../gui/ContextMixin.js";
9
+ import { durationConverter } from "./durationConverter.js";
9
10
  import { deepGetMediaElements } from "./EFMedia.js";
10
11
  import {
12
+ deepGetElementsWithFrameTasks,
11
13
  EFTemporal,
14
+ flushStartTimeMsCache,
12
15
  shallowGetTemporalElements,
13
16
  timegroupContext,
14
17
  } from "./EFTemporal.js";
15
18
  import { TimegroupController } from "./TimegroupController.js";
16
- import { durationConverter } from "./durationConverter.js";
17
19
  import { updateAnimations } from "./updateAnimations.ts";
18
20
 
19
21
  const log = debug("ef:elements:EFTimegroup");
@@ -50,6 +52,10 @@ export class EFTimegroup extends EFTemporal(LitElement) {
50
52
 
51
53
  #currentTime = 0;
52
54
 
55
+ // Frame update locking mechanism (only for root timegroups)
56
+ private isFrameUpdateInProgress = false;
57
+ private queuedTimeUpdate: number | null = null;
58
+
53
59
  @property({
54
60
  type: String,
55
61
  attribute: "mode",
@@ -70,27 +76,84 @@ export class EFTimegroup extends EFTemporal(LitElement) {
70
76
 
71
77
  @property({ type: Number, attribute: "currenttime" })
72
78
  set currentTime(time: number) {
73
- this.#currentTime = Math.max(0, Math.min(time, this.durationMs / 1000));
74
- try {
75
- if (this.id) {
76
- if (this.isConnected) {
77
- localStorage.setItem(this.storageKey, time.toString());
78
- }
79
- }
80
- } catch (error) {
81
- log("Failed to save time to localStorage", error);
79
+ const newTime = Math.max(0, Math.min(time, this.durationMs / 1000));
80
+
81
+ // Only apply locking mechanism for root timegroups to prevent cascade overload
82
+ if (this.isRootTimegroup && this.isFrameUpdateInProgress) {
83
+ // Queue the latest time update - only keep the most recent
84
+ this.queuedTimeUpdate = newTime;
85
+ return;
86
+ }
87
+
88
+ if (this.isRootTimegroup) {
89
+ this.#executeTimeUpdate(newTime);
90
+ } else {
91
+ // Non-root timegroups update immediately (no cascade risk)
92
+ this.#currentTime = newTime;
93
+ this.#saveTimeToLocalStorage(newTime);
82
94
  }
83
95
  }
96
+
84
97
  get currentTime() {
85
98
  return this.#currentTime;
86
99
  }
100
+
87
101
  get currentTimeMs() {
88
102
  return this.currentTime * 1000;
89
103
  }
104
+
90
105
  set currentTimeMs(ms: number) {
91
106
  this.currentTime = ms / 1000;
92
107
  }
93
108
 
109
+ /**
110
+ * Determines if this is a root timegroup (no parent timegroups)
111
+ */
112
+ get isRootTimegroup(): boolean {
113
+ return this.closest("ef-timegroup") === this;
114
+ }
115
+
116
+ /**
117
+ * Executes time update with frame locking for root timegroups
118
+ */
119
+ async #executeTimeUpdate(time: number) {
120
+ this.isFrameUpdateInProgress = true;
121
+ this.#currentTime = time;
122
+
123
+ try {
124
+ // Save to localStorage
125
+ this.#saveTimeToLocalStorage(time);
126
+
127
+ // Wait for any pending frame tasks to complete before allowing next update
128
+ await this.waitForFrameTasks();
129
+ } catch (error) {
130
+ console.error("⚠️ [TIME_UPDATE_ERROR] Error during frame update:", error);
131
+ } finally {
132
+ this.isFrameUpdateInProgress = false;
133
+
134
+ // Process queued update if any (ensures latest scrub position is processed)
135
+ if (this.queuedTimeUpdate !== null && this.queuedTimeUpdate !== time) {
136
+ const nextTime = this.queuedTimeUpdate;
137
+ this.queuedTimeUpdate = null;
138
+ // Schedule on next tick to avoid recursive call stack
139
+ setTimeout(() => this.#executeTimeUpdate(nextTime), 0);
140
+ }
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Saves time to localStorage (extracted for reuse)
146
+ */
147
+ #saveTimeToLocalStorage(time: number) {
148
+ try {
149
+ if (this.id && this.isConnected) {
150
+ localStorage.setItem(this.storageKey, time.toString());
151
+ }
152
+ } catch (error) {
153
+ log("Failed to save time to localStorage", error);
154
+ }
155
+ }
156
+
94
157
  render() {
95
158
  return html`<slot></slot> `;
96
159
  }
@@ -110,7 +173,7 @@ export class EFTimegroup extends EFTemporal(LitElement) {
110
173
  super.connectedCallback();
111
174
  if (this.id) {
112
175
  this.waitForMediaDurations().then(() => {
113
- this.#currentTime = this.maybeLoadTimeFromLocalStorage();
176
+ this.currentTime = this.maybeLoadTimeFromLocalStorage();
114
177
  });
115
178
  }
116
179
 
@@ -197,6 +260,30 @@ export class EFTimegroup extends EFTemporal(LitElement) {
197
260
  }
198
261
  }
199
262
 
263
+ async getPendingFrameTasks() {
264
+ await this.updateComplete;
265
+ const temporals = deepGetElementsWithFrameTasks(this);
266
+ return temporals
267
+ .map((temporal) => temporal.frameTask)
268
+ .filter((task) => task.status < TaskStatus.COMPLETE);
269
+ }
270
+
271
+ async waitForFrameTasks() {
272
+ const limit = 10;
273
+ let step = 0;
274
+ await this.updateComplete;
275
+ while (step < limit) {
276
+ step++;
277
+ let pendingTasks = await this.getPendingFrameTasks();
278
+ await Promise.all(pendingTasks.map((task) => task.taskComplete));
279
+ await this.updateComplete;
280
+ pendingTasks = await this.getPendingFrameTasks();
281
+ if (pendingTasks.length === 0) {
282
+ break;
283
+ }
284
+ }
285
+ }
286
+
200
287
  /**
201
288
  * Wait for all media elements to load their initial segments.
202
289
  * Ideally we would only need the extracted index json data, but
@@ -204,10 +291,30 @@ export class EFTimegroup extends EFTemporal(LitElement) {
204
291
  * in calculations and it was not clear why.
205
292
  */
206
293
  async waitForMediaDurations() {
294
+ // We must await updateComplete to ensure all media elements inside this are connected
295
+ // and will match deepGetMediaElements
296
+ await this.updateComplete;
207
297
  const mediaElements = deepGetMediaElements(this);
208
- return await Promise.all(
209
- mediaElements.map((m) => m.trackFragmentIndexLoader.taskComplete),
210
- );
298
+ // Then, we must await the fragmentIndexTask to ensure all media elements have their
299
+ // fragment index loaded, which is where their duration is parsed from.
300
+ await Promise.all(mediaElements.map((m) => m.mediaEngineTask.taskComplete));
301
+
302
+ // After waiting for durations, we must force some updates to cascade and ensure all temporal elements
303
+ // have correct durations and start times. It is not ideal that we have to do this inside here,
304
+ // but it is the best current way to ensure that all temporal elements have correct durations and start times.
305
+
306
+ // Next, we must flush the startTimeMs cache to ensure all media elements have their
307
+ // startTimeMs parsed fresh, otherwise the startTimeMs is cached per animation frame.
308
+ flushStartTimeMsCache();
309
+
310
+ // Request an update to the currentTime of this group, ensuring that time updates will cascade
311
+ // down to children, forcing sequence groups to arrange correctly.
312
+ // This also makes the filmstrip update correctly.
313
+ this.requestUpdate("currentTime");
314
+ // Finally, we must await updateComplete to ensure all temporal elements have their
315
+ // currentTime updated and all animations have run.
316
+
317
+ await this.updateComplete;
211
318
  }
212
319
 
213
320
  get childTemporals() {
@@ -290,16 +397,40 @@ export class EFTimegroup extends EFTemporal(LitElement) {
290
397
  ) {
291
398
  await this.waitForMediaDurations();
292
399
 
400
+ // Create AbortController for audio fetch operations
401
+ const abortController = new AbortController();
402
+
293
403
  await Promise.all(
294
404
  deepGetMediaElements(this).map(async (mediaElement) => {
405
+ // Skip muted elements entirely - no audio fetching or processing needed
406
+ if (mediaElement.mute) {
407
+ return;
408
+ }
409
+
295
410
  const mediaStartsBeforeEnd = mediaElement.startTimeMs <= toMs;
296
411
  const mediaEndsAfterStart = mediaElement.endTimeMs >= fromMs;
297
412
  const mediaOverlaps = mediaStartsBeforeEnd && mediaEndsAfterStart;
298
- if (!mediaOverlaps || mediaElement.defaultAudioTrackId === undefined) {
413
+ if (!mediaOverlaps) {
299
414
  return;
300
415
  }
301
416
 
302
- const audio = await mediaElement.fetchAudioSpanningTime(fromMs, toMs);
417
+ // Convert from root timegroup timeline to media element's local timeline
418
+ const mediaLocalFromMs = Math.max(0, fromMs - mediaElement.startTimeMs);
419
+ const mediaLocalToMs = Math.min(
420
+ mediaElement.endTimeMs - mediaElement.startTimeMs,
421
+ toMs - mediaElement.startTimeMs,
422
+ );
423
+
424
+ // Skip if no valid local time range
425
+ if (mediaLocalFromMs >= mediaLocalToMs) {
426
+ return;
427
+ }
428
+
429
+ const audio = await mediaElement.fetchAudioSpanningTime(
430
+ mediaLocalFromMs, // ✅ Now using media element's local timeline
431
+ mediaLocalToMs, // ✅ Now using media element's local timeline
432
+ abortController.signal,
433
+ );
303
434
  if (!audio) {
304
435
  throw new Error("Failed to fetch audio");
305
436
  }
@@ -310,16 +441,25 @@ export class EFTimegroup extends EFTemporal(LitElement) {
310
441
  );
311
442
  bufferSource.connect(audioContext.destination);
312
443
 
444
+ // Calculate timing for placing this audio in the output context
313
445
  const ctxStartMs = Math.max(0, mediaElement.startTimeMs - fromMs);
314
446
  const ctxEndMs = mediaElement.endTimeMs - fromMs;
315
447
  const ctxDurationMs = ctxEndMs - ctxStartMs;
316
448
 
317
- const offset =
318
- Math.max(0, fromMs - mediaElement.startTimeMs) - audio.startMs;
449
+ // Calculate offset within the fetched audio buffer
450
+ // Since we now use local timeline coordinates, audio.startMs is relative to media start
451
+ const requestedOffsetInMedia = mediaLocalFromMs; // Already in local timeline
452
+ const actualOffsetInBuffer = requestedOffsetInMedia - audio.startMs; // Both in local timeline
453
+
454
+ // Ensure offset is never negative (this would cause audio scheduling errors)
455
+ const safeOffset = Math.max(0, actualOffsetInBuffer);
456
+
457
+ if (safeOffset !== actualOffsetInBuffer) {
458
+ }
319
459
 
320
460
  bufferSource.start(
321
461
  ctxStartMs / 1000,
322
- offset / 1000,
462
+ safeOffset / 1000,
323
463
  ctxDurationMs / 1000,
324
464
  );
325
465
  }),
@@ -327,14 +467,68 @@ export class EFTimegroup extends EFTemporal(LitElement) {
327
467
  }
328
468
 
329
469
  async renderAudio(fromMs: number, toMs: number) {
470
+ // Here we determine the number of samples we need to render rather than the duration.
471
+ // We cannot tolerate having more or fewer samples than fit exactlly into AAC frames.
330
472
  const durationMs = toMs - fromMs;
331
- const audioContext = new OfflineAudioContext(
332
- 2,
333
- Math.round((48000 * durationMs) / 1000),
334
- 48000,
335
- );
473
+ const duration = durationMs / 1000;
474
+ const exactSamples = 48000 * duration;
475
+ const aacFrames = exactSamples / 1024;
476
+ const alignedFrames = Math.round(aacFrames);
477
+ const contextSize = alignedFrames * 1024; // AAC-aligned sample count
478
+
479
+ // Debug logging for audio duration calculations
480
+ if (contextSize <= 0) {
481
+ throw new Error(
482
+ `Duration must be greater than 0 when rendering audio. ${contextSize}ms`,
483
+ );
484
+ }
485
+
486
+ let audioContext: OfflineAudioContext;
487
+ try {
488
+ audioContext = new OfflineAudioContext(2, contextSize, 48000);
489
+ } catch (error) {
490
+ throw new Error(
491
+ `[EFTimegroup.renderAudio] Failed to create OfflineAudioContext(2, ${contextSize}, 48000) for renderAudio(${fromMs}, ${toMs}) with contextSize=${contextSize}: ${error instanceof Error ? error.message : String(error)}. This typically happens when audio parameters are invalid (e.g., contextSize <= 0).`,
492
+ );
493
+ }
494
+
336
495
  await this.#addAudioToContext(audioContext, fromMs, toMs);
337
- return await audioContext.startRendering();
496
+ const renderedBuffer = await audioContext.startRendering();
497
+
498
+ return renderedBuffer;
499
+ }
500
+
501
+ /**
502
+ * TEMPORARY TEST METHOD: Renders audio and immediately plays it back
503
+ * Usage: timegroup.testPlayAudio(0, 5000) // Play first 5 seconds
504
+ */
505
+ async testPlayAudio(fromMs: number, toMs: number) {
506
+ try {
507
+ // Render the audio using the existing renderAudio method
508
+ const renderedBuffer = await this.renderAudio(fromMs, toMs);
509
+
510
+ // Create a regular AudioContext for playback
511
+ const playbackContext = new AudioContext();
512
+
513
+ // Create a buffer source and connect it
514
+ const bufferSource = playbackContext.createBufferSource();
515
+ bufferSource.buffer = renderedBuffer;
516
+ bufferSource.connect(playbackContext.destination);
517
+
518
+ // Start playback immediately
519
+ bufferSource.start(0);
520
+
521
+ // Return a promise that resolves when playback ends
522
+ return new Promise<void>((resolve) => {
523
+ bufferSource.onended = () => {
524
+ playbackContext.close();
525
+ resolve();
526
+ };
527
+ });
528
+ } catch (error) {
529
+ console.error("🎵 [TEST_PLAY_AUDIO] Error:", error);
530
+ throw error;
531
+ }
338
532
  }
339
533
 
340
534
  async loadMd5Sums() {