@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
@@ -0,0 +1,64 @@
1
+ import { Task } from "@lit/task";
2
+ import type { VideoSample } from "mediabunny";
3
+ import { type EFMedia, IgnorableError } from "../../EFMedia";
4
+ import type { BufferedSeekingInput } from "../BufferedSeekingInput";
5
+
6
+ type AudioSeekTask = Task<
7
+ readonly [number, BufferedSeekingInput | undefined],
8
+ VideoSample | undefined
9
+ >;
10
+ export const makeAudioSeekTask = (host: EFMedia): AudioSeekTask => {
11
+ return new Task(host, {
12
+ args: () => [host.desiredSeekTimeMs, host.audioInputTask.value] as const,
13
+ onError: (error) => {
14
+ if (error instanceof IgnorableError) {
15
+ console.info("audioSeekTask aborted");
16
+ }
17
+ console.error("audioSeekTask error", error);
18
+ },
19
+ onComplete: (_value) => {},
20
+ task: async (
21
+ [targetSeekTimeMs],
22
+ { signal },
23
+ ): Promise<VideoSample | undefined> => {
24
+ // CRITICAL FIX: Use the targetSeekTimeMs from args, not host.desiredSeekTimeMs
25
+ // This ensures we use the same seek time that the segment loading tasks used
26
+
27
+ await host.audioSegmentIdTask.taskComplete;
28
+ signal.throwIfAborted(); // Abort if a new seek started
29
+ await host.audioSegmentFetchTask.taskComplete;
30
+ signal.throwIfAborted(); // Abort if a new seek started
31
+ await host.audioInitSegmentFetchTask.taskComplete;
32
+ signal.throwIfAborted(); // Abort if a new seek started
33
+
34
+ const audioInput = await host.audioInputTask.taskComplete;
35
+ signal.throwIfAborted(); // Abort if a new seek started
36
+ if (!audioInput) {
37
+ throw new Error("Audio input is not available");
38
+ }
39
+ const audioTrack = await audioInput.getFirstAudioTrack();
40
+ if (!audioTrack) {
41
+ throw new Error("Audio track is not available");
42
+ }
43
+ signal.throwIfAborted(); // Abort if a new seek started
44
+
45
+ const sample = (await audioInput.seek(
46
+ audioTrack.id,
47
+ targetSeekTimeMs, // Use the captured value, not host.desiredSeekTimeMs
48
+ )) as unknown as VideoSample | undefined;
49
+ signal.throwIfAborted(); // Abort if a new seek started
50
+
51
+ // If seek returned undefined, it was aborted - don't throw
52
+ if (sample === undefined && signal.aborted) {
53
+ return undefined;
54
+ }
55
+
56
+ // If we got undefined but weren't aborted, that's an actual error
57
+ if (sample === undefined) {
58
+ throw new Error("Audio seek failed to find sample");
59
+ }
60
+
61
+ return sample;
62
+ },
63
+ });
64
+ };
@@ -0,0 +1,45 @@
1
+ import { Task } from "@lit/task";
2
+ import type { MediaEngine } from "../../../transcoding/types";
3
+ import type { EFMedia } from "../../EFMedia";
4
+ import { getLatestMediaEngine } from "../tasks/makeMediaEngineTask";
5
+
6
+ export const makeAudioSegmentFetchTask = (
7
+ host: EFMedia,
8
+ ): Task<
9
+ readonly [MediaEngine | undefined, number | undefined],
10
+ ArrayBuffer
11
+ > => {
12
+ return new Task(host, {
13
+ args: () =>
14
+ [host.mediaEngineTask.value, host.audioSegmentIdTask.value] as const,
15
+ onError: (error) => {
16
+ console.error("audioSegmentFetchTask error", error);
17
+ },
18
+ onComplete: (_value) => {},
19
+ task: async (_, { signal }) => {
20
+ const mediaEngine = await getLatestMediaEngine(host, signal);
21
+ const segmentId = await host.audioSegmentIdTask.taskComplete;
22
+ if (segmentId === undefined) {
23
+ // Provide more context in the error to help with debugging
24
+ const rendition = mediaEngine.audioRendition;
25
+ const debugInfo = {
26
+ hasRendition: !!rendition,
27
+ segmentDurationMs: rendition?.segmentDurationMs,
28
+ segmentDurationsMs: rendition?.segmentDurationsMs?.length || 0,
29
+ desiredSeekTimeMs: host.desiredSeekTimeMs,
30
+ intrinsicDurationMs: host.intrinsicDurationMs,
31
+ };
32
+ throw new Error(
33
+ `Segment ID is not available for audio. Debug info: ${JSON.stringify(debugInfo)}`,
34
+ );
35
+ }
36
+
37
+ // SIMPLIFIED: Direct call to mediaEngine - deduplication is built-in
38
+ return mediaEngine.fetchMediaSegment(
39
+ segmentId,
40
+ mediaEngine.getAudioRendition(),
41
+ signal,
42
+ );
43
+ },
44
+ });
45
+ };
@@ -0,0 +1,24 @@
1
+ import { Task } from "@lit/task";
2
+ import type { MediaEngine } from "../../../transcoding/types";
3
+ import type { EFMedia } from "../../EFMedia";
4
+ import { getLatestMediaEngine } from "../tasks/makeMediaEngineTask";
5
+
6
+ export const makeAudioSegmentIdTask = (
7
+ host: EFMedia,
8
+ ): Task<readonly [MediaEngine | undefined, number], number | undefined> => {
9
+ return new Task(host, {
10
+ args: () => [host.mediaEngineTask.value, host.desiredSeekTimeMs] as const,
11
+ onError: (error) => {
12
+ console.error("audioSegmentIdTask error", error);
13
+ },
14
+ onComplete: (_value) => {},
15
+ task: async ([, targetSeekTimeMs], { signal }) => {
16
+ const mediaEngine = await getLatestMediaEngine(host, signal);
17
+ signal.throwIfAborted(); // Abort if a new seek started
18
+ return mediaEngine.computeSegmentId(
19
+ targetSeekTimeMs, // Use captured value, not host.desiredSeekTimeMs
20
+ mediaEngine.getAudioRendition(),
21
+ );
22
+ },
23
+ });
24
+ };
@@ -0,0 +1,183 @@
1
+ import { Task } from "@lit/task";
2
+
3
+ import { EF_INTERACTIVE } from "../../../EF_INTERACTIVE.js";
4
+ import { LRUCache } from "../../../utils/LRUCache.js";
5
+ import type { EFMedia } from "../../EFMedia.js";
6
+
7
+ // DECAY_WEIGHT constant - same as original
8
+ const DECAY_WEIGHT = 0.8;
9
+
10
+ export function makeAudioTimeDomainAnalysisTask(element: EFMedia) {
11
+ // Internal cache for this task instance (same as original #byteTimeDomainCache)
12
+ const cache = new LRUCache<string, Uint8Array>(1000);
13
+
14
+ return new Task(element, {
15
+ autoRun: EF_INTERACTIVE,
16
+ onError: (error) => {
17
+ console.error("byteTimeDomainTask error", error);
18
+ },
19
+ args: () =>
20
+ [
21
+ element.audioBufferTask.status,
22
+ element.currentSourceTimeMs,
23
+ element.fftSize,
24
+ element.fftDecay,
25
+ element.fftGain,
26
+ element.shouldInterpolateFrequencies,
27
+ ] as const,
28
+ task: async () => {
29
+ await element.audioBufferTask.taskComplete;
30
+ if (!element.audioBufferTask.value) return null;
31
+ if (element.currentSourceTimeMs < 0) return null;
32
+
33
+ const currentTimeMs = element.currentSourceTimeMs;
34
+
35
+ // ONLY CHANGE: Get real audio data for analysis (same technique as playback)
36
+ const analysisWindowMs = 5000; // Get 5 seconds for better analysis
37
+ const fromMs = Math.max(0, currentTimeMs);
38
+ // Clamp toMs to video duration to prevent requesting segments beyond available content
39
+ const maxToMs = fromMs + analysisWindowMs;
40
+ const videoDurationMs = element.intrinsicDurationMs || 0;
41
+ const toMs =
42
+ videoDurationMs > 0 ? Math.min(maxToMs, videoDurationMs) : maxToMs;
43
+
44
+ // If the clamping results in an invalid range (seeking beyond the end), skip analysis silently
45
+ if (fromMs >= toMs) {
46
+ return null;
47
+ }
48
+
49
+ const { fetchAudioSpanningTime: fetchAudioSpan } = await import(
50
+ "../shared/AudioSpanUtils.ts"
51
+ );
52
+ const audioSpan = await fetchAudioSpan(
53
+ element,
54
+ fromMs,
55
+ toMs,
56
+ new AbortController().signal,
57
+ );
58
+
59
+ if (!audioSpan || !audioSpan.blob) {
60
+ console.warn("Time domain analysis skipped: no audio data available");
61
+ return null;
62
+ }
63
+
64
+ // Decode the real audio data
65
+ const tempAudioContext = new OfflineAudioContext(2, 48000, 48000);
66
+ const arrayBuffer = await audioSpan.blob.arrayBuffer();
67
+ const audioBuffer = await tempAudioContext.decodeAudioData(arrayBuffer);
68
+
69
+ // Use actual startOffset from audioSpan (relative to requested time)
70
+ const startOffsetMs = audioSpan.startMs;
71
+
72
+ // ORIGINAL ALGORITHM FROM HERE - unchanged customer logic
73
+ const smoothedKey = `${element.shouldInterpolateFrequencies}:${element.fftSize}:${element.fftDecay}:${element.fftGain}:${startOffsetMs}:${currentTimeMs}`;
74
+ const cachedData = cache.get(smoothedKey);
75
+ if (cachedData) {
76
+ return cachedData;
77
+ }
78
+
79
+ // Process multiple frames with decay, similar to the reference code
80
+ const framesData = await Promise.all(
81
+ Array.from({ length: element.fftDecay }, async (_, frameIndex) => {
82
+ const frameOffset = frameIndex * (1000 / 30);
83
+ const startTime = Math.max(
84
+ 0,
85
+ (currentTimeMs - frameOffset - startOffsetMs) / 1000,
86
+ );
87
+
88
+ const cacheKey = `${element.shouldInterpolateFrequencies}:${element.fftSize}:${element.fftGain}:${startOffsetMs}:${startTime}`;
89
+ const cachedFrame = cache.get(cacheKey);
90
+ if (cachedFrame) {
91
+ return cachedFrame;
92
+ }
93
+
94
+ let audioContext: OfflineAudioContext;
95
+ try {
96
+ audioContext = new OfflineAudioContext(2, 48000 * (1 / 30), 48000);
97
+ } catch (error) {
98
+ throw new Error(
99
+ `[EFMedia.byteTimeDomainTask] Failed to create OfflineAudioContext(2, ${48000 * (1 / 30)}, 48000) for frame ${frameIndex} at time ${startTime}s: ${error instanceof Error ? error.message : String(error)}. This is for audio time domain analysis.`,
100
+ );
101
+ }
102
+
103
+ const source = audioContext.createBufferSource();
104
+ source.buffer = audioBuffer;
105
+
106
+ // Create analyzer for PCM data
107
+ const analyser = audioContext.createAnalyser();
108
+ analyser.fftSize = element.fftSize; // Ensure enough samples
109
+ analyser.minDecibels = -90;
110
+ analyser.maxDecibels = -20;
111
+
112
+ const gainNode = audioContext.createGain();
113
+ gainNode.gain.value = element.fftGain; // Amplify the signal
114
+
115
+ source.connect(gainNode);
116
+ gainNode.connect(analyser);
117
+ analyser.connect(audioContext.destination);
118
+
119
+ source.start(0, startTime, 1 / 30);
120
+
121
+ const dataLength = analyser.fftSize / 2;
122
+ try {
123
+ await audioContext.startRendering();
124
+ const frameData = new Uint8Array(dataLength);
125
+ analyser.getByteTimeDomainData(frameData);
126
+
127
+ // const points = frameData;
128
+ // Calculate RMS and midpoint values
129
+ const points = new Uint8Array(dataLength);
130
+ for (let i = 0; i < dataLength; i++) {
131
+ const pointSamples = frameData.slice(
132
+ i * (frameData.length / dataLength),
133
+ (i + 1) * (frameData.length / dataLength),
134
+ );
135
+
136
+ // Calculate RMS while preserving sign
137
+ const rms = Math.sqrt(
138
+ pointSamples.reduce((sum, sample) => {
139
+ const normalized = (sample - 128) / 128;
140
+ return sum + normalized * normalized;
141
+ }, 0) / pointSamples.length,
142
+ );
143
+
144
+ // Get average sign of the samples to determine direction
145
+ const avgSign = Math.sign(
146
+ pointSamples.reduce((sum, sample) => sum + (sample - 128), 0),
147
+ );
148
+
149
+ // Convert RMS back to byte range, preserving direction
150
+ points[i] = Math.min(255, Math.round(128 + avgSign * rms * 128));
151
+ }
152
+
153
+ cache.set(cacheKey, points);
154
+ return points;
155
+ } finally {
156
+ source.disconnect();
157
+ analyser.disconnect();
158
+ }
159
+ }),
160
+ );
161
+
162
+ // Combine frames with decay weighting
163
+ const frameLength = framesData[0]?.length ?? 0;
164
+ const smoothedData = new Uint8Array(frameLength);
165
+
166
+ for (let i = 0; i < frameLength; i++) {
167
+ let weightedSum = 0;
168
+ let weightSum = 0;
169
+
170
+ framesData.forEach((frame: Uint8Array, frameIndex: number) => {
171
+ const decayWeight = DECAY_WEIGHT ** frameIndex;
172
+ weightedSum += (frame[i] ?? 0) * decayWeight;
173
+ weightSum += decayWeight;
174
+ });
175
+
176
+ smoothedData[i] = Math.min(255, Math.round(weightedSum / weightSum));
177
+ }
178
+
179
+ cache.set(smoothedKey, smoothedData);
180
+ return smoothedData;
181
+ },
182
+ });
183
+ }
@@ -0,0 +1,128 @@
1
+ import type {
2
+ AudioSpan,
3
+ MediaEngine,
4
+ SegmentTimeRange,
5
+ } from "../../../transcoding/types";
6
+ import type { EFMedia } from "../../EFMedia";
7
+
8
+ /**
9
+ * Fetch audio segment data using MediaEngine
10
+ * Pure function with explicit dependencies
11
+ */
12
+ const fetchAudioSegmentData = async (
13
+ segmentIds: number[],
14
+ mediaEngine: MediaEngine,
15
+ signal: AbortSignal,
16
+ ): Promise<Map<number, ArrayBuffer>> => {
17
+ const audioRendition = mediaEngine.audioRendition;
18
+ if (!audioRendition) {
19
+ throw new Error("Audio rendition not available");
20
+ }
21
+
22
+ const segmentData = new Map<number, ArrayBuffer>();
23
+
24
+ // Fetch all segments - MediaEngine handles deduplication internally
25
+ const fetchPromises = segmentIds.map(async (segmentId) => {
26
+ const arrayBuffer = await mediaEngine.fetchMediaSegment(
27
+ segmentId,
28
+ audioRendition,
29
+ signal,
30
+ );
31
+ return [segmentId, arrayBuffer] as [number, ArrayBuffer];
32
+ });
33
+
34
+ const fetchedSegments = await Promise.all(fetchPromises);
35
+ signal.throwIfAborted();
36
+
37
+ for (const [segmentId, arrayBuffer] of fetchedSegments) {
38
+ segmentData.set(segmentId, arrayBuffer);
39
+ }
40
+
41
+ return segmentData;
42
+ };
43
+
44
+ /**
45
+ * Create audio span blob from init segment and media segments
46
+ * Pure function for blob creation
47
+ */
48
+ const createAudioSpanBlob = (
49
+ initSegment: ArrayBuffer,
50
+ mediaSegments: ArrayBuffer[],
51
+ ): Blob => {
52
+ const chunks = [initSegment, ...mediaSegments];
53
+ return new Blob(chunks, { type: "audio/mp4" });
54
+ };
55
+
56
+ /**
57
+ * Fetch audio spanning a time range
58
+ * Main function that orchestrates segment calculation, fetching, and blob creation
59
+ */
60
+ export const fetchAudioSpanningTime = async (
61
+ host: EFMedia,
62
+ fromMs: number,
63
+ toMs: number,
64
+ signal: AbortSignal,
65
+ ): Promise<AudioSpan> => {
66
+ // Validate inputs
67
+ if (fromMs >= toMs || fromMs < 0) {
68
+ throw new Error(`Invalid time range: fromMs=${fromMs}, toMs=${toMs}`);
69
+ }
70
+
71
+ // Get dependencies from host
72
+ const mediaEngine = await host.mediaEngineTask.taskComplete;
73
+ const initSegment = await host.audioInitSegmentFetchTask.taskComplete;
74
+
75
+ if (!mediaEngine?.audioRendition) {
76
+ throw new Error("Audio rendition not available");
77
+ }
78
+
79
+ if (!initSegment) {
80
+ throw new Error("Audio init segment is not available");
81
+ }
82
+
83
+ // Calculate segments needed using the media engine's method
84
+ const segmentRanges = mediaEngine.calculateAudioSegmentRange(
85
+ fromMs,
86
+ toMs,
87
+ mediaEngine.audioRendition,
88
+ host.intrinsicDurationMs || 10000,
89
+ );
90
+
91
+ if (segmentRanges.length === 0) {
92
+ throw new Error(`No segments found for time range ${fromMs}-${toMs}ms`);
93
+ }
94
+
95
+ // Fetch segment data
96
+ const segmentIds = segmentRanges.map((r: SegmentTimeRange) => r.segmentId);
97
+ const segmentData = await fetchAudioSegmentData(
98
+ segmentIds,
99
+ mediaEngine,
100
+ signal,
101
+ );
102
+
103
+ // Create ordered array of segments
104
+ const orderedSegments = segmentIds.map((id: number) => {
105
+ const segment = segmentData.get(id);
106
+ if (!segment) {
107
+ throw new Error(`Missing segment data for segment ID ${id}`);
108
+ }
109
+ return segment;
110
+ });
111
+
112
+ // Create blob
113
+ const blob = createAudioSpanBlob(initSegment, orderedSegments);
114
+
115
+ // Calculate actual time boundaries
116
+ const actualStartMs = Math.min(
117
+ ...segmentRanges.map((r: SegmentTimeRange) => r.startMs),
118
+ );
119
+ const actualEndMs = Math.max(
120
+ ...segmentRanges.map((r: SegmentTimeRange) => r.endMs),
121
+ );
122
+
123
+ return {
124
+ startMs: actualStartMs,
125
+ endMs: actualEndMs,
126
+ blob,
127
+ };
128
+ };