@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,5 +1,4 @@
1
1
  import type { ReactiveController, ReactiveControllerHost } from "lit";
2
- import { JitTranscodingClient } from "../JitTranscodingClient.ts";
3
2
 
4
3
  export class MediaController implements ReactiveController {
5
4
  #src: string | null = null;
@@ -29,10 +28,6 @@ export class MediaController implements ReactiveController {
29
28
  return "asset";
30
29
  }
31
30
 
32
- if (JitTranscodingClient.isJitTranscodeEligible(this.host.src)) {
33
- return "jit-transcode";
34
- }
35
-
36
31
  return "asset";
37
32
  }
38
33
 
@@ -84,7 +79,6 @@ export class MediaController implements ReactiveController {
84
79
 
85
80
  handleUpdate(changes: Map<string, { oldValue: any; newValue: any }>) {
86
81
  if (changes.has("src") || changes.has("assetId") || changes.has("mode")) {
87
- console.log("SRC/ASSETID/MODE changed");
88
82
  }
89
83
  }
90
84
 
@@ -98,11 +92,7 @@ export class MediaController implements ReactiveController {
98
92
  this.assetId = this.host.assetId;
99
93
  }
100
94
 
101
- hostDisconnected() {
102
- console.log("hostDisconnected");
103
- }
95
+ hostDisconnected() {}
104
96
 
105
- updated() {
106
- console.log("updated");
107
- }
97
+ updated() {}
108
98
  }
@@ -0,0 +1,95 @@
1
+ import type { AudioSample, VideoSample } from "mediabunny";
2
+ import { roundToMilliseconds } from "./EFMedia/shared/PrecisionUtils";
3
+ export type MediaSample = VideoSample | AudioSample;
4
+
5
+ // Generic sample buffer that works with both VideoSample and AudioSample
6
+ export class SampleBuffer {
7
+ private buffer: MediaSample[] = [];
8
+ private bufferSize: number;
9
+
10
+ constructor(bufferSize = 10) {
11
+ this.bufferSize = bufferSize;
12
+ }
13
+
14
+ push(sample: MediaSample) {
15
+ // Defensive copy to avoid concurrent modification during iteration
16
+ const currentBuffer = [...this.buffer];
17
+ currentBuffer.push(sample);
18
+
19
+ if (currentBuffer.length > this.bufferSize) {
20
+ const shifted = currentBuffer.shift();
21
+ if (shifted) {
22
+ try {
23
+ shifted.close();
24
+ } catch (_error) {
25
+ // Sample already closed, continue
26
+ }
27
+ }
28
+ }
29
+
30
+ // Update buffer atomically
31
+ this.buffer = currentBuffer;
32
+ }
33
+
34
+ clear() {
35
+ // Get current buffer and clear atomically
36
+ const toClose = this.buffer;
37
+ this.buffer = [];
38
+
39
+ // Close samples after clearing to avoid holding references
40
+ for (const sample of toClose) {
41
+ try {
42
+ sample.close();
43
+ } catch (_error) {
44
+ // Sample already closed, continue
45
+ }
46
+ }
47
+ }
48
+
49
+ peek(): MediaSample | undefined {
50
+ // Defensive read - get current buffer state
51
+ const currentBuffer = this.buffer;
52
+ return currentBuffer[0];
53
+ }
54
+
55
+ find(desiredSeekTimeMs: number): MediaSample | undefined {
56
+ // Take snapshot to avoid concurrent modification during iteration
57
+ const currentBuffer = [...this.buffer];
58
+
59
+ if (currentBuffer.length === 0) return undefined;
60
+
61
+ // Use consistent precision handling across the entire pipeline
62
+ const targetTimeMs = roundToMilliseconds(desiredSeekTimeMs);
63
+
64
+ // Find the sample that contains the target time
65
+ for (const sample of currentBuffer) {
66
+ const sampleStartMs = roundToMilliseconds((sample.timestamp || 0) * 1000);
67
+ const sampleDurationMs = roundToMilliseconds(
68
+ (sample.duration || 0) * 1000,
69
+ );
70
+ const sampleEndMs = roundToMilliseconds(sampleStartMs + sampleDurationMs);
71
+
72
+ // Check if the desired time falls within this sample's time span [start, end], inclusive of end
73
+ if (targetTimeMs >= sampleStartMs && targetTimeMs <= sampleEndMs) {
74
+ return sample;
75
+ }
76
+ }
77
+
78
+ return undefined; // No sample contains the target time
79
+ }
80
+
81
+ get length() {
82
+ return this.buffer.length;
83
+ }
84
+
85
+ get firstTimestamp() {
86
+ // Defensive read - get current buffer state
87
+ const currentBuffer = this.buffer;
88
+ return currentBuffer[0]?.timestamp || 0;
89
+ }
90
+
91
+ getContents(): MediaSample[] {
92
+ // Defensive copy to avoid concurrent modification during iteration
93
+ return [...this.buffer];
94
+ }
95
+ }
@@ -1,7 +1,6 @@
1
1
  import { consume, createContext, provide } from "@lit/context";
2
2
  import type { LitElement } from "lit";
3
3
  import { property, state } from "lit/decorators.js";
4
-
5
4
  import type { EFTimegroup } from "../elements/EFTimegroup.js";
6
5
  import {
7
6
  type EFConfiguration,
@@ -161,9 +160,6 @@ export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
161
160
  attributes: true,
162
161
  });
163
162
 
164
- // Preferrably we would use a resizeObserver, but it is difficult to get the first resize
165
- // timed correctly. So we use requestAnimationFrame as a stop-gap.
166
- // requestAnimationFrame(this.setStageScale);
167
163
  if (this.playing) {
168
164
  this.startPlayback();
169
165
  }
@@ -212,7 +208,7 @@ export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
212
208
 
213
209
  #playbackAudioContext: AudioContext | null = null;
214
210
  #playbackAnimationFrameRequest: number | null = null;
215
- #AUDIO_PLAYBACK_SLICE_MS = 1000;
211
+ #AUDIO_PLAYBACK_SLICE_MS = ((47 * 1024) / 48000) * 1000; // AAC-aligned: ~1002.67ms
216
212
 
217
213
  #syncPlayheadToAudioContext(target: EFTimegroup, startMs: number) {
218
214
  const rawTimeMs =
@@ -237,6 +233,7 @@ export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
237
233
  cancelAnimationFrame(this.#playbackAnimationFrameRequest);
238
234
  }
239
235
  this.#playbackAudioContext = null;
236
+ this.#playbackAnimationFrameRequest = null;
240
237
  }
241
238
 
242
239
  private async startPlayback() {
@@ -277,7 +274,7 @@ export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
277
274
  await playbackContext.suspend();
278
275
 
279
276
  const fillBuffer = async () => {
280
- if (bufferCount > 1) {
277
+ if (bufferCount > 2) {
281
278
  return;
282
279
  }
283
280
  const canFillBuffer = await queueBufferSource();
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Cache manager for handling multiple cache types with LRU eviction and statistics
3
+ */
4
+
5
+ import type {
6
+ CacheStats,
7
+ ManifestResponse,
8
+ VideoMetadata,
9
+ } from "../types/index.js";
10
+
11
+ export class CacheManager {
12
+ private segmentCache = new Map<string, ArrayBuffer>();
13
+ private metadataCache = new Map<string, VideoMetadata>();
14
+ private manifestCache = new Map<string, ManifestResponse>();
15
+ private initSegmentCache = new Map<string, ArrayBuffer>();
16
+ private cacheAccessOrder: string[] = [];
17
+
18
+ // Cache performance tracking
19
+ private cacheHits = 0;
20
+ private cacheMisses = 0;
21
+ private totalRequests = 0;
22
+
23
+ constructor(private maxSize: number) {}
24
+
25
+ /**
26
+ * Cache a segment with LRU eviction
27
+ */
28
+ cacheSegment(cacheKey: string, buffer: ArrayBuffer): void {
29
+ // Implement LRU eviction
30
+ if (this.segmentCache.size >= this.maxSize) {
31
+ const firstKey = this.segmentCache.keys().next().value;
32
+ if (firstKey) {
33
+ this.segmentCache.delete(firstKey);
34
+ // Remove from access order tracking
35
+ const index = this.cacheAccessOrder.indexOf(firstKey);
36
+ if (index > -1) {
37
+ this.cacheAccessOrder.splice(index, 1);
38
+ }
39
+ }
40
+ }
41
+
42
+ this.segmentCache.set(cacheKey, buffer);
43
+
44
+ // Track access order for LRU analytics
45
+ const existingIndex = this.cacheAccessOrder.indexOf(cacheKey);
46
+ if (existingIndex > -1) {
47
+ this.cacheAccessOrder.splice(existingIndex, 1);
48
+ }
49
+ this.cacheAccessOrder.push(cacheKey);
50
+ }
51
+
52
+ /**
53
+ * Get a segment from cache
54
+ */
55
+ getSegment(cacheKey: string): ArrayBuffer | undefined {
56
+ const cached = this.segmentCache.get(cacheKey);
57
+ if (cached) {
58
+ this.cacheHits++;
59
+ // Update access order for LRU
60
+ const index = this.cacheAccessOrder.indexOf(cacheKey);
61
+ if (index > -1) {
62
+ this.cacheAccessOrder.splice(index, 1);
63
+ this.cacheAccessOrder.push(cacheKey);
64
+ }
65
+ return cached;
66
+ }
67
+ this.cacheMisses++;
68
+ return undefined;
69
+ }
70
+
71
+ /**
72
+ * Check if a segment exists in cache
73
+ */
74
+ hasSegment(cacheKey: string): boolean {
75
+ return this.segmentCache.has(cacheKey);
76
+ }
77
+
78
+ /**
79
+ * Cache metadata
80
+ */
81
+ cacheMetadata(url: string, metadata: VideoMetadata): void {
82
+ this.metadataCache.set(url, metadata);
83
+ }
84
+
85
+ /**
86
+ * Get metadata from cache
87
+ */
88
+ getMetadata(url: string): VideoMetadata | undefined {
89
+ const cached = this.metadataCache.get(url);
90
+ if (cached) {
91
+ this.cacheHits++;
92
+ return cached;
93
+ }
94
+ this.cacheMisses++;
95
+ return undefined;
96
+ }
97
+
98
+ /**
99
+ * Cache manifest
100
+ */
101
+ cacheManifest(url: string, manifest: ManifestResponse): void {
102
+ this.manifestCache.set(url, manifest);
103
+ }
104
+
105
+ /**
106
+ * Get manifest from cache
107
+ */
108
+ getManifest(url: string): ManifestResponse | undefined {
109
+ const cached = this.manifestCache.get(url);
110
+ if (cached) {
111
+ this.cacheHits++;
112
+ return cached;
113
+ }
114
+ this.cacheMisses++;
115
+ return undefined;
116
+ }
117
+
118
+ /**
119
+ * Cache init segment
120
+ */
121
+ cacheInitSegment(cacheKey: string, buffer: ArrayBuffer): void {
122
+ this.initSegmentCache.set(cacheKey, buffer);
123
+ }
124
+
125
+ /**
126
+ * Get init segment from cache
127
+ */
128
+ getInitSegment(cacheKey: string): ArrayBuffer | undefined {
129
+ const cached = this.initSegmentCache.get(cacheKey);
130
+ if (cached) {
131
+ this.cacheHits++;
132
+ return cached;
133
+ }
134
+ this.cacheMisses++;
135
+ return undefined;
136
+ }
137
+
138
+ /**
139
+ * Get comprehensive cache statistics
140
+ */
141
+ getCacheStats(): CacheStats {
142
+ this.totalRequests = this.cacheHits + this.cacheMisses;
143
+ const hitRate =
144
+ this.totalRequests > 0 ? this.cacheHits / this.totalRequests : 0;
145
+ const efficiency =
146
+ this.segmentCache.size > 0 ? this.cacheHits / this.segmentCache.size : 0;
147
+
148
+ return {
149
+ size: this.segmentCache.size,
150
+ maxSize: this.maxSize,
151
+ hitRate: hitRate,
152
+ efficiency: efficiency,
153
+ totalRequests: this.totalRequests,
154
+ recentKeys: this.cacheAccessOrder.slice(-5), // Last 5 accessed keys
155
+ };
156
+ }
157
+
158
+ /**
159
+ * Clear all caches
160
+ */
161
+ clearAll(): void {
162
+ this.segmentCache.clear();
163
+ this.metadataCache.clear();
164
+ this.manifestCache.clear();
165
+ this.initSegmentCache.clear();
166
+ this.cacheAccessOrder = [];
167
+ this.cacheHits = 0;
168
+ this.cacheMisses = 0;
169
+ this.totalRequests = 0;
170
+ }
171
+
172
+ /**
173
+ * Get cache sizes for each cache type
174
+ */
175
+ getCacheSizes(): {
176
+ segments: number;
177
+ metadata: number;
178
+ manifests: number;
179
+ initSegments: number;
180
+ } {
181
+ return {
182
+ segments: this.segmentCache.size,
183
+ metadata: this.metadataCache.size,
184
+ manifests: this.manifestCache.size,
185
+ initSegments: this.initSegmentCache.size,
186
+ };
187
+ }
188
+
189
+ /**
190
+ * Clear specific cache type
191
+ */
192
+ clearSegmentCache(): void {
193
+ this.segmentCache.clear();
194
+ this.cacheAccessOrder = [];
195
+ }
196
+
197
+ clearMetadataCache(): void {
198
+ this.metadataCache.clear();
199
+ }
200
+
201
+ clearManifestCache(): void {
202
+ this.manifestCache.clear();
203
+ }
204
+
205
+ clearInitSegmentCache(): void {
206
+ this.initSegmentCache.clear();
207
+ }
208
+ }
@@ -0,0 +1,170 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { RequestDeduplicator } from "./RequestDeduplicator.js";
3
+
4
+ describe("RequestDeduplicator", () => {
5
+ let deduplicator: RequestDeduplicator;
6
+
7
+ beforeEach(() => {
8
+ deduplicator = new RequestDeduplicator();
9
+ });
10
+
11
+ describe("executeRequest", () => {
12
+ it("should execute request and return result for new key", async () => {
13
+ const mockFactory = vi.fn().mockResolvedValue("result");
14
+
15
+ const result = await deduplicator.executeRequest("key1", mockFactory);
16
+
17
+ expect(result).toBe("result");
18
+ expect(mockFactory).toHaveBeenCalledTimes(1);
19
+ });
20
+
21
+ it("should return same promise for concurrent requests with same key", async () => {
22
+ const mockFactory = vi.fn().mockResolvedValue("result");
23
+
24
+ const [result1, result2] = await Promise.all([
25
+ deduplicator.executeRequest("key1", mockFactory),
26
+ deduplicator.executeRequest("key1", mockFactory),
27
+ ]);
28
+
29
+ expect(result1).toBe("result");
30
+ expect(result2).toBe("result");
31
+ expect(mockFactory).toHaveBeenCalledTimes(1); // Should only be called once
32
+ });
33
+
34
+ it("should allow separate requests for different keys", async () => {
35
+ const mockFactory1 = vi.fn().mockResolvedValue("result1");
36
+ const mockFactory2 = vi.fn().mockResolvedValue("result2");
37
+
38
+ const [result1, result2] = await Promise.all([
39
+ deduplicator.executeRequest("key1", mockFactory1),
40
+ deduplicator.executeRequest("key2", mockFactory2),
41
+ ]);
42
+
43
+ expect(result1).toBe("result1");
44
+ expect(result2).toBe("result2");
45
+ expect(mockFactory1).toHaveBeenCalledTimes(1);
46
+ expect(mockFactory2).toHaveBeenCalledTimes(1);
47
+ });
48
+
49
+ it("should handle request failures and clean up", async () => {
50
+ const error = new Error("Request failed");
51
+ const mockFactory = vi.fn().mockRejectedValue(error);
52
+
53
+ await expect(
54
+ deduplicator.executeRequest("key1", mockFactory),
55
+ ).rejects.toThrow("Request failed");
56
+
57
+ // Should allow new request with same key after failure
58
+ const mockFactory2 = vi.fn().mockResolvedValue("success");
59
+ const result = await deduplicator.executeRequest("key1", mockFactory2);
60
+
61
+ expect(result).toBe("success");
62
+ expect(mockFactory).toHaveBeenCalledTimes(1);
63
+ expect(mockFactory2).toHaveBeenCalledTimes(1);
64
+ });
65
+
66
+ it("should clean up pending requests after success", async () => {
67
+ const mockFactory = vi.fn().mockResolvedValue("result");
68
+
69
+ await deduplicator.executeRequest("key1", mockFactory);
70
+
71
+ expect(deduplicator.isPending("key1")).toBe(false);
72
+ expect(deduplicator.getPendingCount()).toBe(0);
73
+ });
74
+ });
75
+
76
+ describe("isPending", () => {
77
+ it("should return true for pending requests", async () => {
78
+ const mockFactory = vi.fn().mockImplementation(
79
+ () =>
80
+ new Promise((resolve) => {
81
+ setTimeout(() => resolve("result"), 100);
82
+ }),
83
+ );
84
+
85
+ const promise = deduplicator.executeRequest("key1", mockFactory);
86
+
87
+ expect(deduplicator.isPending("key1")).toBe(true);
88
+
89
+ await promise;
90
+
91
+ expect(deduplicator.isPending("key1")).toBe(false);
92
+ });
93
+
94
+ it("should return false for non-existent keys", () => {
95
+ expect(deduplicator.isPending("nonexistent")).toBe(false);
96
+ });
97
+ });
98
+
99
+ describe("getPendingCount", () => {
100
+ it("should return 0 initially", () => {
101
+ expect(deduplicator.getPendingCount()).toBe(0);
102
+ });
103
+
104
+ it("should track pending request count", async () => {
105
+ const mockFactory = vi.fn().mockImplementation(
106
+ () =>
107
+ new Promise((resolve) => {
108
+ setTimeout(() => resolve("result"), 100);
109
+ }),
110
+ );
111
+
112
+ const promise1 = deduplicator.executeRequest("key1", mockFactory);
113
+ const promise2 = deduplicator.executeRequest("key2", mockFactory);
114
+
115
+ expect(deduplicator.getPendingCount()).toBe(2);
116
+
117
+ await Promise.all([promise1, promise2]);
118
+
119
+ expect(deduplicator.getPendingCount()).toBe(0);
120
+ });
121
+ });
122
+
123
+ describe("getPendingKeys", () => {
124
+ it("should return empty array initially", () => {
125
+ expect(deduplicator.getPendingKeys()).toEqual([]);
126
+ });
127
+
128
+ it("should return pending keys", async () => {
129
+ const mockFactory = vi.fn().mockImplementation(
130
+ () =>
131
+ new Promise((resolve) => {
132
+ setTimeout(() => resolve("result"), 100);
133
+ }),
134
+ );
135
+
136
+ const promise1 = deduplicator.executeRequest("key1", mockFactory);
137
+ const promise2 = deduplicator.executeRequest("key2", mockFactory);
138
+
139
+ const pendingKeys = deduplicator.getPendingKeys();
140
+ expect(pendingKeys).toHaveLength(2);
141
+ expect(pendingKeys).toContain("key1");
142
+ expect(pendingKeys).toContain("key2");
143
+
144
+ await Promise.all([promise1, promise2]);
145
+
146
+ expect(deduplicator.getPendingKeys()).toEqual([]);
147
+ });
148
+ });
149
+
150
+ describe("clear", () => {
151
+ it("should clear all pending requests", async () => {
152
+ const mockFactory = vi.fn().mockImplementation(
153
+ () =>
154
+ new Promise((resolve) => {
155
+ setTimeout(() => resolve("result"), 100);
156
+ }),
157
+ );
158
+
159
+ deduplicator.executeRequest("key1", mockFactory);
160
+ deduplicator.executeRequest("key2", mockFactory);
161
+
162
+ expect(deduplicator.getPendingCount()).toBe(2);
163
+
164
+ deduplicator.clear();
165
+
166
+ expect(deduplicator.getPendingCount()).toBe(0);
167
+ expect(deduplicator.getPendingKeys()).toEqual([]);
168
+ });
169
+ });
170
+ });
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Request deduplication utility
3
+ * Manages pending requests to prevent concurrent duplicate requests
4
+ */
5
+
6
+ export class RequestDeduplicator {
7
+ private pendingRequests = new Map<string, Promise<any>>();
8
+
9
+ /**
10
+ * Execute a request with deduplication
11
+ * If a request with the same key is already pending, return the existing promise
12
+ * Otherwise, execute the request factory and track the promise
13
+ */
14
+ async executeRequest<T>(
15
+ key: string,
16
+ requestFactory: () => Promise<T>,
17
+ ): Promise<T> {
18
+ // Check if there's already a pending request for this key
19
+ const existingRequest = this.pendingRequests.get(key);
20
+ if (existingRequest) {
21
+ return existingRequest;
22
+ }
23
+
24
+ // Create and track the new request
25
+ const requestPromise = requestFactory();
26
+ this.pendingRequests.set(key, requestPromise);
27
+
28
+ try {
29
+ const result = await requestPromise;
30
+ this.pendingRequests.delete(key);
31
+ return result;
32
+ } catch (error) {
33
+ this.pendingRequests.delete(key);
34
+ throw error;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Clear all pending requests (used in cache clearing)
40
+ */
41
+ clear(): void {
42
+ this.pendingRequests.clear();
43
+ }
44
+
45
+ /**
46
+ * Get number of pending requests
47
+ */
48
+ getPendingCount(): number {
49
+ return this.pendingRequests.size;
50
+ }
51
+
52
+ /**
53
+ * Check if a request is pending
54
+ */
55
+ isPending(key: string): boolean {
56
+ return this.pendingRequests.has(key);
57
+ }
58
+
59
+ /**
60
+ * Get all pending request keys
61
+ */
62
+ getPendingKeys(): string[] {
63
+ return Array.from(this.pendingRequests.keys());
64
+ }
65
+ }