@editframe/elements 0.17.6-beta.0 → 0.18.7-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 (211) hide show
  1. package/dist/EF_FRAMEGEN.js +1 -1
  2. package/dist/elements/EFAudio.d.ts +21 -2
  3. package/dist/elements/EFAudio.js +41 -11
  4. package/dist/elements/EFImage.d.ts +1 -0
  5. package/dist/elements/EFImage.js +11 -3
  6. package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +18 -0
  7. package/dist/elements/EFMedia/AssetIdMediaEngine.js +41 -0
  8. package/dist/elements/EFMedia/AssetMediaEngine.browsertest.d.ts +0 -0
  9. package/dist/elements/EFMedia/AssetMediaEngine.d.ts +45 -0
  10. package/dist/elements/EFMedia/AssetMediaEngine.js +135 -0
  11. package/dist/elements/EFMedia/BaseMediaEngine.d.ts +55 -0
  12. package/dist/elements/EFMedia/BaseMediaEngine.js +115 -0
  13. package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +43 -0
  14. package/dist/elements/EFMedia/BufferedSeekingInput.js +179 -0
  15. package/dist/elements/EFMedia/JitMediaEngine.browsertest.d.ts +0 -0
  16. package/dist/elements/EFMedia/JitMediaEngine.d.ts +31 -0
  17. package/dist/elements/EFMedia/JitMediaEngine.js +81 -0
  18. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.d.ts +9 -0
  19. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +16 -0
  20. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +48 -0
  21. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.d.ts +3 -0
  22. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +141 -0
  23. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.d.ts +9 -0
  24. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.d.ts +4 -0
  25. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +16 -0
  26. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.d.ts +9 -0
  27. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.d.ts +3 -0
  28. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +30 -0
  29. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.d.ts +0 -0
  30. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.d.ts +7 -0
  31. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +32 -0
  32. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +4 -0
  33. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +28 -0
  34. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.d.ts +4 -0
  35. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +17 -0
  36. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.d.ts +3 -0
  37. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +107 -0
  38. package/dist/elements/EFMedia/shared/AudioSpanUtils.d.ts +7 -0
  39. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +54 -0
  40. package/dist/elements/EFMedia/shared/BufferUtils.d.ts +70 -0
  41. package/dist/elements/EFMedia/shared/BufferUtils.js +89 -0
  42. package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +23 -0
  43. package/dist/elements/EFMedia/shared/PrecisionUtils.d.ts +28 -0
  44. package/dist/elements/EFMedia/shared/PrecisionUtils.js +29 -0
  45. package/dist/elements/EFMedia/shared/RenditionHelpers.d.ts +19 -0
  46. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.d.ts +18 -0
  47. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +60 -0
  48. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.d.ts +9 -0
  49. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +16 -0
  50. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +46 -0
  51. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.d.ts +9 -0
  52. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.d.ts +4 -0
  53. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.js +16 -0
  54. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.d.ts +9 -0
  55. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.d.ts +3 -0
  56. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.js +27 -0
  57. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.d.ts +7 -0
  58. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +34 -0
  59. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.d.ts +9 -0
  60. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.d.ts +4 -0
  61. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +28 -0
  62. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.d.ts +9 -0
  63. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.d.ts +4 -0
  64. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.js +17 -0
  65. package/dist/elements/EFMedia.browsertest.d.ts +1 -0
  66. package/dist/elements/EFMedia.d.ts +63 -111
  67. package/dist/elements/EFMedia.js +117 -1113
  68. package/dist/elements/EFTemporal.d.ts +1 -1
  69. package/dist/elements/EFTemporal.js +1 -1
  70. package/dist/elements/EFTimegroup.d.ts +11 -0
  71. package/dist/elements/EFTimegroup.js +83 -13
  72. package/dist/elements/EFVideo.d.ts +54 -32
  73. package/dist/elements/EFVideo.js +100 -207
  74. package/dist/elements/EFWaveform.js +2 -2
  75. package/dist/elements/SampleBuffer.d.ts +14 -0
  76. package/dist/elements/SampleBuffer.js +52 -0
  77. package/dist/getRenderInfo.js +2 -1
  78. package/dist/gui/ContextMixin.js +3 -2
  79. package/dist/gui/EFFilmstrip.d.ts +3 -3
  80. package/dist/gui/EFFilmstrip.js +1 -1
  81. package/dist/gui/EFFitScale.d.ts +2 -2
  82. package/dist/gui/TWMixin.js +1 -1
  83. package/dist/style.css +1 -1
  84. package/dist/transcoding/cache/CacheManager.d.ts +73 -0
  85. package/dist/transcoding/cache/RequestDeduplicator.d.ts +29 -0
  86. package/dist/transcoding/cache/RequestDeduplicator.js +53 -0
  87. package/dist/transcoding/cache/RequestDeduplicator.test.d.ts +1 -0
  88. package/dist/transcoding/types/index.d.ts +242 -0
  89. package/dist/transcoding/utils/MediaUtils.d.ts +9 -0
  90. package/dist/transcoding/utils/UrlGenerator.d.ts +26 -0
  91. package/dist/transcoding/utils/UrlGenerator.js +45 -0
  92. package/dist/transcoding/utils/constants.d.ts +27 -0
  93. package/dist/utils/LRUCache.d.ts +34 -0
  94. package/dist/utils/LRUCache.js +115 -0
  95. package/package.json +3 -3
  96. package/src/elements/EFAudio.browsertest.ts +189 -49
  97. package/src/elements/EFAudio.ts +59 -13
  98. package/src/elements/EFImage.browsertest.ts +42 -0
  99. package/src/elements/EFImage.ts +23 -3
  100. package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +222 -0
  101. package/src/elements/EFMedia/AssetIdMediaEngine.ts +70 -0
  102. package/src/elements/EFMedia/AssetMediaEngine.browsertest.ts +100 -0
  103. package/src/elements/EFMedia/AssetMediaEngine.ts +255 -0
  104. package/src/elements/EFMedia/BaseMediaEngine.test.ts +164 -0
  105. package/src/elements/EFMedia/BaseMediaEngine.ts +219 -0
  106. package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +481 -0
  107. package/src/elements/EFMedia/BufferedSeekingInput.ts +324 -0
  108. package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +165 -0
  109. package/src/elements/EFMedia/JitMediaEngine.ts +166 -0
  110. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +554 -0
  111. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +81 -0
  112. package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +250 -0
  113. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +59 -0
  114. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +23 -0
  115. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +55 -0
  116. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +43 -0
  117. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +199 -0
  118. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +64 -0
  119. package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +45 -0
  120. package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +24 -0
  121. package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +183 -0
  122. package/src/elements/EFMedia/shared/AudioSpanUtils.ts +128 -0
  123. package/src/elements/EFMedia/shared/BufferUtils.ts +310 -0
  124. package/src/elements/EFMedia/shared/MediaTaskUtils.ts +44 -0
  125. package/src/elements/EFMedia/shared/PrecisionUtils.ts +46 -0
  126. package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +247 -0
  127. package/src/elements/EFMedia/shared/RenditionHelpers.ts +79 -0
  128. package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +128 -0
  129. package/src/elements/EFMedia/tasks/makeMediaEngineTask.test.ts +233 -0
  130. package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +89 -0
  131. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.ts +555 -0
  132. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +79 -0
  133. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.ts +59 -0
  134. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts +23 -0
  135. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.ts +55 -0
  136. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.ts +45 -0
  137. package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +68 -0
  138. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.ts +57 -0
  139. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +43 -0
  140. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.ts +56 -0
  141. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.ts +24 -0
  142. package/src/elements/EFMedia.browsertest.ts +706 -273
  143. package/src/elements/EFMedia.ts +136 -1769
  144. package/src/elements/EFTemporal.ts +3 -4
  145. package/src/elements/EFTimegroup.browsertest.ts +6 -3
  146. package/src/elements/EFTimegroup.ts +147 -21
  147. package/src/elements/EFVideo.browsertest.ts +980 -169
  148. package/src/elements/EFVideo.ts +113 -458
  149. package/src/elements/EFWaveform.ts +1 -1
  150. package/src/elements/MediaController.ts +2 -12
  151. package/src/elements/SampleBuffer.ts +95 -0
  152. package/src/gui/ContextMixin.ts +3 -6
  153. package/src/transcoding/cache/CacheManager.ts +208 -0
  154. package/src/transcoding/cache/RequestDeduplicator.test.ts +170 -0
  155. package/src/transcoding/cache/RequestDeduplicator.ts +65 -0
  156. package/src/transcoding/types/index.ts +269 -0
  157. package/src/transcoding/utils/MediaUtils.ts +63 -0
  158. package/src/transcoding/utils/UrlGenerator.ts +68 -0
  159. package/src/transcoding/utils/constants.ts +36 -0
  160. package/src/utils/LRUCache.ts +153 -0
  161. package/test/EFVideo.framegen.browsertest.ts +39 -30
  162. 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
  163. 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
  164. package/test/__cache__/GET__api_v1_transcode_audio_1_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__9ed2d25c675aa6bb6ff5b3ae23887c71/data.bin +0 -0
  165. package/test/__cache__/GET__api_v1_transcode_audio_1_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__9ed2d25c675aa6bb6ff5b3ae23887c71/metadata.json +22 -0
  166. 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
  167. 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
  168. package/test/__cache__/GET__api_v1_transcode_audio_2_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__d5a3309a2bf756dd6e304807eb402f56/data.bin +0 -0
  169. package/test/__cache__/GET__api_v1_transcode_audio_2_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__d5a3309a2bf756dd6e304807eb402f56/metadata.json +22 -0
  170. 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
  171. 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
  172. package/test/__cache__/GET__api_v1_transcode_audio_3_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__773254bb671e3466fca8677139fb239e/data.bin +0 -0
  173. package/test/__cache__/GET__api_v1_transcode_audio_3_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__773254bb671e3466fca8677139fb239e/metadata.json +22 -0
  174. 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
  175. 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
  176. 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
  177. 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
  178. 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
  179. 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
  180. 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
  181. 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
  182. 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
  183. 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
  184. 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
  185. 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
  186. package/test/__cache__/GET__api_v1_transcode_high_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a6fb05a22b18d850f7f2950bbcdbdeed/data.bin +0 -0
  187. package/test/__cache__/GET__api_v1_transcode_high_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a6fb05a22b18d850f7f2950bbcdbdeed/metadata.json +21 -0
  188. package/test/__cache__/GET__api_v1_transcode_high_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a50058c7c3602e90879fe3428ed891f4/data.bin +0 -0
  189. package/test/__cache__/GET__api_v1_transcode_high_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a50058c7c3602e90879fe3428ed891f4/metadata.json +21 -0
  190. 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
  191. 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
  192. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -0
  193. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +19 -0
  194. package/test/createJitTestClips.ts +320 -188
  195. package/test/recordReplayProxyPlugin.js +352 -0
  196. package/test/useAssetMSW.ts +1 -1
  197. package/test/useMSW.ts +35 -22
  198. package/types.json +1 -1
  199. package/dist/JitTranscodingClient.d.ts +0 -167
  200. package/dist/JitTranscodingClient.js +0 -373
  201. package/dist/ScrubTrackManager.d.ts +0 -96
  202. package/dist/ScrubTrackManager.js +0 -216
  203. package/dist/elements/printTaskStatus.js +0 -11
  204. package/src/elements/__screenshots__/EFMedia.browsertest.ts/EFMedia-JIT-audio-playback-audioBufferTask-should-work-in-JIT-mode-without-URL-errors-1.png +0 -0
  205. package/test/EFVideo.frame-tasks.browsertest.ts +0 -524
  206. /package/dist/{DecoderResetFrequency.test.d.ts → elements/EFMedia/AssetIdMediaEngine.test.d.ts} +0 -0
  207. /package/dist/{DecoderResetRecovery.test.d.ts → elements/EFMedia/BaseMediaEngine.test.d.ts} +0 -0
  208. /package/dist/{JitTranscodingClient.browsertest.d.ts → elements/EFMedia/BufferedSeekingInput.browsertest.d.ts} +0 -0
  209. /package/dist/{JitTranscodingClient.test.d.ts → elements/EFMedia/shared/RenditionHelpers.browsertest.d.ts} +0 -0
  210. /package/dist/{ScrubTrackIntegration.test.d.ts → elements/EFMedia/tasks/makeMediaEngineTask.browsertest.d.ts} +0 -0
  211. /package/dist/{SegmentSwitchLoading.test.d.ts → elements/EFMedia/tasks/makeMediaEngineTask.test.d.ts} +0 -0
@@ -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"),
@@ -549,7 +548,7 @@ export const EFTemporal = <T extends Constructor<LitElement>>(
549
548
  }
550
549
  const previous = siblingTemorals?.[(ownIndex ?? 0) - 1];
551
550
  if (!previous) {
552
- console.log("Previous temporal element not found", {
551
+ console.error("Previous temporal element not found", {
553
552
  ownIndex,
554
553
  siblingTemorals,
555
554
  });
@@ -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,21 +1,21 @@
1
1
  import { provide } from "@lit/context";
2
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 {
11
- EFTemporal,
12
12
  deepGetElementsWithFrameTasks,
13
+ EFTemporal,
13
14
  flushStartTimeMsCache,
14
15
  shallowGetTemporalElements,
15
16
  timegroupContext,
16
17
  } from "./EFTemporal.js";
17
18
  import { TimegroupController } from "./TimegroupController.js";
18
- import { durationConverter } from "./durationConverter.js";
19
19
  import { updateAnimations } from "./updateAnimations.ts";
20
20
 
21
21
  const log = debug("ef:elements:EFTimegroup");
@@ -52,6 +52,10 @@ export class EFTimegroup extends EFTemporal(LitElement) {
52
52
 
53
53
  #currentTime = 0;
54
54
 
55
+ // Frame update locking mechanism (only for root timegroups)
56
+ private isFrameUpdateInProgress = false;
57
+ private queuedTimeUpdate: number | null = null;
58
+
55
59
  @property({
56
60
  type: String,
57
61
  attribute: "mode",
@@ -72,27 +76,84 @@ export class EFTimegroup extends EFTemporal(LitElement) {
72
76
 
73
77
  @property({ type: Number, attribute: "currenttime" })
74
78
  set currentTime(time: number) {
75
- this.#currentTime = Math.max(0, Math.min(time, this.durationMs / 1000));
76
- try {
77
- if (this.id) {
78
- if (this.isConnected) {
79
- localStorage.setItem(this.storageKey, time.toString());
80
- }
81
- }
82
- } catch (error) {
83
- 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);
84
94
  }
85
95
  }
96
+
86
97
  get currentTime() {
87
98
  return this.#currentTime;
88
99
  }
100
+
89
101
  get currentTimeMs() {
90
102
  return this.currentTime * 1000;
91
103
  }
104
+
92
105
  set currentTimeMs(ms: number) {
93
106
  this.currentTime = ms / 1000;
94
107
  }
95
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
+
96
157
  render() {
97
158
  return html`<slot></slot> `;
98
159
  }
@@ -236,9 +297,7 @@ export class EFTimegroup extends EFTemporal(LitElement) {
236
297
  const mediaElements = deepGetMediaElements(this);
237
298
  // Then, we must await the fragmentIndexTask to ensure all media elements have their
238
299
  // fragment index loaded, which is where their duration is parsed from.
239
- await Promise.all(
240
- mediaElements.map((m) => m.fragmentIndexTask.taskComplete),
241
- );
300
+ await Promise.all(mediaElements.map((m) => m.mediaEngineTask.taskComplete));
242
301
 
243
302
  // After waiting for durations, we must force some updates to cascade and ensure all temporal elements
244
303
  // have correct durations and start times. It is not ideal that we have to do this inside here,
@@ -338,16 +397,40 @@ export class EFTimegroup extends EFTemporal(LitElement) {
338
397
  ) {
339
398
  await this.waitForMediaDurations();
340
399
 
400
+ // Create AbortController for audio fetch operations
401
+ const abortController = new AbortController();
402
+
341
403
  await Promise.all(
342
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
+
343
410
  const mediaStartsBeforeEnd = mediaElement.startTimeMs <= toMs;
344
411
  const mediaEndsAfterStart = mediaElement.endTimeMs >= fromMs;
345
412
  const mediaOverlaps = mediaStartsBeforeEnd && mediaEndsAfterStart;
346
- if (!mediaOverlaps || mediaElement.defaultAudioTrackId === undefined) {
413
+ if (!mediaOverlaps) {
414
+ return;
415
+ }
416
+
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) {
347
426
  return;
348
427
  }
349
428
 
350
- const audio = await mediaElement.fetchAudioSpanningTime(fromMs, toMs);
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
+ );
351
434
  if (!audio) {
352
435
  throw new Error("Failed to fetch audio");
353
436
  }
@@ -358,16 +441,25 @@ export class EFTimegroup extends EFTemporal(LitElement) {
358
441
  );
359
442
  bufferSource.connect(audioContext.destination);
360
443
 
444
+ // Calculate timing for placing this audio in the output context
361
445
  const ctxStartMs = Math.max(0, mediaElement.startTimeMs - fromMs);
362
446
  const ctxEndMs = mediaElement.endTimeMs - fromMs;
363
447
  const ctxDurationMs = ctxEndMs - ctxStartMs;
364
448
 
365
- const offset =
366
- 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
+ }
367
459
 
368
460
  bufferSource.start(
369
461
  ctxStartMs / 1000,
370
- offset / 1000,
462
+ safeOffset / 1000,
371
463
  ctxDurationMs / 1000,
372
464
  );
373
465
  }),
@@ -375,8 +467,14 @@ export class EFTimegroup extends EFTemporal(LitElement) {
375
467
  }
376
468
 
377
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.
378
472
  const durationMs = toMs - fromMs;
379
- const contextSize = Math.round((48000 * durationMs) / 1000);
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
380
478
 
381
479
  // Debug logging for audio duration calculations
382
480
  if (contextSize <= 0) {
@@ -400,6 +498,34 @@ export class EFTimegroup extends EFTemporal(LitElement) {
400
498
  return renderedBuffer;
401
499
  }
402
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
+ // Render the audio using the existing renderAudio method
507
+ const renderedBuffer = await this.renderAudio(fromMs, toMs);
508
+
509
+ // Create a regular AudioContext for playback
510
+ const playbackContext = new AudioContext();
511
+
512
+ // Create a buffer source and connect it
513
+ const bufferSource = playbackContext.createBufferSource();
514
+ bufferSource.buffer = renderedBuffer;
515
+ bufferSource.connect(playbackContext.destination);
516
+
517
+ // Start playback immediately
518
+ bufferSource.start(0);
519
+
520
+ // Return a promise that resolves when playback ends
521
+ return new Promise<void>((resolve) => {
522
+ bufferSource.onended = () => {
523
+ playbackContext.close();
524
+ resolve();
525
+ };
526
+ });
527
+ }
528
+
403
529
  async loadMd5Sums() {
404
530
  const efElements = this.efElements;
405
531
  const loaderTasks: Promise<any>[] = [];