@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,79 @@
1
+ import type {
2
+ AudioRendition,
3
+ MediaEngine,
4
+ VideoRendition,
5
+ } from "../../../transcoding/types";
6
+
7
+ /**
8
+ * Get audio rendition from media engine, throwing if not available
9
+ */
10
+ export const getAudioRendition = (mediaEngine: MediaEngine): AudioRendition => {
11
+ const audioRendition = mediaEngine.audioRendition;
12
+ if (!audioRendition) {
13
+ throw new Error("Audio rendition is not available");
14
+ }
15
+ return audioRendition;
16
+ };
17
+
18
+ /**
19
+ * Get video rendition from media engine, throwing if not available
20
+ */
21
+ export const getVideoRendition = (mediaEngine: MediaEngine): VideoRendition => {
22
+ const videoRendition = mediaEngine.videoRendition;
23
+ if (!videoRendition) {
24
+ throw new Error("Video rendition is not available");
25
+ }
26
+ return videoRendition;
27
+ };
28
+
29
+ /**
30
+ * Calculate which segment contains a given timestamp
31
+ * Returns 1-based segment ID, or undefined if segmentDurationMs is not available
32
+ */
33
+ export const computeSegmentId = (
34
+ timeMs: number,
35
+ rendition: AudioRendition | VideoRendition,
36
+ ): number | undefined => {
37
+ if (!rendition.segmentDurationMs) {
38
+ return undefined;
39
+ }
40
+
41
+ // Handle negative time by clamping to 0
42
+ const adjustedTimeMs = Math.max(0, timeMs);
43
+ const segmentIndex = Math.floor(adjustedTimeMs / rendition.segmentDurationMs);
44
+ return segmentIndex + 1; // Convert to 1-based segment ID
45
+ };
46
+
47
+ /**
48
+ * Calculate range of segment IDs that overlap with a time range
49
+ * Returns array of 1-based segment IDs, or empty array if segmentDurationMs is not available
50
+ */
51
+ export const calculateSegmentRange = (
52
+ startTimeMs: number,
53
+ endTimeMs: number,
54
+ rendition: AudioRendition | VideoRendition,
55
+ ): number[] => {
56
+ if (!rendition.segmentDurationMs) {
57
+ return [];
58
+ }
59
+
60
+ // Handle edge case where start equals end
61
+ if (startTimeMs === endTimeMs) {
62
+ const segmentId = computeSegmentId(startTimeMs, rendition);
63
+ return segmentId ? [segmentId] : [];
64
+ }
65
+
66
+ const startSegmentId = computeSegmentId(startTimeMs, rendition);
67
+ const endSegmentId = computeSegmentId(endTimeMs, rendition);
68
+
69
+ if (startSegmentId === undefined || endSegmentId === undefined) {
70
+ return [];
71
+ }
72
+
73
+ const segments: number[] = [];
74
+ for (let segmentId = startSegmentId; segmentId <= endSegmentId; segmentId++) {
75
+ segments.push(segmentId);
76
+ }
77
+
78
+ return segments;
79
+ };
@@ -0,0 +1,128 @@
1
+ import { test as baseTest, describe, vi } from "vitest";
2
+ import type { UrlGenerator } from "../../../transcoding/utils/UrlGenerator";
3
+ import {
4
+ createMediaEngine,
5
+ handleMediaEngineComplete,
6
+ } from "./makeMediaEngineTask";
7
+
8
+ // Define test fixtures using test.extend
9
+ const test = baseTest.extend<{
10
+ mockUrlGenerator: UrlGenerator;
11
+ mockHost: any;
12
+ mockTimegroup: any;
13
+ }>({
14
+ mockUrlGenerator: async ({}, use) => {
15
+ const mockUrlGenerator = {
16
+ generateManifestUrl: vi
17
+ .fn()
18
+ .mockReturnValue("https://example.com/manifest.m3u8"),
19
+ } as any;
20
+ await use(mockUrlGenerator);
21
+ },
22
+
23
+ mockTimegroup: async ({}, use) => {
24
+ const mockTimegroup = {
25
+ currentTimeMs: 0,
26
+ requestUpdate: vi.fn(),
27
+ };
28
+ await use(mockTimegroup);
29
+ },
30
+
31
+ mockHost: async ({ mockTimegroup, mockUrlGenerator }, use) => {
32
+ const mockHost = {
33
+ src: "https://example.com/video.mp4",
34
+ assetId: null,
35
+ urlGenerator: mockUrlGenerator,
36
+ apiHost: "https://api.example.com",
37
+ requestUpdate: vi.fn(),
38
+ rootTimegroup: mockTimegroup,
39
+ };
40
+ await use(mockHost);
41
+ },
42
+ });
43
+
44
+ describe("createMediaEngine", () => {
45
+ describe("input validation", () => {
46
+ test("should reject when assetId provided but apiHost is missing", async ({
47
+ mockHost,
48
+ expect,
49
+ }) => {
50
+ // Set up host with assetId but no apiHost
51
+ mockHost.src = "test.mp4";
52
+ mockHost.assetId = "asset123";
53
+ mockHost.apiHost = null;
54
+
55
+ await expect(createMediaEngine(mockHost)).rejects.toThrow(
56
+ "API host is required for AssetID mode",
57
+ );
58
+ });
59
+
60
+ test("should reject with empty src", async ({ mockHost, expect }) => {
61
+ // Set up host with empty src
62
+ mockHost.src = "";
63
+ mockHost.assetId = null;
64
+
65
+ await expect(createMediaEngine(mockHost)).rejects.toThrow(
66
+ "Unsupported media source",
67
+ );
68
+ });
69
+
70
+ test("should reject with null src", async ({ mockHost, expect }) => {
71
+ // Set up host with null src
72
+ mockHost.src = null;
73
+ mockHost.assetId = null;
74
+
75
+ await expect(createMediaEngine(mockHost)).rejects.toThrow(
76
+ "Unsupported media source",
77
+ );
78
+ });
79
+
80
+ test("should reject with whitespace-only src", async ({
81
+ mockHost,
82
+ expect,
83
+ }) => {
84
+ // Set up host with whitespace-only src
85
+ mockHost.src = " \t\n ";
86
+ mockHost.assetId = null;
87
+
88
+ await expect(createMediaEngine(mockHost)).rejects.toThrow(
89
+ "Unsupported media source",
90
+ );
91
+ });
92
+ });
93
+ });
94
+
95
+ describe("handleMediaEngineComplete", () => {
96
+ test("should call requestUpdate on host", async ({ mockHost, expect }) => {
97
+ handleMediaEngineComplete(mockHost);
98
+
99
+ expect(mockHost.requestUpdate).toHaveBeenCalledWith("intrinsicDurationMs");
100
+ expect(mockHost.requestUpdate).toHaveBeenCalledWith("ownCurrentTimeMs");
101
+ });
102
+
103
+ test("should call requestUpdate on rootTimegroup when present", async ({
104
+ mockHost,
105
+ mockTimegroup,
106
+ expect,
107
+ }) => {
108
+ handleMediaEngineComplete(mockHost);
109
+
110
+ expect(mockTimegroup.requestUpdate).toHaveBeenCalledWith(
111
+ "ownCurrentTimeMs",
112
+ );
113
+ expect(mockTimegroup.requestUpdate).toHaveBeenCalledWith("durationMs");
114
+ });
115
+
116
+ test("should handle missing rootTimegroup gracefully", async ({
117
+ mockHost,
118
+ expect,
119
+ }) => {
120
+ mockHost.rootTimegroup = null;
121
+
122
+ // Should not throw
123
+ handleMediaEngineComplete(mockHost);
124
+
125
+ expect(mockHost.requestUpdate).toHaveBeenCalledWith("intrinsicDurationMs");
126
+ expect(mockHost.requestUpdate).toHaveBeenCalledWith("ownCurrentTimeMs");
127
+ });
128
+ });
@@ -0,0 +1,233 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import type { EFMedia } from "../../EFMedia";
3
+ import { AssetIdMediaEngine } from "../AssetIdMediaEngine";
4
+ import { AssetMediaEngine } from "../AssetMediaEngine";
5
+ import { JitMediaEngine } from "../JitMediaEngine";
6
+ import { createMediaEngine } from "./makeMediaEngineTask";
7
+
8
+ // Mock the engine classes
9
+ vi.mock("../AssetIdMediaEngine", () => ({
10
+ AssetIdMediaEngine: {
11
+ fetchByAssetId: vi.fn(),
12
+ },
13
+ }));
14
+ vi.mock("../AssetMediaEngine");
15
+ vi.mock("../JitMediaEngine");
16
+
17
+ describe("makeMediaEngineTask", () => {
18
+ const mockUrlGenerator = {
19
+ generateManifestUrl: vi.fn(),
20
+ };
21
+
22
+ const createMockHost = (overrides: Partial<EFMedia> = {}): EFMedia =>
23
+ ({
24
+ src: "",
25
+ assetId: null,
26
+ apiHost: "https://api.example.com",
27
+ urlGenerator: mockUrlGenerator,
28
+ ...overrides,
29
+ }) as EFMedia;
30
+
31
+ beforeEach(() => {
32
+ vi.clearAllMocks();
33
+ });
34
+
35
+ describe("createMediaEngine", () => {
36
+ it("should use AssetIdMediaEngine when assetId is provided", async () => {
37
+ const mockEngine = { durationMs: 15000 };
38
+ vi.mocked(AssetIdMediaEngine.fetchByAssetId).mockResolvedValue(
39
+ mockEngine as any,
40
+ );
41
+
42
+ const host = createMockHost({
43
+ assetId: "test-asset-123",
44
+ apiHost: "https://api.example.com",
45
+ });
46
+
47
+ const result = await createMediaEngine(host);
48
+
49
+ expect(AssetIdMediaEngine.fetchByAssetId).toHaveBeenCalledWith(
50
+ host,
51
+ mockUrlGenerator,
52
+ "test-asset-123",
53
+ "https://api.example.com",
54
+ );
55
+ expect(result).toBe(mockEngine);
56
+ });
57
+
58
+ it("should throw error when assetId is provided but apiHost is missing", async () => {
59
+ const host = createMockHost({
60
+ assetId: "test-asset-123",
61
+ apiHost: undefined,
62
+ });
63
+
64
+ await expect(createMediaEngine(host)).rejects.toThrow(
65
+ "API host is required for AssetID mode",
66
+ );
67
+ });
68
+
69
+ it("should ignore empty assetId and use src instead", async () => {
70
+ const mockEngine = { durationMs: 15000 };
71
+ vi.mocked(AssetMediaEngine.fetch).mockResolvedValue(mockEngine as any);
72
+
73
+ const host = createMockHost({
74
+ assetId: "",
75
+ src: "/path/to/asset",
76
+ });
77
+
78
+ const result = await createMediaEngine(host);
79
+
80
+ expect(AssetMediaEngine.fetch).toHaveBeenCalledWith(
81
+ host,
82
+ mockUrlGenerator,
83
+ "/path/to/asset",
84
+ );
85
+ expect(AssetIdMediaEngine.fetchByAssetId).not.toHaveBeenCalled();
86
+ expect(result).toBe(mockEngine);
87
+ });
88
+
89
+ it("should ignore whitespace-only assetId and use src instead", async () => {
90
+ const mockEngine = { durationMs: 15000 };
91
+ vi.mocked(AssetMediaEngine.fetch).mockResolvedValue(mockEngine as any);
92
+
93
+ const host = createMockHost({
94
+ assetId: " ",
95
+ src: "/path/to/asset",
96
+ });
97
+
98
+ const result = await createMediaEngine(host);
99
+
100
+ expect(AssetMediaEngine.fetch).toHaveBeenCalledWith(
101
+ host,
102
+ mockUrlGenerator,
103
+ "/path/to/asset",
104
+ );
105
+ expect(AssetIdMediaEngine.fetchByAssetId).not.toHaveBeenCalled();
106
+ expect(result).toBe(mockEngine);
107
+ });
108
+
109
+ it("should use JitMediaEngine for HTTP URLs", async () => {
110
+ const mockEngine = { durationMs: 15000 };
111
+ const manifestUrl = "https://api.example.com/manifest.json";
112
+
113
+ vi.mocked(mockUrlGenerator.generateManifestUrl).mockReturnValue(
114
+ manifestUrl,
115
+ );
116
+ vi.mocked(JitMediaEngine.fetch).mockResolvedValue(mockEngine as any);
117
+
118
+ const host = createMockHost({
119
+ src: "https://example.com/video.mp4",
120
+ });
121
+
122
+ const result = await createMediaEngine(host);
123
+
124
+ expect(mockUrlGenerator.generateManifestUrl).toHaveBeenCalledWith(
125
+ "https://example.com/video.mp4",
126
+ );
127
+ expect(JitMediaEngine.fetch).toHaveBeenCalledWith(
128
+ host,
129
+ mockUrlGenerator,
130
+ manifestUrl,
131
+ );
132
+ expect(result).toBe(mockEngine);
133
+ });
134
+
135
+ it("should use JitMediaEngine for HTTPS URLs", async () => {
136
+ const mockEngine = { durationMs: 15000 };
137
+ const manifestUrl = "https://api.example.com/manifest.json";
138
+
139
+ vi.mocked(mockUrlGenerator.generateManifestUrl).mockReturnValue(
140
+ manifestUrl,
141
+ );
142
+ vi.mocked(JitMediaEngine.fetch).mockResolvedValue(mockEngine as any);
143
+
144
+ const host = createMockHost({
145
+ src: "https://example.com/video.mp4",
146
+ });
147
+
148
+ const result = await createMediaEngine(host);
149
+
150
+ expect(JitMediaEngine.fetch).toHaveBeenCalledWith(
151
+ host,
152
+ mockUrlGenerator,
153
+ manifestUrl,
154
+ );
155
+ expect(result).toBe(mockEngine);
156
+ });
157
+
158
+ it("should use AssetMediaEngine for local paths", async () => {
159
+ const mockEngine = { durationMs: 15000 };
160
+ vi.mocked(AssetMediaEngine.fetch).mockResolvedValue(mockEngine as any);
161
+
162
+ const host = createMockHost({
163
+ src: "/local/asset.mp4",
164
+ });
165
+
166
+ const result = await createMediaEngine(host);
167
+
168
+ expect(AssetMediaEngine.fetch).toHaveBeenCalledWith(
169
+ host,
170
+ mockUrlGenerator,
171
+ "/local/asset.mp4",
172
+ );
173
+ expect(result).toBe(mockEngine);
174
+ });
175
+
176
+ it("should throw error for empty src when no assetId", async () => {
177
+ const host = createMockHost({
178
+ src: "",
179
+ assetId: null,
180
+ });
181
+
182
+ await expect(createMediaEngine(host)).rejects.toThrow(
183
+ "Unsupported media source",
184
+ );
185
+ });
186
+
187
+ it("should throw error for whitespace-only src when no assetId", async () => {
188
+ const host = createMockHost({
189
+ src: " ",
190
+ assetId: null,
191
+ });
192
+
193
+ await expect(createMediaEngine(host)).rejects.toThrow(
194
+ "Unsupported media source",
195
+ );
196
+ });
197
+
198
+ it("should throw error for null src when no assetId", async () => {
199
+ const host = createMockHost({
200
+ src: null as any,
201
+ assetId: null,
202
+ });
203
+
204
+ await expect(createMediaEngine(host)).rejects.toThrow(
205
+ "Unsupported media source",
206
+ );
207
+ });
208
+
209
+ it("should prioritize assetId over src when both are provided", async () => {
210
+ const mockEngine = { durationMs: 15000 };
211
+ vi.mocked(AssetIdMediaEngine.fetchByAssetId).mockResolvedValue(
212
+ mockEngine as any,
213
+ );
214
+
215
+ const host = createMockHost({
216
+ assetId: "test-asset-123",
217
+ src: "/local/asset.mp4",
218
+ apiHost: "https://api.example.com",
219
+ });
220
+
221
+ const result = await createMediaEngine(host);
222
+
223
+ expect(AssetIdMediaEngine.fetchByAssetId).toHaveBeenCalledWith(
224
+ host,
225
+ mockUrlGenerator,
226
+ "test-asset-123",
227
+ "https://api.example.com",
228
+ );
229
+ expect(AssetMediaEngine.fetch).not.toHaveBeenCalled();
230
+ expect(result).toBe(mockEngine);
231
+ });
232
+ });
233
+ });
@@ -0,0 +1,89 @@
1
+ import { Task } from "@lit/task";
2
+ import { EF_INTERACTIVE } from "../../../EF_INTERACTIVE";
3
+ import type { MediaEngine, VideoRendition } from "../../../transcoding/types";
4
+ import type { EFMedia } from "../../EFMedia";
5
+ import { AssetIdMediaEngine } from "../AssetIdMediaEngine";
6
+ import { AssetMediaEngine } from "../AssetMediaEngine";
7
+ import { JitMediaEngine } from "../JitMediaEngine";
8
+
9
+ export const getLatestMediaEngine = async (
10
+ host: EFMedia,
11
+ signal: AbortSignal,
12
+ ): Promise<MediaEngine> => {
13
+ const mediaEngine = await host.mediaEngineTask.taskComplete;
14
+ signal.throwIfAborted();
15
+ if (!mediaEngine) {
16
+ throw new Error("Media engine is not available");
17
+ }
18
+ return mediaEngine;
19
+ };
20
+
21
+ export const getVideoRendition = (mediaEngine: MediaEngine): VideoRendition => {
22
+ const videoRendition = mediaEngine.videoRendition;
23
+ if (!videoRendition) {
24
+ throw new Error("Video rendition is not available");
25
+ }
26
+ return videoRendition;
27
+ };
28
+
29
+ /**
30
+ * Core logic for creating a MediaEngine with explicit dependencies.
31
+ * Pure function that requires all dependencies to be provided.
32
+ */
33
+ export const createMediaEngine = (host: EFMedia): Promise<MediaEngine> => {
34
+ const { src, assetId, urlGenerator, apiHost } = host;
35
+
36
+ // Check for AssetID mode first
37
+ if (assetId !== null && assetId !== undefined && assetId.trim() !== "") {
38
+ if (!apiHost) {
39
+ return Promise.reject(new Error("API host is required for AssetID mode"));
40
+ }
41
+ return AssetIdMediaEngine.fetchByAssetId(
42
+ host,
43
+ urlGenerator,
44
+ assetId,
45
+ apiHost,
46
+ );
47
+ }
48
+
49
+ // Check for null/undefined/empty/whitespace src
50
+ if (!src || typeof src !== "string" || src.trim() === "") {
51
+ console.error(`Unsupported media source: ${src}, assetId: ${assetId}`);
52
+ return Promise.reject(new Error("Unsupported media source"));
53
+ }
54
+
55
+ // Check for HTTP/HTTPS URLs (exactly "http://" or "https://")
56
+ const lowerSrc = src.toLowerCase();
57
+ if (lowerSrc.startsWith("http://") || lowerSrc.startsWith("https://")) {
58
+ const url = urlGenerator.generateManifestUrl(src);
59
+ return JitMediaEngine.fetch(host, urlGenerator, url);
60
+ }
61
+
62
+ return AssetMediaEngine.fetch(host, urlGenerator, src);
63
+ };
64
+
65
+ /**
66
+ * Handle completion of media engine task - triggers necessary updates.
67
+ * Extracted for testability.
68
+ */
69
+ export const handleMediaEngineComplete = (host: EFMedia): void => {
70
+ host.requestUpdate("intrinsicDurationMs");
71
+ host.requestUpdate("ownCurrentTimeMs");
72
+ host.rootTimegroup?.requestUpdate("ownCurrentTimeMs");
73
+ host.rootTimegroup?.requestUpdate("durationMs");
74
+ };
75
+
76
+ type MediaEngineTask = Task<readonly [string, string | null], MediaEngine>;
77
+
78
+ export const makeMediaEngineTask = (host: EFMedia): MediaEngineTask => {
79
+ return new Task(host, {
80
+ autoRun: EF_INTERACTIVE,
81
+ args: () => [host.src, host.assetId] as const,
82
+ task: async () => {
83
+ return createMediaEngine(host);
84
+ },
85
+ onComplete: (_value) => {
86
+ handleMediaEngineComplete(host);
87
+ },
88
+ });
89
+ };