@editframe/elements 0.17.6-beta.0 → 0.18.3-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/dist/EF_FRAMEGEN.js +1 -1
  2. package/dist/ScrubTrackManager.d.ts +2 -2
  3. package/dist/elements/EFAudio.d.ts +21 -2
  4. package/dist/elements/EFAudio.js +41 -11
  5. package/dist/elements/EFImage.d.ts +1 -0
  6. package/dist/elements/EFImage.js +11 -3
  7. package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +18 -0
  8. package/dist/elements/EFMedia/AssetIdMediaEngine.js +41 -0
  9. package/dist/elements/EFMedia/AssetMediaEngine.d.ts +47 -0
  10. package/dist/elements/EFMedia/AssetMediaEngine.js +116 -0
  11. package/dist/elements/EFMedia/BaseMediaEngine.d.ts +55 -0
  12. package/dist/elements/EFMedia/BaseMediaEngine.js +96 -0
  13. package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +43 -0
  14. package/dist/elements/EFMedia/BufferedSeekingInput.js +159 -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 +62 -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 +138 -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 +22 -0
  29. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.d.ts +7 -0
  30. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +24 -0
  31. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +4 -0
  32. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +18 -0
  33. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.d.ts +4 -0
  34. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +16 -0
  35. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.d.ts +3 -0
  36. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +104 -0
  37. package/dist/elements/EFMedia/services/AudioElementFactory.d.ts +22 -0
  38. package/dist/elements/EFMedia/services/AudioElementFactory.js +72 -0
  39. package/dist/elements/EFMedia/services/MediaSourceService.browsertest.d.ts +1 -0
  40. package/dist/elements/EFMedia/services/MediaSourceService.d.ts +47 -0
  41. package/dist/elements/EFMedia/services/MediaSourceService.js +73 -0
  42. package/dist/elements/EFMedia/shared/AudioSpanUtils.d.ts +7 -0
  43. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +54 -0
  44. package/dist/elements/EFMedia/shared/BufferUtils.d.ts +70 -0
  45. package/dist/elements/EFMedia/shared/BufferUtils.js +89 -0
  46. package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +23 -0
  47. package/dist/elements/EFMedia/shared/RenditionHelpers.browsertest.d.ts +1 -0
  48. package/dist/elements/EFMedia/shared/RenditionHelpers.d.ts +19 -0
  49. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.d.ts +1 -0
  50. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.d.ts +18 -0
  51. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +60 -0
  52. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.test.d.ts +1 -0
  53. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.d.ts +9 -0
  54. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +16 -0
  55. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +46 -0
  56. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.d.ts +9 -0
  57. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.d.ts +4 -0
  58. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.js +16 -0
  59. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.d.ts +9 -0
  60. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.d.ts +3 -0
  61. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.js +27 -0
  62. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.d.ts +7 -0
  63. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +25 -0
  64. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.d.ts +9 -0
  65. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.d.ts +4 -0
  66. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +18 -0
  67. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.d.ts +9 -0
  68. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.d.ts +4 -0
  69. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.js +16 -0
  70. package/dist/elements/EFMedia.browsertest.d.ts +1 -0
  71. package/dist/elements/EFMedia.d.ts +75 -111
  72. package/dist/elements/EFMedia.js +141 -1111
  73. package/dist/elements/EFTemporal.d.ts +1 -1
  74. package/dist/elements/EFTemporal.js +1 -1
  75. package/dist/elements/EFTimegroup.d.ts +11 -0
  76. package/dist/elements/EFTimegroup.js +88 -13
  77. package/dist/elements/EFVideo.d.ts +60 -29
  78. package/dist/elements/EFVideo.js +103 -203
  79. package/dist/elements/EFWaveform.js +2 -2
  80. package/dist/elements/SampleBuffer.d.ts +14 -0
  81. package/dist/elements/SampleBuffer.js +52 -0
  82. package/dist/getRenderInfo.d.ts +2 -2
  83. package/dist/getRenderInfo.js +2 -1
  84. package/dist/gui/ContextMixin.js +17 -70
  85. package/dist/gui/EFFilmstrip.d.ts +3 -3
  86. package/dist/gui/EFFilmstrip.js +1 -1
  87. package/dist/gui/EFFitScale.d.ts +2 -2
  88. package/dist/gui/TWMixin.js +1 -1
  89. package/dist/gui/services/ElementConnectionManager.browsertest.d.ts +1 -0
  90. package/dist/gui/services/ElementConnectionManager.d.ts +59 -0
  91. package/dist/gui/services/ElementConnectionManager.js +128 -0
  92. package/dist/gui/services/PlaybackController.browsertest.d.ts +1 -0
  93. package/dist/gui/services/PlaybackController.d.ts +103 -0
  94. package/dist/gui/services/PlaybackController.js +290 -0
  95. package/dist/services/MediaSourceManager.d.ts +62 -0
  96. package/dist/services/MediaSourceManager.js +211 -0
  97. package/dist/style.css +1 -1
  98. package/dist/transcoding/cache/CacheManager.d.ts +73 -0
  99. package/dist/transcoding/cache/RequestDeduplicator.d.ts +29 -0
  100. package/dist/transcoding/cache/RequestDeduplicator.js +53 -0
  101. package/dist/transcoding/cache/RequestDeduplicator.test.d.ts +1 -0
  102. package/dist/transcoding/types/index.d.ts +242 -0
  103. package/dist/transcoding/utils/MediaUtils.d.ts +9 -0
  104. package/dist/transcoding/utils/UrlGenerator.d.ts +26 -0
  105. package/dist/transcoding/utils/UrlGenerator.js +45 -0
  106. package/dist/transcoding/utils/constants.d.ts +27 -0
  107. package/dist/utils/LRUCache.d.ts +34 -0
  108. package/dist/utils/LRUCache.js +115 -0
  109. package/package.json +3 -2
  110. package/src/elements/EFAudio.browsertest.ts +183 -43
  111. package/src/elements/EFAudio.ts +59 -13
  112. package/src/elements/EFImage.browsertest.ts +42 -0
  113. package/src/elements/EFImage.ts +23 -3
  114. package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +222 -0
  115. package/src/elements/EFMedia/AssetIdMediaEngine.ts +70 -0
  116. package/src/elements/EFMedia/AssetMediaEngine.ts +210 -0
  117. package/src/elements/EFMedia/BaseMediaEngine.test.ts +164 -0
  118. package/src/elements/EFMedia/BaseMediaEngine.ts +170 -0
  119. package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +400 -0
  120. package/src/elements/EFMedia/BufferedSeekingInput.ts +267 -0
  121. package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +165 -0
  122. package/src/elements/EFMedia/JitMediaEngine.ts +110 -0
  123. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +554 -0
  124. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +81 -0
  125. package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +241 -0
  126. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +59 -0
  127. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +23 -0
  128. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +55 -0
  129. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +35 -0
  130. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +42 -0
  131. package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +34 -0
  132. package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +23 -0
  133. package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +174 -0
  134. package/src/elements/EFMedia/services/AudioElementFactory.browsertest.ts +325 -0
  135. package/src/elements/EFMedia/services/AudioElementFactory.ts +119 -0
  136. package/src/elements/EFMedia/services/MediaSourceService.browsertest.ts +257 -0
  137. package/src/elements/EFMedia/services/MediaSourceService.ts +102 -0
  138. package/src/elements/EFMedia/shared/AudioSpanUtils.ts +128 -0
  139. package/src/elements/EFMedia/shared/BufferUtils.ts +310 -0
  140. package/src/elements/EFMedia/shared/MediaTaskUtils.ts +44 -0
  141. package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +247 -0
  142. package/src/elements/EFMedia/shared/RenditionHelpers.ts +79 -0
  143. package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +128 -0
  144. package/src/elements/EFMedia/tasks/makeMediaEngineTask.test.ts +233 -0
  145. package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +89 -0
  146. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.ts +555 -0
  147. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +79 -0
  148. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.ts +59 -0
  149. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts +23 -0
  150. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.ts +55 -0
  151. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.ts +45 -0
  152. package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +44 -0
  153. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.ts +57 -0
  154. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +32 -0
  155. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.ts +56 -0
  156. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.ts +23 -0
  157. package/src/elements/EFMedia.browsertest.ts +658 -265
  158. package/src/elements/EFMedia.ts +173 -1763
  159. package/src/elements/EFTemporal.ts +3 -4
  160. package/src/elements/EFTimegroup.browsertest.ts +6 -3
  161. package/src/elements/EFTimegroup.ts +152 -21
  162. package/src/elements/EFVideo.browsertest.ts +115 -37
  163. package/src/elements/EFVideo.ts +123 -452
  164. package/src/elements/EFWaveform.ts +1 -1
  165. package/src/elements/MediaController.ts +2 -12
  166. package/src/elements/SampleBuffer.ts +97 -0
  167. package/src/gui/ContextMixin.ts +23 -104
  168. package/src/gui/services/ElementConnectionManager.browsertest.ts +263 -0
  169. package/src/gui/services/ElementConnectionManager.ts +224 -0
  170. package/src/gui/services/PlaybackController.browsertest.ts +437 -0
  171. package/src/gui/services/PlaybackController.ts +521 -0
  172. package/src/services/MediaSourceManager.ts +333 -0
  173. package/src/transcoding/cache/CacheManager.ts +208 -0
  174. package/src/transcoding/cache/RequestDeduplicator.test.ts +170 -0
  175. package/src/transcoding/cache/RequestDeduplicator.ts +65 -0
  176. package/src/transcoding/types/index.ts +265 -0
  177. package/src/transcoding/utils/MediaUtils.ts +63 -0
  178. package/src/transcoding/utils/UrlGenerator.ts +68 -0
  179. package/src/transcoding/utils/constants.ts +36 -0
  180. package/src/utils/LRUCache.ts +153 -0
  181. package/test/EFVideo.framegen.browsertest.ts +38 -29
  182. 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
  183. 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
  184. 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
  185. 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
  186. 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
  187. 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
  188. 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
  189. 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
  190. 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
  191. 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
  192. 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
  193. 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
  194. 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
  195. 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
  196. 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
  197. 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
  198. 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
  199. 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
  200. 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
  201. 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
  202. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -0
  203. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +19 -0
  204. package/test/createJitTestClips.ts +320 -188
  205. package/test/recordReplayProxyPlugin.js +302 -0
  206. package/test/useAssetMSW.ts +1 -1
  207. package/test/useMSW.ts +35 -22
  208. package/types.json +1 -1
  209. package/dist/JitTranscodingClient.d.ts +0 -167
  210. package/dist/JitTranscodingClient.js +0 -373
  211. package/dist/ScrubTrackManager.js +0 -216
  212. package/dist/elements/printTaskStatus.js +0 -11
  213. package/src/elements/__screenshots__/EFMedia.browsertest.ts/EFMedia-JIT-audio-playback-audioBufferTask-should-work-in-JIT-mode-without-URL-errors-1.png +0 -0
  214. package/test/EFVideo.frame-tasks.browsertest.ts +0 -524
  215. /package/dist/{JitTranscodingClient.browsertest.d.ts → elements/EFMedia/AssetIdMediaEngine.test.d.ts} +0 -0
  216. /package/dist/{JitTranscodingClient.test.d.ts → elements/EFMedia/BaseMediaEngine.test.d.ts} +0 -0
  217. /package/dist/{ScrubTrackIntegration.test.d.ts → elements/EFMedia/BufferedSeekingInput.browsertest.d.ts} +0 -0
  218. /package/dist/{SegmentSwitchLoading.test.d.ts → elements/EFMedia/services/AudioElementFactory.browsertest.d.ts} +0 -0
@@ -1,2 +1,2 @@
1
- var TWMixin_default = "*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:\"\"}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.col-span-2{grid-column:span 2/span 2}.mx-2{margin-left:.5rem;margin-right:.5rem}.mb-\\[1px\\]{margin-bottom:1px}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-\\[1\\.1rem\\]{height:1.1rem}.h-\\[5px\\]{height:5px}.h-full{height:100%}.w-1{width:.25rem}.w-\\[2px\\]{width:2px}.w-full{width:100%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.cursor-crosshair{cursor:crosshair}.resize{resize:both}.flex-wrap{flex-wrap:wrap}.place-content-center{place-content:center}.items-center{align-items:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.text-nowrap{text-wrap:nowrap}.rounded{border-radius:.25rem}.border{border-width:1px}.border-r-2{border-right-width:2px}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity))}.border-red-700{--tw-border-opacity:1;border-color:rgb(185 28 28/var(--tw-border-opacity))}.border-slate-500{--tw-border-opacity:1;border-color:rgb(100 116 139/var(--tw-border-opacity))}.border-b-slate-600{--tw-border-opacity:1;border-bottom-color:rgb(71 85 105/var(--tw-border-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(191 219 254/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity))}.bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity))}.bg-opacity-20{--tw-bg-opacity:.2}.p-\\[1px\\]{padding:1px}.pb-0{padding-bottom:0}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pr-0{padding-right:0}.pr-1{padding-right:.25rem}.pt-\\[8px\\]{padding-top:8px}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-5xl{font-size:3rem;line-height:1}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.line-through{text-decoration-line:line-through}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-slate-300{--tw-shadow-color:#cbd5e1;--tw-shadow:var(--tw-shadow-colored)}.shadow-slate-600{--tw-shadow-color:#475569;--tw-shadow:var(--tw-shadow-colored)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px);filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.filter{filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia)}.hover\\:bg-slate-400:hover{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer:hover~.peer-hover\\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer:hover~.peer-hover\\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.data-\\[focused\\]\\:bg-slate-400[data-focused]{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer[data-focused]~.peer-data-\\[focused\\]\\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer[data-focused]~.peer-data-\\[focused\\]\\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}";
1
+ var TWMixin_default = "*,:before,:after{box-sizing:border-box;border:0 solid #e5e7eb}:before,:after{--tw-content:\"\"}html,:host{-webkit-text-size-adjust:100%;tab-size:4;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{line-height:inherit;margin:0}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-feature-settings:normal;font-variation-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-feature-settings:inherit;font-variation-settings:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:#0000;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{margin:0;padding:0;list-style:none}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder{opacity:1;color:#9ca3af}textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.top-0{top:0}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.col-span-2{grid-column:span 2/span 2}.mx-2{margin-left:.5rem;margin-right:.5rem}.mb-\\[1px\\]{margin-bottom:1px}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-\\[1\\.1rem\\]{height:1.1rem}.h-\\[270px\\]{height:270px}.h-\\[5px\\]{height:5px}.h-full{height:100%}.w-1{width:.25rem}.w-\\[2px\\]{width:2px}.w-\\[480px\\]{width:480px}.w-full{width:100%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y))rotate(var(--tw-rotate))skewX(var(--tw-skew-x))skewY(var(--tw-skew-y))scaleX(var(--tw-scale-x))scaleY(var(--tw-scale-y))}.cursor-crosshair{cursor:crosshair}.resize{resize:both}.flex-wrap{flex-wrap:wrap}.place-content-center{place-content:center}.items-center{align-items:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.text-nowrap{text-wrap:nowrap}.rounded{border-radius:.25rem}.border{border-width:1px}.border-r-2{border-right-width:2px}.border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity))}.border-red-700{--tw-border-opacity:1;border-color:rgb(185 28 28/var(--tw-border-opacity))}.border-slate-500{--tw-border-opacity:1;border-color:rgb(100 116 139/var(--tw-border-opacity))}.border-b-slate-600{--tw-border-opacity:1;border-bottom-color:rgb(71 85 105/var(--tw-border-opacity))}.bg-blue-200{--tw-bg-opacity:1;background-color:rgb(191 219 254/var(--tw-bg-opacity))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity))}.bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.bg-slate-800{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity))}.bg-opacity-20{--tw-bg-opacity:.2}.p-\\[1px\\]{padding:1px}.pb-0{padding-bottom:0}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pr-0{padding-right:0}.pr-1{padding-right:.25rem}.pt-\\[8px\\]{padding-top:8px}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-5xl{font-size:3rem;line-height:1}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.line-through{text-decoration-line:line-through}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-slate-300{--tw-shadow-color:#cbd5e1;--tw-shadow:var(--tw-shadow-colored)}.shadow-slate-600{--tw-shadow-color:#475569;--tw-shadow:var(--tw-shadow-colored)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px);filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.filter{filter:var(--tw-blur)var(--tw-brightness)var(--tw-contrast)var(--tw-grayscale)var(--tw-hue-rotate)var(--tw-invert)var(--tw-saturate)var(--tw-sepia)var(--tw-drop-shadow)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur)var(--tw-backdrop-brightness)var(--tw-backdrop-contrast)var(--tw-backdrop-grayscale)var(--tw-backdrop-hue-rotate)var(--tw-backdrop-invert)var(--tw-backdrop-opacity)var(--tw-backdrop-saturate)var(--tw-backdrop-sepia)}.hover\\:bg-slate-400:hover{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer:hover~.peer-hover\\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer:hover~.peer-hover\\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}.data-\\[focused\\]\\:bg-slate-400[data-focused]{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}.peer[data-focused]~.peer-data-\\[focused\\]\\:border-slate-400{--tw-border-opacity:1;border-color:rgb(148 163 184/var(--tw-border-opacity))}.peer[data-focused]~.peer-data-\\[focused\\]\\:bg-slate-300{--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}";
2
2
  export { TWMixin_default as default };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Manages dynamic connection/disconnection of media elements to AudioContext
3
+ * Extracted from ContextMixin to improve separation of concerns and testability
4
+ */
5
+ export declare class ElementConnectionManager {
6
+ private connectedMediaSources;
7
+ private lookaheadMs;
8
+ constructor(lookaheadMs?: number);
9
+ /**
10
+ * Update connected media elements based on current playhead position
11
+ * Connects upcoming elements and disconnects past elements
12
+ */
13
+ updateConnectedElements(audioContext: AudioContext, timegroup: any, // EFTimegroup type
14
+ currentMs: number): Promise<void>;
15
+ /**
16
+ * Find elements that should be connected based on timeline position
17
+ */
18
+ private getElementsToConnect;
19
+ /**
20
+ * Connect new elements that aren't already connected
21
+ */
22
+ private connectNewElements;
23
+ /**
24
+ * Update connection states for all managed elements
25
+ */
26
+ private updateElementStates;
27
+ /**
28
+ * Activate an element (connect to destination and start playback)
29
+ */
30
+ private activateElement;
31
+ /**
32
+ * Deactivate an element (disconnect but keep prepared)
33
+ */
34
+ private deactivateElement;
35
+ /**
36
+ * Clean up elements that are far in the past
37
+ */
38
+ private cleanupOldElements;
39
+ /**
40
+ * Clear all connected media sources (for cleanup)
41
+ */
42
+ clearAll(): void;
43
+ /**
44
+ * Get connection status for testing/debugging
45
+ */
46
+ getConnectionInfo(): {
47
+ total: number;
48
+ connected: number;
49
+ prepared: number;
50
+ };
51
+ /**
52
+ * Set lookahead time
53
+ */
54
+ setLookaheadMs(lookaheadMs: number): void;
55
+ /**
56
+ * Get current lookahead time
57
+ */
58
+ getLookaheadMs(): number;
59
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Manages dynamic connection/disconnection of media elements to AudioContext
3
+ * Extracted from ContextMixin to improve separation of concerns and testability
4
+ */
5
+ var ElementConnectionManager = class {
6
+ constructor(lookaheadMs = 3e3) {
7
+ this.connectedMediaSources = /* @__PURE__ */ new Map();
8
+ this.lookaheadMs = lookaheadMs;
9
+ }
10
+ /**
11
+ * Update connected media elements based on current playhead position
12
+ * Connects upcoming elements and disconnects past elements
13
+ */
14
+ async updateConnectedElements(audioContext, timegroup, currentMs) {
15
+ if (!audioContext || audioContext.state === "closed") return;
16
+ const allMediaElements = Array.from(timegroup.querySelectorAll("ef-audio, ef-video"));
17
+ const lookaheadMs = currentMs + this.lookaheadMs;
18
+ const elementsToConnect = this.getElementsToConnect(allMediaElements, currentMs, lookaheadMs);
19
+ await this.connectNewElements(audioContext, elementsToConnect);
20
+ await this.updateElementStates(currentMs);
21
+ this.cleanupOldElements(currentMs);
22
+ }
23
+ /**
24
+ * Find elements that should be connected based on timeline position
25
+ */
26
+ getElementsToConnect(allElements, currentMs, lookaheadMs) {
27
+ return allElements.filter((mediaElement) => {
28
+ const startTime = mediaElement.startTimeMs;
29
+ const endTime = mediaElement.endTimeMs;
30
+ const isCurrentlyActive = currentMs >= startTime && currentMs < endTime;
31
+ const isStartingSoon = startTime > currentMs && startTime <= lookaheadMs;
32
+ return isCurrentlyActive || isStartingSoon;
33
+ });
34
+ }
35
+ /**
36
+ * Connect new elements that aren't already connected
37
+ */
38
+ async connectNewElements(audioContext, elementsToConnect) {
39
+ for (const mediaElement of elementsToConnect) if (!this.connectedMediaSources.has(mediaElement)) {
40
+ const mediaElementSource = await mediaElement.getMediaElementSource(audioContext);
41
+ this.connectedMediaSources.set(mediaElement, {
42
+ mediaElementSource,
43
+ connected: false
44
+ });
45
+ }
46
+ }
47
+ /**
48
+ * Update connection states for all managed elements
49
+ */
50
+ async updateElementStates(currentMs) {
51
+ for (const [mediaElement, sourceInfo] of this.connectedMediaSources.entries()) {
52
+ const startTime = mediaElement.startTimeMs;
53
+ const endTime = mediaElement.endTimeMs;
54
+ const isCurrentlyActive = currentMs >= startTime && currentMs < endTime;
55
+ if (isCurrentlyActive && !sourceInfo.connected) await this.activateElement(mediaElement, sourceInfo);
56
+ else if (!isCurrentlyActive && sourceInfo.connected) await this.deactivateElement(mediaElement, sourceInfo);
57
+ }
58
+ }
59
+ /**
60
+ * Activate an element (connect to destination and start playback)
61
+ */
62
+ async activateElement(mediaElement, sourceInfo) {
63
+ sourceInfo.mediaElementSource.connect(sourceInfo.mediaElementSource.context.destination);
64
+ sourceInfo.connected = true;
65
+ if (mediaElement.audioElement) {
66
+ const mediaTimeMs = mediaElement.currentSourceTimeMs;
67
+ mediaElement.audioElement.currentTime = mediaTimeMs / 1e3;
68
+ await mediaElement.audioElement.play();
69
+ }
70
+ }
71
+ /**
72
+ * Deactivate an element (disconnect but keep prepared)
73
+ */
74
+ async deactivateElement(mediaElement, sourceInfo) {
75
+ sourceInfo.mediaElementSource.disconnect();
76
+ sourceInfo.connected = false;
77
+ if (mediaElement.audioElement) mediaElement.audioElement.pause();
78
+ }
79
+ /**
80
+ * Clean up elements that are far in the past
81
+ */
82
+ cleanupOldElements(currentMs) {
83
+ const cleanupThresholdMs = currentMs - this.lookaheadMs;
84
+ for (const [mediaElement, sourceInfo] of this.connectedMediaSources.entries()) {
85
+ const endTime = mediaElement.endTimeMs;
86
+ if (endTime < cleanupThresholdMs) {
87
+ if (sourceInfo.connected) sourceInfo.mediaElementSource.disconnect();
88
+ this.connectedMediaSources.delete(mediaElement);
89
+ }
90
+ }
91
+ }
92
+ /**
93
+ * Clear all connected media sources (for cleanup)
94
+ */
95
+ clearAll() {
96
+ for (const [, sourceInfo] of this.connectedMediaSources.entries()) try {
97
+ if (sourceInfo.connected) sourceInfo.mediaElementSource.disconnect();
98
+ } catch (_error) {}
99
+ this.connectedMediaSources.clear();
100
+ }
101
+ /**
102
+ * Get connection status for testing/debugging
103
+ */
104
+ getConnectionInfo() {
105
+ let connected = 0;
106
+ let prepared = 0;
107
+ for (const [, sourceInfo] of this.connectedMediaSources.entries()) if (sourceInfo.connected) connected++;
108
+ else prepared++;
109
+ return {
110
+ total: this.connectedMediaSources.size,
111
+ connected,
112
+ prepared
113
+ };
114
+ }
115
+ /**
116
+ * Set lookahead time
117
+ */
118
+ setLookaheadMs(lookaheadMs) {
119
+ this.lookaheadMs = lookaheadMs;
120
+ }
121
+ /**
122
+ * Get current lookahead time
123
+ */
124
+ getLookaheadMs() {
125
+ return this.lookaheadMs;
126
+ }
127
+ };
128
+ export { ElementConnectionManager };
@@ -0,0 +1,103 @@
1
+ export interface PlaybackControllerOptions {
2
+ fps?: number;
3
+ onTimeUpdate?: (timeMs: number) => void;
4
+ onPlayStateChange?: (playing: boolean) => void;
5
+ onError?: (error: Error) => void;
6
+ }
7
+ /**
8
+ * Manages playback timing, AudioContext lifecycle, and timeline synchronization
9
+ * Extracted from ContextMixin to improve separation of concerns and testability
10
+ */
11
+ export declare class PlaybackController {
12
+ private playbackAudioContext;
13
+ private animationFrameRequest;
14
+ private options;
15
+ private playing;
16
+ private currentTimeMs;
17
+ private msPerFrame;
18
+ private audioStartTime;
19
+ private playbackStartTimeMs;
20
+ private activeChunks;
21
+ private chunkDurationMs;
22
+ private lookaheadChunks;
23
+ private currentChunkIndex;
24
+ private renderingChunks;
25
+ constructor(options?: PlaybackControllerOptions);
26
+ /**
27
+ * Start playback for the given timegroup
28
+ */
29
+ startPlayback(timegroup: any, fromMs?: number): Promise<void>;
30
+ /**
31
+ * Stop playback and clean up resources
32
+ */
33
+ stopPlayback(): Promise<void>;
34
+ /**
35
+ * Pause playback (can be resumed)
36
+ */
37
+ pausePlayback(): Promise<void>;
38
+ /**
39
+ * Resume paused playback
40
+ */
41
+ resumePlayback(): Promise<void>;
42
+ /**
43
+ * Seek to a specific time (restarts progressive playback from new position)
44
+ */
45
+ seekTo(timeMs: number, timegroup?: any): Promise<void>;
46
+ /**
47
+ * Internal method to sync playhead with unified audio buffer timing
48
+ */
49
+ private syncPlayheadToAudioBuffer;
50
+ /**
51
+ * Update playing state and notify observers
52
+ */
53
+ private setPlaying;
54
+ /**
55
+ * Get current playback state
56
+ */
57
+ isPlaying(): boolean;
58
+ /**
59
+ * Get current time
60
+ */
61
+ getCurrentTime(): number;
62
+ /**
63
+ * Get current AudioContext
64
+ */
65
+ getAudioContext(): AudioContext | null;
66
+ /**
67
+ * Check if AudioContext is ready
68
+ */
69
+ isAudioContextReady(): boolean;
70
+ /**
71
+ * Get playback statistics for debugging
72
+ */
73
+ getPlaybackInfo(): {
74
+ playing: boolean;
75
+ currentTimeMs: number;
76
+ audioContextState: string | null;
77
+ hasElementManager: boolean;
78
+ };
79
+ /**
80
+ * Update playback options
81
+ */
82
+ updateOptions(options: Partial<PlaybackControllerOptions>): void;
83
+ /**
84
+ * Start progressive chunk rendering and playback
85
+ */
86
+ private startProgressivePlayback;
87
+ /**
88
+ * Render and schedule a single audio chunk
89
+ */
90
+ private renderAndScheduleChunk;
91
+ /**
92
+ * Update chunk rendering as playhead advances - now handles all chunk management
93
+ */
94
+ private updateProgressiveChunks;
95
+ /**
96
+ * Systematically ensure chunks are ready ahead of current playback (synchronous)
97
+ */
98
+ private ensureChunksAhead;
99
+ /**
100
+ * Clean up chunks that are behind the current playhead
101
+ */
102
+ private cleanupOldChunks;
103
+ }
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Manages playback timing, AudioContext lifecycle, and timeline synchronization
3
+ * Extracted from ContextMixin to improve separation of concerns and testability
4
+ */
5
+ var PlaybackController = class {
6
+ constructor(options = {}) {
7
+ this.playbackAudioContext = null;
8
+ this.animationFrameRequest = null;
9
+ this.playing = false;
10
+ this.currentTimeMs = 0;
11
+ this.audioStartTime = 0;
12
+ this.playbackStartTimeMs = 0;
13
+ this.activeChunks = /* @__PURE__ */ new Map();
14
+ this.chunkDurationMs = 4e3;
15
+ this.lookaheadChunks = 2;
16
+ this.currentChunkIndex = 0;
17
+ this.renderingChunks = /* @__PURE__ */ new Set();
18
+ this.options = {
19
+ fps: 30,
20
+ onTimeUpdate: () => {},
21
+ onPlayStateChange: () => {},
22
+ onError: () => {},
23
+ ...options
24
+ };
25
+ this.msPerFrame = 1e3 / this.options.fps;
26
+ }
27
+ /**
28
+ * Start playback for the given timegroup
29
+ */
30
+ async startPlayback(timegroup, fromMs) {
31
+ await this.stopPlayback();
32
+ if (!timegroup) {
33
+ this.setPlaying(false);
34
+ this.options.onPlayStateChange(false);
35
+ this.options.onError(/* @__PURE__ */ new Error("No timegroup provided"));
36
+ return;
37
+ }
38
+ await timegroup.waitForMediaDurations?.();
39
+ const currentMs = fromMs ?? timegroup.currentTimeMs ?? 0;
40
+ const toMs = timegroup.endTimeMs;
41
+ if (currentMs >= toMs) {
42
+ this.setPlaying(false);
43
+ this.options.onPlayStateChange(false);
44
+ return;
45
+ }
46
+ try {
47
+ this.playbackAudioContext = new AudioContext({ latencyHint: "playback" });
48
+ if (this.playbackAudioContext.state === "suspended") {
49
+ console.warn("AudioContext is suspended, attempting to resume...");
50
+ try {
51
+ await Promise.race([this.playbackAudioContext.resume(), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("AudioContext resume timeout")), 2e3))]);
52
+ } catch (error) {
53
+ console.warn("AudioContext resume failed:", error);
54
+ }
55
+ } else await this.playbackAudioContext.resume();
56
+ this.audioStartTime = this.playbackAudioContext.currentTime;
57
+ this.playbackStartTimeMs = currentMs;
58
+ this.currentChunkIndex = Math.floor(currentMs / this.chunkDurationMs);
59
+ await this.startProgressivePlayback(timegroup, currentMs, toMs);
60
+ if (this.isAudioContextReady()) {
61
+ this.setPlaying(true);
62
+ this.currentTimeMs = currentMs;
63
+ this.options.onTimeUpdate(currentMs);
64
+ this.syncPlayheadToAudioBuffer(timegroup, currentMs);
65
+ } else {
66
+ this.setPlaying(false);
67
+ this.options.onPlayStateChange(false);
68
+ console.warn("AudioContext not ready for playback, state:", this.playbackAudioContext?.state);
69
+ }
70
+ } catch (error) {
71
+ console.error("🎵 [PLAYBACK_ERROR] Failed to setup progressive audio playback:", error);
72
+ this.setPlaying(false);
73
+ this.options.onPlayStateChange(false);
74
+ this.options.onError(error);
75
+ }
76
+ }
77
+ /**
78
+ * Stop playback and clean up resources
79
+ */
80
+ async stopPlayback() {
81
+ for (const [_chunkIndex, bufferSource] of this.activeChunks.entries()) try {
82
+ bufferSource.stop();
83
+ } catch (_error) {}
84
+ this.activeChunks.clear();
85
+ this.renderingChunks.clear();
86
+ if (this.playbackAudioContext) {
87
+ if (this.playbackAudioContext.state !== "closed") await this.playbackAudioContext.close();
88
+ }
89
+ if (this.animationFrameRequest) {
90
+ cancelAnimationFrame(this.animationFrameRequest);
91
+ this.animationFrameRequest = null;
92
+ }
93
+ this.playbackAudioContext = null;
94
+ this.setPlaying(false);
95
+ }
96
+ /**
97
+ * Pause playback (can be resumed)
98
+ */
99
+ async pausePlayback() {
100
+ if (this.playbackAudioContext && this.playbackAudioContext.state === "running") try {
101
+ await Promise.race([this.playbackAudioContext.suspend(), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("AudioContext suspend timeout")), 2e3))]);
102
+ } catch (error) {
103
+ console.warn("AudioContext suspend failed:", error);
104
+ }
105
+ if (this.animationFrameRequest) {
106
+ cancelAnimationFrame(this.animationFrameRequest);
107
+ this.animationFrameRequest = null;
108
+ }
109
+ this.setPlaying(false);
110
+ }
111
+ /**
112
+ * Resume paused playback
113
+ */
114
+ async resumePlayback() {
115
+ if (this.playbackAudioContext && this.playbackAudioContext.state === "suspended") {
116
+ try {
117
+ await Promise.race([this.playbackAudioContext.resume(), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("AudioContext resume timeout")), 2e3))]);
118
+ } catch (error) {
119
+ console.warn("AudioContext resume failed:", error);
120
+ }
121
+ this.setPlaying(true);
122
+ }
123
+ }
124
+ /**
125
+ * Seek to a specific time (restarts progressive playback from new position)
126
+ */
127
+ async seekTo(timeMs, timegroup) {
128
+ this.currentTimeMs = timeMs;
129
+ this.options.onTimeUpdate(timeMs);
130
+ if (this.playing && timegroup) {
131
+ for (const bufferSource of this.activeChunks.values()) try {
132
+ bufferSource.stop();
133
+ } catch (_error) {}
134
+ this.activeChunks.clear();
135
+ this.renderingChunks.clear();
136
+ this.audioStartTime = this.playbackAudioContext?.currentTime ?? 0;
137
+ this.playbackStartTimeMs = timeMs;
138
+ this.currentChunkIndex = Math.floor(timeMs / this.chunkDurationMs);
139
+ await this.startProgressivePlayback(timegroup, timeMs, timegroup.endTimeMs);
140
+ }
141
+ }
142
+ /**
143
+ * Internal method to sync playhead with unified audio buffer timing
144
+ */
145
+ syncPlayheadToAudioBuffer(timegroup, startMs) {
146
+ if (!this.playbackAudioContext || !this.playing) return;
147
+ const elapsedAudioTime = this.playbackAudioContext.currentTime - this.audioStartTime;
148
+ const rawTimeMs = startMs + elapsedAudioTime * 1e3;
149
+ const nextTimeMs = Math.round(rawTimeMs / this.msPerFrame) * this.msPerFrame;
150
+ if (nextTimeMs !== this.currentTimeMs) {
151
+ this.currentTimeMs = nextTimeMs;
152
+ this.options.onTimeUpdate(nextTimeMs);
153
+ if (timegroup && timegroup.currentTimeMs !== nextTimeMs) timegroup.currentTimeMs = nextTimeMs;
154
+ this.updateProgressiveChunks(timegroup, nextTimeMs, timegroup.endTimeMs);
155
+ }
156
+ this.animationFrameRequest = requestAnimationFrame(() => {
157
+ this.syncPlayheadToAudioBuffer(timegroup, startMs);
158
+ });
159
+ }
160
+ /**
161
+ * Update playing state and notify observers
162
+ */
163
+ setPlaying(playing) {
164
+ if (this.playing !== playing) {
165
+ this.playing = playing;
166
+ this.options.onPlayStateChange(playing);
167
+ }
168
+ }
169
+ /**
170
+ * Get current playback state
171
+ */
172
+ isPlaying() {
173
+ return this.playing;
174
+ }
175
+ /**
176
+ * Get current time
177
+ */
178
+ getCurrentTime() {
179
+ return this.currentTimeMs;
180
+ }
181
+ /**
182
+ * Get current AudioContext
183
+ */
184
+ getAudioContext() {
185
+ return this.playbackAudioContext;
186
+ }
187
+ /**
188
+ * Check if AudioContext is ready
189
+ */
190
+ isAudioContextReady() {
191
+ return this.playbackAudioContext != null && this.playbackAudioContext.state !== "closed";
192
+ }
193
+ /**
194
+ * Get playback statistics for debugging
195
+ */
196
+ getPlaybackInfo() {
197
+ return {
198
+ playing: this.playing,
199
+ currentTimeMs: this.currentTimeMs,
200
+ audioContextState: this.playbackAudioContext?.state || null,
201
+ hasElementManager: false
202
+ };
203
+ }
204
+ /**
205
+ * Update playback options
206
+ */
207
+ updateOptions(options) {
208
+ Object.assign(this.options, options);
209
+ if (options.fps) this.msPerFrame = 1e3 / options.fps;
210
+ }
211
+ /**
212
+ * Start progressive chunk rendering and playback
213
+ */
214
+ async startProgressivePlayback(timegroup, fromMs, _toMs) {
215
+ const firstChunkIndex = Math.floor(fromMs / this.chunkDurationMs);
216
+ const firstChunkStart = firstChunkIndex * this.chunkDurationMs;
217
+ const offsetInChunk = fromMs - firstChunkStart;
218
+ await this.renderAndScheduleChunk(timegroup, firstChunkStart, firstChunkIndex, offsetInChunk);
219
+ }
220
+ /**
221
+ * Render and schedule a single audio chunk
222
+ */
223
+ async renderAndScheduleChunk(timegroup, chunkStartMs, chunkIndex, offsetInChunk = 0) {
224
+ if (this.renderingChunks.has(chunkIndex) || this.activeChunks.has(chunkIndex)) return;
225
+ this.renderingChunks.add(chunkIndex);
226
+ try {
227
+ const chunkEndMs = chunkStartMs + this.chunkDurationMs;
228
+ const chunkBuffer = await timegroup.renderAudio(chunkStartMs, chunkEndMs);
229
+ const bufferSource = this.playbackAudioContext?.createBufferSource();
230
+ if (!bufferSource || !this.playbackAudioContext?.destination) throw new Error("Audio context or buffer source not available");
231
+ bufferSource.buffer = chunkBuffer;
232
+ bufferSource.connect(this.playbackAudioContext.destination);
233
+ const chunkTimelineStartMs = chunkIndex * this.chunkDurationMs;
234
+ const relativeDelayMs = Math.max(0, chunkTimelineStartMs - this.playbackStartTimeMs);
235
+ const chunkStartTime = this.audioStartTime + relativeDelayMs / 1e3;
236
+ const startOffset = offsetInChunk / 1e3;
237
+ const now = this.playbackAudioContext?.currentTime ?? 0;
238
+ if (chunkStartTime <= now) console.warn(`🎵 [CHUNK_TIMING_WARNING] Chunk ${chunkIndex} scheduled in the past! startTime=${chunkStartTime.toFixed(3)}s, currentTime=${now.toFixed(3)}s`);
239
+ bufferSource.start(chunkStartTime, startOffset);
240
+ this.activeChunks.set(chunkIndex, bufferSource);
241
+ bufferSource.onended = () => {
242
+ this.activeChunks.delete(chunkIndex);
243
+ };
244
+ } catch (error) {
245
+ console.error(`🎵 [CHUNK_ERROR] Failed to render chunk ${chunkIndex}:`, error);
246
+ } finally {
247
+ this.renderingChunks.delete(chunkIndex);
248
+ }
249
+ }
250
+ /**
251
+ * Update chunk rendering as playhead advances - now handles all chunk management
252
+ */
253
+ updateProgressiveChunks(timegroup, currentTimeMs, maxTimeMs) {
254
+ const newChunkIndex = Math.floor(currentTimeMs / this.chunkDurationMs);
255
+ if (newChunkIndex !== this.currentChunkIndex) {
256
+ this.currentChunkIndex = newChunkIndex;
257
+ this.cleanupOldChunks();
258
+ }
259
+ this.ensureChunksAhead(timegroup, maxTimeMs);
260
+ }
261
+ /**
262
+ * Systematically ensure chunks are ready ahead of current playback (synchronous)
263
+ */
264
+ ensureChunksAhead(timegroup, maxTimeMs) {
265
+ for (let i = 1; i <= this.lookaheadChunks; i++) {
266
+ const targetChunkIndex = this.currentChunkIndex + i;
267
+ const targetChunkStartMs = targetChunkIndex * this.chunkDurationMs;
268
+ if (targetChunkStartMs >= maxTimeMs) break;
269
+ if (!this.renderingChunks.has(targetChunkIndex) && !this.activeChunks.has(targetChunkIndex)) {
270
+ const offsetInChunk = 0;
271
+ this.renderAndScheduleChunk(timegroup, targetChunkStartMs, targetChunkIndex, offsetInChunk).catch((error) => {
272
+ console.error(`🎵 [ENSURE_CHUNKS_ERROR] Failed to render chunk ${targetChunkIndex}:`, error);
273
+ });
274
+ }
275
+ }
276
+ }
277
+ /**
278
+ * Clean up chunks that are behind the current playhead
279
+ */
280
+ cleanupOldChunks() {
281
+ const cutoffChunkIndex = this.currentChunkIndex - 1;
282
+ for (const [chunkIndex, bufferSource] of this.activeChunks.entries()) if (chunkIndex < cutoffChunkIndex) {
283
+ try {
284
+ bufferSource.stop();
285
+ } catch (_error) {}
286
+ this.activeChunks.delete(chunkIndex);
287
+ }
288
+ }
289
+ };
290
+ export { PlaybackController };