@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.
- package/dist/EF_FRAMEGEN.js +1 -1
- package/dist/ScrubTrackManager.d.ts +2 -2
- package/dist/elements/EFAudio.d.ts +21 -2
- package/dist/elements/EFAudio.js +41 -11
- package/dist/elements/EFImage.d.ts +1 -0
- package/dist/elements/EFImage.js +11 -3
- package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +18 -0
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +41 -0
- package/dist/elements/EFMedia/AssetMediaEngine.d.ts +47 -0
- package/dist/elements/EFMedia/AssetMediaEngine.js +116 -0
- package/dist/elements/EFMedia/BaseMediaEngine.d.ts +55 -0
- package/dist/elements/EFMedia/BaseMediaEngine.js +96 -0
- package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +43 -0
- package/dist/elements/EFMedia/BufferedSeekingInput.js +159 -0
- package/dist/elements/EFMedia/JitMediaEngine.browsertest.d.ts +0 -0
- package/dist/elements/EFMedia/JitMediaEngine.d.ts +31 -0
- package/dist/elements/EFMedia/JitMediaEngine.js +62 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +16 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +48 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +138 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +16 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +22 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.d.ts +7 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +24 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +18 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.d.ts +4 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +16 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.d.ts +3 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +104 -0
- package/dist/elements/EFMedia/services/AudioElementFactory.d.ts +22 -0
- package/dist/elements/EFMedia/services/AudioElementFactory.js +72 -0
- package/dist/elements/EFMedia/services/MediaSourceService.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia/services/MediaSourceService.d.ts +47 -0
- package/dist/elements/EFMedia/services/MediaSourceService.js +73 -0
- package/dist/elements/EFMedia/shared/AudioSpanUtils.d.ts +7 -0
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +54 -0
- package/dist/elements/EFMedia/shared/BufferUtils.d.ts +70 -0
- package/dist/elements/EFMedia/shared/BufferUtils.js +89 -0
- package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +23 -0
- package/dist/elements/EFMedia/shared/RenditionHelpers.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia/shared/RenditionHelpers.d.ts +19 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.d.ts +18 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +60 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.test.d.ts +1 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +16 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +46 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.js +16 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.d.ts +3 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.js +27 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.d.ts +7 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +25 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +18 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.d.ts +9 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.js +16 -0
- package/dist/elements/EFMedia.browsertest.d.ts +1 -0
- package/dist/elements/EFMedia.d.ts +75 -111
- package/dist/elements/EFMedia.js +141 -1111
- package/dist/elements/EFTemporal.d.ts +1 -1
- package/dist/elements/EFTemporal.js +1 -1
- package/dist/elements/EFTimegroup.d.ts +11 -0
- package/dist/elements/EFTimegroup.js +88 -13
- package/dist/elements/EFVideo.d.ts +60 -29
- package/dist/elements/EFVideo.js +103 -203
- package/dist/elements/EFWaveform.js +2 -2
- package/dist/elements/SampleBuffer.d.ts +14 -0
- package/dist/elements/SampleBuffer.js +52 -0
- package/dist/getRenderInfo.d.ts +2 -2
- package/dist/getRenderInfo.js +2 -1
- package/dist/gui/ContextMixin.js +17 -70
- package/dist/gui/EFFilmstrip.d.ts +3 -3
- package/dist/gui/EFFilmstrip.js +1 -1
- package/dist/gui/EFFitScale.d.ts +2 -2
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/services/ElementConnectionManager.browsertest.d.ts +1 -0
- package/dist/gui/services/ElementConnectionManager.d.ts +59 -0
- package/dist/gui/services/ElementConnectionManager.js +128 -0
- package/dist/gui/services/PlaybackController.browsertest.d.ts +1 -0
- package/dist/gui/services/PlaybackController.d.ts +103 -0
- package/dist/gui/services/PlaybackController.js +290 -0
- package/dist/services/MediaSourceManager.d.ts +62 -0
- package/dist/services/MediaSourceManager.js +211 -0
- package/dist/style.css +1 -1
- package/dist/transcoding/cache/CacheManager.d.ts +73 -0
- package/dist/transcoding/cache/RequestDeduplicator.d.ts +29 -0
- package/dist/transcoding/cache/RequestDeduplicator.js +53 -0
- package/dist/transcoding/cache/RequestDeduplicator.test.d.ts +1 -0
- package/dist/transcoding/types/index.d.ts +242 -0
- package/dist/transcoding/utils/MediaUtils.d.ts +9 -0
- package/dist/transcoding/utils/UrlGenerator.d.ts +26 -0
- package/dist/transcoding/utils/UrlGenerator.js +45 -0
- package/dist/transcoding/utils/constants.d.ts +27 -0
- package/dist/utils/LRUCache.d.ts +34 -0
- package/dist/utils/LRUCache.js +115 -0
- package/package.json +3 -2
- package/src/elements/EFAudio.browsertest.ts +183 -43
- package/src/elements/EFAudio.ts +59 -13
- package/src/elements/EFImage.browsertest.ts +42 -0
- package/src/elements/EFImage.ts +23 -3
- package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +222 -0
- package/src/elements/EFMedia/AssetIdMediaEngine.ts +70 -0
- package/src/elements/EFMedia/AssetMediaEngine.ts +210 -0
- package/src/elements/EFMedia/BaseMediaEngine.test.ts +164 -0
- package/src/elements/EFMedia/BaseMediaEngine.ts +170 -0
- package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +400 -0
- package/src/elements/EFMedia/BufferedSeekingInput.ts +267 -0
- package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +165 -0
- package/src/elements/EFMedia/JitMediaEngine.ts +110 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +554 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +81 -0
- package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +241 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +59 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +23 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +55 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +35 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +42 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +34 -0
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +23 -0
- package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +174 -0
- package/src/elements/EFMedia/services/AudioElementFactory.browsertest.ts +325 -0
- package/src/elements/EFMedia/services/AudioElementFactory.ts +119 -0
- package/src/elements/EFMedia/services/MediaSourceService.browsertest.ts +257 -0
- package/src/elements/EFMedia/services/MediaSourceService.ts +102 -0
- package/src/elements/EFMedia/shared/AudioSpanUtils.ts +128 -0
- package/src/elements/EFMedia/shared/BufferUtils.ts +310 -0
- package/src/elements/EFMedia/shared/MediaTaskUtils.ts +44 -0
- package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +247 -0
- package/src/elements/EFMedia/shared/RenditionHelpers.ts +79 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +128 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.test.ts +233 -0
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +89 -0
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.ts +555 -0
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +79 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.ts +59 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts +23 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.ts +55 -0
- package/src/elements/EFMedia/videoTasks/makeVideoInputTask.ts +45 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +44 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.ts +57 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +32 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.ts +56 -0
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.ts +23 -0
- package/src/elements/EFMedia.browsertest.ts +658 -265
- package/src/elements/EFMedia.ts +173 -1763
- package/src/elements/EFTemporal.ts +3 -4
- package/src/elements/EFTimegroup.browsertest.ts +6 -3
- package/src/elements/EFTimegroup.ts +152 -21
- package/src/elements/EFVideo.browsertest.ts +115 -37
- package/src/elements/EFVideo.ts +123 -452
- package/src/elements/EFWaveform.ts +1 -1
- package/src/elements/MediaController.ts +2 -12
- package/src/elements/SampleBuffer.ts +97 -0
- package/src/gui/ContextMixin.ts +23 -104
- package/src/gui/services/ElementConnectionManager.browsertest.ts +263 -0
- package/src/gui/services/ElementConnectionManager.ts +224 -0
- package/src/gui/services/PlaybackController.browsertest.ts +437 -0
- package/src/gui/services/PlaybackController.ts +521 -0
- package/src/services/MediaSourceManager.ts +333 -0
- package/src/transcoding/cache/CacheManager.ts +208 -0
- package/src/transcoding/cache/RequestDeduplicator.test.ts +170 -0
- package/src/transcoding/cache/RequestDeduplicator.ts +65 -0
- package/src/transcoding/types/index.ts +265 -0
- package/src/transcoding/utils/MediaUtils.ts +63 -0
- package/src/transcoding/utils/UrlGenerator.ts +68 -0
- package/src/transcoding/utils/constants.ts +36 -0
- package/src/utils/LRUCache.ts +153 -0
- package/test/EFVideo.framegen.browsertest.ts +38 -29
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -0
- package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +19 -0
- package/test/createJitTestClips.ts +320 -188
- package/test/recordReplayProxyPlugin.js +302 -0
- package/test/useAssetMSW.ts +1 -1
- package/test/useMSW.ts +35 -22
- package/types.json +1 -1
- package/dist/JitTranscodingClient.d.ts +0 -167
- package/dist/JitTranscodingClient.js +0 -373
- package/dist/ScrubTrackManager.js +0 -216
- package/dist/elements/printTaskStatus.js +0 -11
- package/src/elements/__screenshots__/EFMedia.browsertest.ts/EFMedia-JIT-audio-playback-audioBufferTask-should-work-in-JIT-mode-without-URL-errors-1.png +0 -0
- package/test/EFVideo.frame-tasks.browsertest.ts +0 -524
- /package/dist/{JitTranscodingClient.browsertest.d.ts → elements/EFMedia/AssetIdMediaEngine.test.d.ts} +0 -0
- /package/dist/{JitTranscodingClient.test.d.ts → elements/EFMedia/BaseMediaEngine.test.d.ts} +0 -0
- /package/dist/{ScrubTrackIntegration.test.d.ts → elements/EFMedia/BufferedSeekingInput.browsertest.d.ts} +0 -0
- /package/dist/{SegmentSwitchLoading.test.d.ts → elements/EFMedia/services/AudioElementFactory.browsertest.d.ts} +0 -0
|
@@ -1,15 +1,37 @@
|
|
|
1
|
+
import { css } from "lit";
|
|
1
2
|
import { customElement } from "lit/decorators.js";
|
|
2
|
-
import {
|
|
3
|
-
import { afterEach, beforeEach, describe,
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import type { VideoSample } from "mediabunny";
|
|
4
|
+
import { afterEach, beforeEach, describe, vi } from "vitest";
|
|
5
|
+
import { test as baseTest } from "../../test/useMSW.js";
|
|
6
|
+
|
|
7
|
+
import type { EFConfiguration } from "../gui/EFConfiguration.js";
|
|
6
8
|
import "../gui/EFPreview.js";
|
|
9
|
+
import "../gui/EFWorkbench.js";
|
|
10
|
+
import { JitMediaEngine } from "./EFMedia/JitMediaEngine.js";
|
|
11
|
+
import { EFMedia } from "./EFMedia.js";
|
|
7
12
|
import "./EFTimegroup.js";
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
13
|
+
import type { EFTimegroup } from "./EFTimegroup.js";
|
|
14
|
+
import "./EFVideo.js";
|
|
15
|
+
import { UrlGenerator } from "../transcoding/utils/UrlGenerator.js";
|
|
16
|
+
import type { EFVideo } from "./EFVideo.js";
|
|
10
17
|
|
|
11
18
|
@customElement("test-media")
|
|
12
|
-
class TestMedia extends EFMedia {
|
|
19
|
+
class TestMedia extends EFMedia {
|
|
20
|
+
static styles = [
|
|
21
|
+
...EFMedia.styles,
|
|
22
|
+
css`
|
|
23
|
+
:host {
|
|
24
|
+
display: block;
|
|
25
|
+
width: 100%;
|
|
26
|
+
height: 100%;
|
|
27
|
+
}
|
|
28
|
+
video {
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 100%;
|
|
31
|
+
}
|
|
32
|
+
`,
|
|
33
|
+
];
|
|
34
|
+
}
|
|
13
35
|
|
|
14
36
|
declare global {
|
|
15
37
|
interface HTMLElementTagNameMap {
|
|
@@ -17,17 +39,145 @@ declare global {
|
|
|
17
39
|
}
|
|
18
40
|
}
|
|
19
41
|
|
|
20
|
-
|
|
21
|
-
|
|
42
|
+
const test = baseTest.extend<{
|
|
43
|
+
timegroup: EFTimegroup;
|
|
44
|
+
jitVideo: EFVideo;
|
|
45
|
+
configuration: EFConfiguration;
|
|
46
|
+
urlGenerator: UrlGenerator;
|
|
47
|
+
host: EFVideo;
|
|
48
|
+
}>({
|
|
49
|
+
timegroup: async ({}, use) => {
|
|
50
|
+
const timegroup = document.createElement("ef-timegroup");
|
|
51
|
+
timegroup.setAttribute("mode", "contain");
|
|
52
|
+
await use(timegroup);
|
|
53
|
+
},
|
|
54
|
+
configuration: async ({ expect }, use) => {
|
|
55
|
+
const configuration = document.createElement("ef-configuration");
|
|
56
|
+
configuration.innerHTML = `<h1 style="font: 10px monospace">${expect.getState().currentTestName}</h1>`;
|
|
57
|
+
// Use integrated proxy server (same host/port as test runner)
|
|
58
|
+
const apiHost = `${window.location.protocol}//${window.location.host}`;
|
|
59
|
+
configuration.setAttribute("api-host", apiHost);
|
|
60
|
+
configuration.apiHost = apiHost;
|
|
61
|
+
document.body.appendChild(configuration);
|
|
62
|
+
await use(configuration);
|
|
63
|
+
// configuration.remove();
|
|
64
|
+
},
|
|
65
|
+
urlGenerator: async ({}, use) => {
|
|
66
|
+
// UrlGenerator points to integrated proxy server (same host/port as test runner)
|
|
67
|
+
const apiHost = `${window.location.protocol}//${window.location.host}`;
|
|
68
|
+
const generator = new UrlGenerator(() => apiHost);
|
|
69
|
+
await use(generator);
|
|
70
|
+
},
|
|
71
|
+
host: async ({ configuration }, use) => {
|
|
72
|
+
const host = document.createElement("ef-video");
|
|
73
|
+
configuration.appendChild(host);
|
|
74
|
+
host.src = "http://web:3000/head-moov-480p.mp4";
|
|
75
|
+
await use(host);
|
|
76
|
+
},
|
|
77
|
+
jitVideo: async ({ configuration, timegroup, host }, use) => {
|
|
78
|
+
timegroup.append(host);
|
|
79
|
+
configuration.append(timegroup);
|
|
80
|
+
await host.mediaEngineTask.run();
|
|
81
|
+
await use(host);
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe("JIT Media Engine", () => {
|
|
86
|
+
test("initializes JitMediaEngine", async ({ jitVideo, expect }) => {
|
|
87
|
+
const mediaEngine = jitVideo.mediaEngineTask.value;
|
|
88
|
+
expect(mediaEngine).toBeInstanceOf(JitMediaEngine);
|
|
89
|
+
});
|
|
22
90
|
|
|
91
|
+
test("loads media duration", async ({ jitVideo, expect }) => {
|
|
92
|
+
expect(jitVideo.intrinsicDurationMs).toBe(10_000);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("video seek on load", () => {
|
|
96
|
+
test("seeks to time specified on element", async ({
|
|
97
|
+
configuration,
|
|
98
|
+
expect,
|
|
99
|
+
timegroup,
|
|
100
|
+
}) => {
|
|
101
|
+
const element = document.createElement("ef-video");
|
|
102
|
+
element.src = "http://web:3000/head-moov-480p.mp4";
|
|
103
|
+
timegroup.append(element);
|
|
104
|
+
configuration.append(timegroup);
|
|
105
|
+
|
|
106
|
+
// Initialize media engine first
|
|
107
|
+
await element.mediaEngineTask.run();
|
|
108
|
+
await element.videoSegmentIdTask.run();
|
|
109
|
+
|
|
110
|
+
// Then set the time - this should trigger proper synchronization
|
|
111
|
+
timegroup.currentTimeMs = 2200;
|
|
112
|
+
element.desiredSeekTimeMs = 2200;
|
|
113
|
+
|
|
114
|
+
const sample = await element.videoSeekTask.taskComplete;
|
|
115
|
+
|
|
116
|
+
expect(sample).toBeDefined();
|
|
117
|
+
expect(sample?.timestamp).toEqual(2.2);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("video seeking", () => {
|
|
122
|
+
test("seeks to 0 seconds and loads first frame", async ({
|
|
123
|
+
timegroup,
|
|
124
|
+
jitVideo,
|
|
125
|
+
expect,
|
|
126
|
+
}) => {
|
|
127
|
+
timegroup.currentTimeMs = 0;
|
|
128
|
+
const frame = await (jitVideo as any).videoSeekTask.taskComplete;
|
|
129
|
+
expect(frame).toBeDefined();
|
|
130
|
+
expect(frame?.timestamp).toEqual(0);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("seeks to 3 seconds and loads frame", async ({
|
|
134
|
+
timegroup,
|
|
135
|
+
jitVideo,
|
|
136
|
+
expect,
|
|
137
|
+
}) => {
|
|
138
|
+
timegroup.currentTimeMs = 3_000;
|
|
139
|
+
jitVideo.desiredSeekTimeMs = 3_000;
|
|
140
|
+
const frame = await (jitVideo as any).videoSeekTask.taskComplete;
|
|
141
|
+
expect(frame).toBeDefined();
|
|
142
|
+
expect(frame?.timestamp).toEqual(3);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("seeks to 5 seconds and loads frame", async ({
|
|
146
|
+
timegroup,
|
|
147
|
+
jitVideo,
|
|
148
|
+
expect,
|
|
149
|
+
}) => {
|
|
150
|
+
timegroup.currentTimeMs = 5_000;
|
|
151
|
+
jitVideo.desiredSeekTimeMs = 5_000;
|
|
152
|
+
const frame = await (jitVideo as any).videoSeekTask.taskComplete;
|
|
153
|
+
expect(frame).toBeDefined();
|
|
154
|
+
expect(frame?.timestamp).toEqual(5);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("seeks ahead in 50ms increments", async ({
|
|
158
|
+
timegroup,
|
|
159
|
+
jitVideo,
|
|
160
|
+
expect,
|
|
161
|
+
}) => {
|
|
162
|
+
timegroup.currentTimeMs = 0;
|
|
163
|
+
let frame: VideoSample | undefined;
|
|
164
|
+
for (let i = 0; i <= 3000; i += 50) {
|
|
165
|
+
timegroup.currentTimeMs = i;
|
|
166
|
+
jitVideo.desiredSeekTimeMs = i;
|
|
167
|
+
frame = await (jitVideo as any).videoSeekTask.taskComplete;
|
|
168
|
+
expect(frame).toBeDefined();
|
|
169
|
+
}
|
|
170
|
+
expect(frame?.timestamp).toEqual(3);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe("EFMedia", () => {
|
|
23
176
|
beforeEach(() => {
|
|
24
177
|
// Clean up DOM
|
|
25
178
|
while (document.body.children.length) {
|
|
26
179
|
document.body.children[0]?.remove();
|
|
27
180
|
}
|
|
28
|
-
|
|
29
|
-
// Set up MSW handlers to proxy requests to test assets
|
|
30
|
-
worker.use(...assetMSWHandlers);
|
|
31
181
|
});
|
|
32
182
|
|
|
33
183
|
afterEach(() => {
|
|
@@ -38,325 +188,568 @@ describe("EFMedia", () => {
|
|
|
38
188
|
}
|
|
39
189
|
});
|
|
40
190
|
|
|
41
|
-
test
|
|
42
|
-
|
|
191
|
+
const test = baseTest.extend<{
|
|
192
|
+
element: TestMedia;
|
|
193
|
+
}>({
|
|
194
|
+
element: async ({}, use) => {
|
|
195
|
+
const element = document.createElement("test-media");
|
|
196
|
+
document.body.appendChild(element);
|
|
197
|
+
await use(element);
|
|
198
|
+
element.remove();
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test("should be defined", ({ element, expect }) => {
|
|
43
203
|
expect(element.tagName).toBe("TEST-MEDIA");
|
|
44
204
|
});
|
|
45
205
|
|
|
46
|
-
describe("
|
|
47
|
-
test("
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
element.mode = "auto";
|
|
206
|
+
describe("mute", () => {
|
|
207
|
+
test("defaults to false", ({ element, expect }) => {
|
|
208
|
+
expect(element.mute).toBe(false);
|
|
209
|
+
});
|
|
51
210
|
|
|
52
|
-
|
|
211
|
+
test("reads from js property", ({ element, expect }) => {
|
|
212
|
+
element.mute = true;
|
|
213
|
+
expect(element.mute).toBe(true);
|
|
53
214
|
});
|
|
54
215
|
|
|
55
|
-
test("
|
|
56
|
-
|
|
57
|
-
element.
|
|
58
|
-
|
|
216
|
+
test("reads from dom attribute", ({ element, expect }) => {
|
|
217
|
+
element.setAttribute("mute", "true");
|
|
218
|
+
expect(element.mute).toBe(true);
|
|
219
|
+
});
|
|
59
220
|
|
|
60
|
-
|
|
221
|
+
test("handles any attribute value as true (standard boolean behavior)", ({
|
|
222
|
+
element,
|
|
223
|
+
expect,
|
|
224
|
+
}) => {
|
|
225
|
+
element.setAttribute("mute", "false");
|
|
226
|
+
expect(element.mute).toBe(true); // Standard boolean attributes: any value = true
|
|
61
227
|
});
|
|
62
|
-
});
|
|
63
228
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
229
|
+
test("reflects property changes to attribute", async ({
|
|
230
|
+
element,
|
|
231
|
+
expect,
|
|
232
|
+
}) => {
|
|
233
|
+
element.mute = true;
|
|
234
|
+
await element.updateComplete; // Wait for Lit to update
|
|
235
|
+
expect(element.hasAttribute("mute")).toBe(true);
|
|
236
|
+
expect(element.getAttribute("mute")).toBe(""); // Standard boolean reflection
|
|
237
|
+
|
|
238
|
+
element.mute = false;
|
|
239
|
+
await element.updateComplete; // Wait for Lit to update
|
|
240
|
+
expect(element.hasAttribute("mute")).toBe(false); // Standard boolean reflection removes attribute
|
|
241
|
+
});
|
|
70
242
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
243
|
+
describe("audio rendering", () => {
|
|
244
|
+
// Create a separate test context for audio rendering tests that need configuration
|
|
245
|
+
const audioTest = baseTest.extend<{
|
|
246
|
+
timegroup: EFTimegroup;
|
|
247
|
+
configuration: EFConfiguration;
|
|
248
|
+
}>({
|
|
249
|
+
timegroup: async ({}, use) => {
|
|
250
|
+
const timegroup = document.createElement("ef-timegroup");
|
|
251
|
+
timegroup.setAttribute("mode", "contain");
|
|
252
|
+
await use(timegroup);
|
|
253
|
+
},
|
|
254
|
+
configuration: async ({ expect }, use) => {
|
|
255
|
+
const configuration = document.createElement("ef-configuration");
|
|
256
|
+
configuration.innerHTML = `<h1 style="font: 10px monospace">${expect.getState().currentTestName}</h1>`;
|
|
257
|
+
// Use integrated proxy server (same host/port as test runner)
|
|
258
|
+
const apiHost = `${window.location.protocol}//${window.location.host}`;
|
|
259
|
+
configuration.setAttribute("api-host", apiHost);
|
|
260
|
+
configuration.apiHost = apiHost;
|
|
261
|
+
document.body.appendChild(configuration);
|
|
262
|
+
await use(configuration);
|
|
263
|
+
// configuration.remove();
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
audioTest(
|
|
268
|
+
"skips muted elements during audio rendering",
|
|
269
|
+
async ({ configuration, timegroup, expect }) => {
|
|
270
|
+
// Create a muted media element
|
|
271
|
+
const mutedElement = document.createElement("test-media");
|
|
272
|
+
mutedElement.src = "http://web:3000/head-moov-480p.mp4";
|
|
273
|
+
mutedElement.mute = true;
|
|
274
|
+
timegroup.append(mutedElement);
|
|
275
|
+
|
|
276
|
+
// Create an unmuted media element
|
|
277
|
+
const unmutedElement = document.createElement("test-media");
|
|
278
|
+
unmutedElement.src = "http://web:3000/head-moov-480p.mp4";
|
|
279
|
+
unmutedElement.mute = false;
|
|
280
|
+
timegroup.append(unmutedElement);
|
|
281
|
+
|
|
282
|
+
configuration.append(timegroup);
|
|
283
|
+
|
|
284
|
+
// Wait for media engines to initialize
|
|
285
|
+
await mutedElement.mediaEngineTask.run();
|
|
286
|
+
await unmutedElement.mediaEngineTask.run();
|
|
287
|
+
|
|
288
|
+
// Spy on fetchAudioSpanningTime to verify muted element is skipped
|
|
289
|
+
const mutedFetchSpy = vi.spyOn(
|
|
290
|
+
mutedElement,
|
|
291
|
+
"fetchAudioSpanningTime",
|
|
292
|
+
);
|
|
293
|
+
const unmutedFetchSpy = vi.spyOn(
|
|
294
|
+
unmutedElement,
|
|
295
|
+
"fetchAudioSpanningTime",
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
// Render a short audio segment
|
|
299
|
+
try {
|
|
300
|
+
await timegroup.renderAudio(0, 1000); // 1 second
|
|
301
|
+
} catch (error) {
|
|
302
|
+
// Audio rendering might fail in test environment, but we're testing the mute logic
|
|
303
|
+
console.log("Audio rendering failed (expected in test):", error);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Verify muted element was skipped (no fetch calls)
|
|
307
|
+
expect(mutedFetchSpy).not.toHaveBeenCalled();
|
|
308
|
+
|
|
309
|
+
// Verify unmuted element was processed (would have fetch calls if audio succeeds)
|
|
310
|
+
// Note: In test environment, this might still be 0 due to audio context limitations
|
|
311
|
+
// but the important thing is that muted element definitely wasn't called
|
|
312
|
+
const mutedCalls = mutedFetchSpy.mock.calls.length;
|
|
313
|
+
const unmutedCalls = unmutedFetchSpy.mock.calls.length;
|
|
314
|
+
|
|
315
|
+
expect(mutedCalls).toBe(0);
|
|
316
|
+
// Unmuted element should either be called (audio works) or both fail equally
|
|
317
|
+
// The key test is that muted=0 and muted < unmuted (if audio works)
|
|
318
|
+
expect(mutedCalls).toBeLessThanOrEqual(unmutedCalls);
|
|
319
|
+
|
|
320
|
+
mutedFetchSpy.mockRestore();
|
|
321
|
+
unmutedFetchSpy.mockRestore();
|
|
322
|
+
},
|
|
323
|
+
);
|
|
75
324
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
325
|
+
audioTest(
|
|
326
|
+
"processes unmuted elements normally",
|
|
327
|
+
async ({ configuration, timegroup, expect }) => {
|
|
328
|
+
// Create an unmuted media element
|
|
329
|
+
const element = document.createElement("test-media");
|
|
330
|
+
element.src = "http://web:3000/head-moov-480p.mp4";
|
|
331
|
+
element.mute = false;
|
|
332
|
+
timegroup.append(element);
|
|
79
333
|
|
|
80
|
-
|
|
81
|
-
expect(audioBuffer).toBeDefined();
|
|
82
|
-
expect(audioBuffer?.buffer).toBeDefined();
|
|
83
|
-
expect(audioBuffer?.startOffsetMs).toBeGreaterThanOrEqual(0);
|
|
84
|
-
},
|
|
85
|
-
);
|
|
334
|
+
configuration.append(timegroup);
|
|
86
335
|
|
|
87
|
-
|
|
88
|
-
const element = document.createElement("test-media");
|
|
89
|
-
document.body.appendChild(element);
|
|
336
|
+
await element.mediaEngineTask.run();
|
|
90
337
|
|
|
91
|
-
|
|
92
|
-
element.src = "http://web:3000/tail-moov-1080p.mp4";
|
|
93
|
-
element.mode = "jit-transcode";
|
|
338
|
+
const fetchSpy = vi.spyOn(element, "fetchAudioSpanningTime");
|
|
94
339
|
|
|
95
|
-
|
|
96
|
-
|
|
340
|
+
try {
|
|
341
|
+
await timegroup.renderAudio(0, 1000);
|
|
342
|
+
} catch (error) {
|
|
343
|
+
// Audio rendering might fail in test environment
|
|
344
|
+
console.log("Audio rendering failed (expected in test):", error);
|
|
345
|
+
}
|
|
97
346
|
|
|
98
|
-
|
|
99
|
-
|
|
347
|
+
// The element should not have been skipped due to mute
|
|
348
|
+
// (whether it actually gets called depends on test environment audio support)
|
|
349
|
+
expect(element.mute).toBe(false);
|
|
100
350
|
|
|
101
|
-
|
|
102
|
-
|
|
351
|
+
fetchSpy.mockRestore();
|
|
352
|
+
},
|
|
353
|
+
);
|
|
103
354
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
355
|
+
audioTest(
|
|
356
|
+
"handles dynamic mute changes",
|
|
357
|
+
async ({ configuration, timegroup, expect }) => {
|
|
358
|
+
const element = document.createElement("test-media");
|
|
359
|
+
element.src = "http://web:3000/head-moov-480p.mp4";
|
|
360
|
+
element.mute = false; // Start unmuted
|
|
361
|
+
timegroup.append(element);
|
|
110
362
|
|
|
111
|
-
|
|
112
|
-
const element = document.createElement("test-media");
|
|
113
|
-
const preview = document.createElement("ef-preview");
|
|
114
|
-
preview.appendChild(element);
|
|
115
|
-
document.body.appendChild(preview);
|
|
363
|
+
configuration.append(timegroup);
|
|
116
364
|
|
|
117
|
-
|
|
118
|
-
element.assetId = "test-asset-123";
|
|
119
|
-
element.mode = "asset";
|
|
120
|
-
element.src = "/test-assets/media/bars-n-tone2.mp4";
|
|
121
|
-
|
|
122
|
-
// Wait for fragment index to load
|
|
123
|
-
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
124
|
-
|
|
125
|
-
// Asset mode should work fine (this is our baseline)
|
|
126
|
-
try {
|
|
127
|
-
const audioData = await element.fetchAudioSpanningTime(0, 2000);
|
|
128
|
-
expect(audioData).toBeDefined();
|
|
129
|
-
} catch (error) {
|
|
130
|
-
// Audio data might not be available in test environment, but should not throw URL errors
|
|
131
|
-
expect(String(error)).not.toMatch(/URL/);
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
});
|
|
365
|
+
await element.mediaEngineTask.run();
|
|
135
366
|
|
|
136
|
-
|
|
137
|
-
beforeEach(() => {
|
|
138
|
-
// @ts-expect-error
|
|
139
|
-
window.FRAMEGEN_BRIDGE = true;
|
|
140
|
-
});
|
|
141
|
-
afterEach(() => {
|
|
142
|
-
delete window.FRAMEGEN_BRIDGE;
|
|
143
|
-
});
|
|
367
|
+
const fetchSpy = vi.spyOn(element, "fetchAudioSpanningTime");
|
|
144
368
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
"https://editframe.dev/api/v1/isobmff_files/550e8400-e29b-41d4-a716-446655440000:example.mp4/index",
|
|
152
|
-
);
|
|
153
|
-
});
|
|
369
|
+
// First render - unmuted
|
|
370
|
+
try {
|
|
371
|
+
await timegroup.renderAudio(0, 500);
|
|
372
|
+
} catch (error) {
|
|
373
|
+
console.log("Audio rendering failed (expected in test):", error);
|
|
374
|
+
}
|
|
154
375
|
|
|
155
|
-
|
|
156
|
-
const workbench = document.createElement("ef-workbench");
|
|
157
|
-
const element = document.createElement("test-media");
|
|
158
|
-
workbench.appendChild(element);
|
|
159
|
-
element.assetId = "550e8400-e29b-41d4-a716-446655440000:example.mp4";
|
|
160
|
-
expect(element.fragmentTrackPath("1")).toBe(
|
|
161
|
-
"https://editframe.dev/api/v1/isobmff_tracks/550e8400-e29b-41d4-a716-446655440000:example.mp4/1",
|
|
162
|
-
);
|
|
163
|
-
});
|
|
164
|
-
});
|
|
376
|
+
const firstCallCount = fetchSpy.mock.calls.length;
|
|
165
377
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const element = document.createElement("test-media");
|
|
170
|
-
element.setAttribute("asset-id", id);
|
|
171
|
-
expect(element.fragmentIndexPath()).toBe(
|
|
172
|
-
`https://editframe.dev/api/v1/isobmff_files/${id}/index`,
|
|
173
|
-
);
|
|
174
|
-
});
|
|
378
|
+
// Mute the element
|
|
379
|
+
element.mute = true;
|
|
380
|
+
await element.updateComplete;
|
|
175
381
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
);
|
|
183
|
-
});
|
|
382
|
+
// Second render - muted (should be skipped)
|
|
383
|
+
try {
|
|
384
|
+
await timegroup.renderAudio(500, 1000);
|
|
385
|
+
} catch (error) {
|
|
386
|
+
console.log("Audio rendering failed (expected in test):", error);
|
|
387
|
+
}
|
|
184
388
|
|
|
185
|
-
|
|
186
|
-
const id = v4();
|
|
187
|
-
const element = document.createElement("test-media");
|
|
188
|
-
element.setAttribute("asset-id", id);
|
|
189
|
-
const preview = document.createElement("ef-preview");
|
|
190
|
-
preview.appendChild(element);
|
|
191
|
-
preview.apiHost = "test://";
|
|
192
|
-
document.body.appendChild(preview);
|
|
193
|
-
expect(element.fragmentIndexPath()).toBe(
|
|
194
|
-
`test:///api/v1/isobmff_files/${id}/index`,
|
|
195
|
-
);
|
|
196
|
-
});
|
|
389
|
+
const secondCallCount = fetchSpy.mock.calls.length;
|
|
197
390
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
preview.appendChild(element);
|
|
204
|
-
preview.apiHost = "test://";
|
|
205
|
-
document.body.appendChild(preview);
|
|
206
|
-
expect(element.fragmentTrackPath("1")).toBe(
|
|
207
|
-
`test:///api/v1/isobmff_tracks/${id}/1`,
|
|
391
|
+
// Verify no additional calls were made when muted
|
|
392
|
+
expect(secondCallCount).toBe(firstCallCount);
|
|
393
|
+
|
|
394
|
+
fetchSpy.mockRestore();
|
|
395
|
+
},
|
|
208
396
|
);
|
|
209
397
|
});
|
|
210
398
|
});
|
|
211
399
|
|
|
212
|
-
describe("
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
400
|
+
describe("audio analysis", () => {
|
|
401
|
+
const audioAnalysisTest = baseTest.extend<{
|
|
402
|
+
timegroup: EFTimegroup;
|
|
403
|
+
configuration: EFConfiguration;
|
|
404
|
+
}>({
|
|
405
|
+
timegroup: async ({}, use) => {
|
|
406
|
+
const timegroup = document.createElement("ef-timegroup");
|
|
407
|
+
timegroup.setAttribute("mode", "contain");
|
|
408
|
+
await use(timegroup);
|
|
409
|
+
},
|
|
410
|
+
configuration: async ({ expect }, use) => {
|
|
411
|
+
const configuration = document.createElement("ef-configuration");
|
|
412
|
+
configuration.innerHTML = `<h1 style="font: 10px monospace">${expect.getState().currentTestName}</h1>`;
|
|
413
|
+
// Use integrated proxy server (same host/port as test runner)
|
|
414
|
+
const apiHost = `${window.location.protocol}//${window.location.host}`;
|
|
415
|
+
configuration.setAttribute("api-host", apiHost);
|
|
416
|
+
configuration.apiHost = apiHost;
|
|
417
|
+
document.body.appendChild(configuration);
|
|
418
|
+
await use(configuration);
|
|
419
|
+
},
|
|
229
420
|
});
|
|
230
421
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
timegroup
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
422
|
+
audioAnalysisTest(
|
|
423
|
+
"has time domain analysis task",
|
|
424
|
+
async ({ configuration, timegroup, expect }) => {
|
|
425
|
+
const element = document.createElement("test-media");
|
|
426
|
+
element.src = "http://web:3000/head-moov-480p.mp4";
|
|
427
|
+
timegroup.append(element);
|
|
428
|
+
configuration.append(timegroup);
|
|
237
429
|
|
|
238
|
-
|
|
239
|
-
timegroup.appendChild(element);
|
|
240
|
-
preview.appendChild(timegroup);
|
|
241
|
-
document.body.appendChild(preview);
|
|
430
|
+
await element.mediaEngineTask.run();
|
|
242
431
|
|
|
243
|
-
|
|
244
|
-
|
|
432
|
+
expect(element.byteTimeDomainTask).toBeDefined();
|
|
433
|
+
expect(typeof element.byteTimeDomainTask.taskComplete).toBe("object");
|
|
434
|
+
},
|
|
435
|
+
);
|
|
245
436
|
|
|
246
|
-
|
|
437
|
+
audioAnalysisTest(
|
|
438
|
+
"has frequency analysis task",
|
|
439
|
+
async ({ configuration, timegroup, expect }) => {
|
|
440
|
+
const element = document.createElement("test-media");
|
|
441
|
+
element.src = "http://web:3000/head-moov-480p.mp4";
|
|
442
|
+
timegroup.append(element);
|
|
443
|
+
configuration.append(timegroup);
|
|
247
444
|
|
|
248
|
-
|
|
249
|
-
expect(element.durationMs).toBeGreaterThan(8500);
|
|
250
|
-
expect(element.durationMs).toBeLessThan(9500);
|
|
251
|
-
expect(timegroup.durationMs).toBeGreaterThan(8500);
|
|
252
|
-
expect(timegroup.durationMs).toBeLessThan(9500);
|
|
253
|
-
});
|
|
445
|
+
await element.mediaEngineTask.run();
|
|
254
446
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
element.src = "/assets/10s-bars.mp4";
|
|
260
|
-
element.sourceInMs = 6_000;
|
|
447
|
+
expect(element.frequencyDataTask).toBeDefined();
|
|
448
|
+
expect(typeof element.frequencyDataTask.taskComplete).toBe("object");
|
|
449
|
+
},
|
|
450
|
+
);
|
|
261
451
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
452
|
+
audioAnalysisTest(
|
|
453
|
+
"respects FFT configuration properties",
|
|
454
|
+
async ({ configuration, timegroup, expect }) => {
|
|
455
|
+
const element = document.createElement("test-media");
|
|
456
|
+
element.src = "http://web:3000/head-moov-480p.mp4";
|
|
457
|
+
element.fftSize = 256;
|
|
458
|
+
element.fftDecay = 4;
|
|
459
|
+
element.fftGain = 2.0;
|
|
460
|
+
element.interpolateFrequencies = true;
|
|
461
|
+
timegroup.append(element);
|
|
462
|
+
configuration.append(timegroup);
|
|
463
|
+
|
|
464
|
+
await element.mediaEngineTask.run();
|
|
465
|
+
|
|
466
|
+
expect(element.fftSize).toBe(256);
|
|
467
|
+
expect(element.fftDecay).toBe(4);
|
|
468
|
+
expect(element.fftGain).toBe(2.0);
|
|
469
|
+
expect(element.interpolateFrequencies).toBe(true);
|
|
470
|
+
expect(element.shouldInterpolateFrequencies).toBe(true);
|
|
471
|
+
},
|
|
472
|
+
);
|
|
266
473
|
|
|
267
|
-
|
|
268
|
-
|
|
474
|
+
audioAnalysisTest(
|
|
475
|
+
"generates FREQ_WEIGHTS based on fftSize",
|
|
476
|
+
async ({ configuration, timegroup, expect }) => {
|
|
477
|
+
const element = document.createElement("test-media");
|
|
478
|
+
element.src = "http://web:3000/head-moov-480p.mp4";
|
|
479
|
+
element.fftSize = 128;
|
|
480
|
+
timegroup.append(element);
|
|
481
|
+
configuration.append(timegroup);
|
|
482
|
+
|
|
483
|
+
await element.mediaEngineTask.run();
|
|
484
|
+
|
|
485
|
+
const weights = element.FREQ_WEIGHTS;
|
|
486
|
+
expect(weights).toBeInstanceOf(Float32Array);
|
|
487
|
+
expect(weights.length).toBe(element.fftSize / 2); // 64 for fftSize 128
|
|
488
|
+
|
|
489
|
+
// Test frequency weighting - lower frequencies should have lower weights
|
|
490
|
+
expect(weights.length).toBeGreaterThan(0);
|
|
491
|
+
const firstWeight = weights[0];
|
|
492
|
+
const lastWeight = weights[weights.length - 1];
|
|
493
|
+
expect(firstWeight).toBeDefined();
|
|
494
|
+
expect(lastWeight).toBeDefined();
|
|
495
|
+
expect(firstWeight!).toBeLessThan(lastWeight!);
|
|
496
|
+
},
|
|
497
|
+
);
|
|
498
|
+
});
|
|
269
499
|
|
|
270
|
-
|
|
500
|
+
describe("assetId", () => {
|
|
501
|
+
test("reads from js property", ({ element, expect }) => {
|
|
502
|
+
element.assetId = "test-asset-123";
|
|
503
|
+
expect(element.assetId).toBe("test-asset-123");
|
|
504
|
+
});
|
|
271
505
|
|
|
272
|
-
|
|
273
|
-
|
|
506
|
+
test("reads from dom attribute", ({ element, expect }) => {
|
|
507
|
+
element.setAttribute("asset-id", "test-asset-123");
|
|
508
|
+
expect(element.assetId).toBe("test-asset-123");
|
|
274
509
|
});
|
|
275
510
|
|
|
276
|
-
test("
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const element = document.createElement("test-media");
|
|
280
|
-
element.src = "/assets/10s-bars.mp4";
|
|
281
|
-
element.sourceOutMs = 6_000;
|
|
511
|
+
test("defaults to null", ({ element, expect }) => {
|
|
512
|
+
expect(element.assetId).toBe(null);
|
|
513
|
+
});
|
|
282
514
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
515
|
+
test("reflects property changes to attribute", async ({
|
|
516
|
+
element,
|
|
517
|
+
expect,
|
|
518
|
+
}) => {
|
|
519
|
+
element.assetId = "test-asset-456";
|
|
520
|
+
await element.updateComplete;
|
|
521
|
+
expect(element.getAttribute("asset-id")).toBe("test-asset-456");
|
|
522
|
+
|
|
523
|
+
element.assetId = null;
|
|
524
|
+
await element.updateComplete;
|
|
525
|
+
expect(element.hasAttribute("asset-id")).toBe(false);
|
|
526
|
+
});
|
|
287
527
|
|
|
288
|
-
|
|
289
|
-
|
|
528
|
+
test("reads assetId from html source", async ({ expect }) => {
|
|
529
|
+
const container = document.createElement("div");
|
|
530
|
+
container.innerHTML = `<test-media asset-id="test-asset-789"></test-media>`;
|
|
531
|
+
const media = container.querySelector("test-media") as TestMedia;
|
|
532
|
+
expect(media).toBeDefined();
|
|
533
|
+
expect(media.assetId).toBe("test-asset-789");
|
|
534
|
+
});
|
|
535
|
+
});
|
|
290
536
|
|
|
291
|
-
|
|
537
|
+
describe("fftSize", () => {
|
|
538
|
+
test("defaults to 128", ({ element, expect }) => {
|
|
539
|
+
expect(element.fftSize).toBe(128);
|
|
540
|
+
});
|
|
292
541
|
|
|
293
|
-
|
|
294
|
-
|
|
542
|
+
test("reads from js property", ({ element, expect }) => {
|
|
543
|
+
element.fftSize = 1024;
|
|
544
|
+
expect(element.fftSize).toBe(1024);
|
|
295
545
|
});
|
|
296
546
|
|
|
297
|
-
test("
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
element.src = "/assets/10s-bars.mp4";
|
|
302
|
-
element.sourceOutMs = 5_000;
|
|
547
|
+
test("reads from dom attribute", ({ element, expect }) => {
|
|
548
|
+
element.setAttribute("fft-size", "1024");
|
|
549
|
+
expect(element.fftSize).toBe(1024);
|
|
550
|
+
});
|
|
303
551
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
552
|
+
test("reflects property changes to attribute", async ({
|
|
553
|
+
element,
|
|
554
|
+
expect,
|
|
555
|
+
}) => {
|
|
556
|
+
element.fftSize = 512;
|
|
557
|
+
await element.updateComplete;
|
|
558
|
+
expect(element.getAttribute("fft-size")).toBe("512");
|
|
559
|
+
});
|
|
560
|
+
});
|
|
308
561
|
|
|
309
|
-
|
|
310
|
-
|
|
562
|
+
describe("fftDecay", () => {
|
|
563
|
+
test("defaults to 8", ({ element, expect }) => {
|
|
564
|
+
expect(element.fftDecay).toBe(8);
|
|
565
|
+
});
|
|
311
566
|
|
|
312
|
-
|
|
567
|
+
test("reads from js property", ({ element, expect }) => {
|
|
568
|
+
element.fftDecay = 16;
|
|
569
|
+
expect(element.fftDecay).toBe(16);
|
|
570
|
+
});
|
|
313
571
|
|
|
314
|
-
|
|
315
|
-
|
|
572
|
+
test("reads from dom attribute", ({ element, expect }) => {
|
|
573
|
+
element.setAttribute("fft-decay", "16");
|
|
574
|
+
expect(element.fftDecay).toBe(16);
|
|
316
575
|
});
|
|
317
576
|
|
|
318
|
-
test("
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
element.
|
|
323
|
-
element.
|
|
324
|
-
element.
|
|
577
|
+
test("reflects property changes to attribute", async ({
|
|
578
|
+
element,
|
|
579
|
+
expect,
|
|
580
|
+
}) => {
|
|
581
|
+
element.fftDecay = 32;
|
|
582
|
+
await element.updateComplete;
|
|
583
|
+
expect(element.getAttribute("fft-decay")).toBe("32");
|
|
584
|
+
});
|
|
585
|
+
});
|
|
325
586
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
587
|
+
describe("fftGain", () => {
|
|
588
|
+
test("defaults to 3.0", ({ element, expect }) => {
|
|
589
|
+
expect(element.fftGain).toBe(3.0);
|
|
590
|
+
});
|
|
330
591
|
|
|
331
|
-
|
|
332
|
-
|
|
592
|
+
test("reads from js property", ({ element, expect }) => {
|
|
593
|
+
element.fftGain = 0.5;
|
|
594
|
+
expect(element.fftGain).toBe(0.5);
|
|
595
|
+
});
|
|
333
596
|
|
|
334
|
-
|
|
597
|
+
test("reads from dom attribute", ({ element, expect }) => {
|
|
598
|
+
element.setAttribute("fft-gain", "0.5");
|
|
599
|
+
expect(element.fftGain).toBe(0.5);
|
|
600
|
+
});
|
|
335
601
|
|
|
336
|
-
|
|
337
|
-
|
|
602
|
+
test("reflects property changes to attribute", async ({
|
|
603
|
+
element,
|
|
604
|
+
expect,
|
|
605
|
+
}) => {
|
|
606
|
+
element.fftGain = 2.5;
|
|
607
|
+
await element.updateComplete;
|
|
608
|
+
expect(element.getAttribute("fft-gain")).toBe("2.5");
|
|
338
609
|
});
|
|
610
|
+
});
|
|
339
611
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
element.src = "/assets/10s-bars.mp4";
|
|
345
|
-
element.sourceInMs = 9_000;
|
|
346
|
-
element.sourceOutMs = 10_000;
|
|
612
|
+
describe("interpolateFrequencies", () => {
|
|
613
|
+
test("defaults to false", ({ element, expect }) => {
|
|
614
|
+
expect(element.interpolateFrequencies).toBe(false);
|
|
615
|
+
});
|
|
347
616
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
617
|
+
test("reads from js property", ({ element, expect }) => {
|
|
618
|
+
element.interpolateFrequencies = true;
|
|
619
|
+
expect(element.interpolateFrequencies).toBe(true);
|
|
620
|
+
});
|
|
352
621
|
|
|
353
|
-
|
|
354
|
-
|
|
622
|
+
test("reads from dom attribute", ({ element, expect }) => {
|
|
623
|
+
element.setAttribute("interpolate-frequencies", "true");
|
|
624
|
+
expect(element.interpolateFrequencies).toBe(true);
|
|
625
|
+
});
|
|
355
626
|
|
|
356
|
-
|
|
627
|
+
test("handles any attribute value as true (standard boolean behavior)", ({
|
|
628
|
+
element,
|
|
629
|
+
expect,
|
|
630
|
+
}) => {
|
|
631
|
+
element.setAttribute("interpolate-frequencies", "false");
|
|
632
|
+
expect(element.interpolateFrequencies).toBe(true); // Standard boolean attributes: any value = true
|
|
633
|
+
});
|
|
357
634
|
|
|
358
|
-
|
|
359
|
-
|
|
635
|
+
test("reflects property changes to attribute", async ({
|
|
636
|
+
element,
|
|
637
|
+
expect,
|
|
638
|
+
}) => {
|
|
639
|
+
element.interpolateFrequencies = true;
|
|
640
|
+
await element.updateComplete;
|
|
641
|
+
expect(element.hasAttribute("interpolate-frequencies")).toBe(true);
|
|
642
|
+
expect(element.getAttribute("interpolate-frequencies")).toBe(""); // Standard boolean reflection
|
|
643
|
+
|
|
644
|
+
element.interpolateFrequencies = false;
|
|
645
|
+
await element.updateComplete;
|
|
646
|
+
expect(element.hasAttribute("interpolate-frequencies")).toBe(false); // Standard boolean reflection removes attribute
|
|
360
647
|
});
|
|
361
648
|
});
|
|
649
|
+
|
|
650
|
+
// describe("mediaEngineTask", () => {
|
|
651
|
+
// test("is defined", ({ element, expect }) => {
|
|
652
|
+
// expect(element.mediaEngineTask).toBeDefined();
|
|
653
|
+
// });
|
|
654
|
+
|
|
655
|
+
// test("is a task", ({ element, expect }) => {
|
|
656
|
+
// expect(element.mediaEngineTask).toBeInstanceOf(Task);
|
|
657
|
+
// });
|
|
658
|
+
|
|
659
|
+
// test("throws if assetId is set", async ({ element, expect }) => {
|
|
660
|
+
// element.assetId = "test-asset-123";
|
|
661
|
+
// await element.mediaEngineTask.run();
|
|
662
|
+
// expect(element.mediaEngineTask.error).toBeInstanceOf(Error);
|
|
663
|
+
// });
|
|
664
|
+
|
|
665
|
+
// test("creates JitMediaEngine for http sources", async ({
|
|
666
|
+
// elementWithJitManifest,
|
|
667
|
+
// expect,
|
|
668
|
+
// worker,
|
|
669
|
+
// }) => {
|
|
670
|
+
// await elementWithJitManifest.mediaEngineTask.run();
|
|
671
|
+
// expect(elementWithJitManifest.mediaEngineTask.value).toBeInstanceOf(
|
|
672
|
+
// JitMediaEngine,
|
|
673
|
+
// );
|
|
674
|
+
// });
|
|
675
|
+
|
|
676
|
+
// test("creates AssetMediaEngine for local sources", async ({
|
|
677
|
+
// elementWithAsset,
|
|
678
|
+
// expect,
|
|
679
|
+
// }) => {
|
|
680
|
+
// await elementWithAsset.mediaEngineTask.run();
|
|
681
|
+
// expect(elementWithAsset.mediaEngineTask.value).toBeInstanceOf(
|
|
682
|
+
// AssetMediaEngine,
|
|
683
|
+
// );
|
|
684
|
+
// });
|
|
685
|
+
// });
|
|
686
|
+
|
|
687
|
+
// describe("Video Buffering Integration", () => {
|
|
688
|
+
// test("videoBufferTask is available and configured", ({
|
|
689
|
+
// element,
|
|
690
|
+
// expect,
|
|
691
|
+
// }) => {
|
|
692
|
+
// expect(element.videoBufferTask).toBeDefined();
|
|
693
|
+
// expect(element.videoBufferDurationMs).toBe(60000); // 60 seconds default
|
|
694
|
+
// expect(element.maxVideoBufferFetches).toBe(2); // 2 parallel fetches default
|
|
695
|
+
// expect(element.enableVideoBuffering).toBe(true); // enabled by default
|
|
696
|
+
// });
|
|
697
|
+
|
|
698
|
+
// test("buffer configuration can be customized", ({ element, expect }) => {
|
|
699
|
+
// element.videoBufferDurationMs = 45000;
|
|
700
|
+
// element.maxVideoBufferFetches = 3;
|
|
701
|
+
// element.enableVideoBuffering = false;
|
|
702
|
+
|
|
703
|
+
// expect(element.videoBufferDurationMs).toBe(45000);
|
|
704
|
+
// expect(element.maxVideoBufferFetches).toBe(3);
|
|
705
|
+
// expect(element.enableVideoBuffering).toBe(false);
|
|
706
|
+
// });
|
|
707
|
+
|
|
708
|
+
// test("buffer task starts automatically with JIT asset", async ({
|
|
709
|
+
// elementWithJitManifest,
|
|
710
|
+
// expect,
|
|
711
|
+
// }) => {
|
|
712
|
+
// const element = elementWithJitManifest;
|
|
713
|
+
|
|
714
|
+
// // Wait for media engine to initialize
|
|
715
|
+
// await element.mediaEngineTask.taskComplete;
|
|
716
|
+
|
|
717
|
+
// // Buffer task should be available and have started
|
|
718
|
+
// expect(element.videoBufferTask).toBeDefined();
|
|
719
|
+
// // Task status should be INITIAL (0) or higher, indicating it's been created
|
|
720
|
+
// expect(element.videoBufferTask.status).toBeGreaterThanOrEqual(0);
|
|
721
|
+
// });
|
|
722
|
+
// });
|
|
723
|
+
// });
|
|
724
|
+
|
|
725
|
+
// // Test to verify buffer tasks use EFMedia properties directly (no hardcoded config duplication)
|
|
726
|
+
// describe("Buffer Task Property Integration", () => {
|
|
727
|
+
// test("audio and video buffer tasks use EFMedia properties directly", async ({
|
|
728
|
+
// element,
|
|
729
|
+
// expect,
|
|
730
|
+
// }) => {
|
|
731
|
+
// // Set custom buffer configuration on the element
|
|
732
|
+
// element.audioBufferDurationMs = 15000;
|
|
733
|
+
// element.maxAudioBufferFetches = 3;
|
|
734
|
+
// element.enableAudioBuffering = false;
|
|
735
|
+
|
|
736
|
+
// element.videoBufferDurationMs = 45000;
|
|
737
|
+
// element.maxVideoBufferFetches = 5;
|
|
738
|
+
// element.enableVideoBuffering = false;
|
|
739
|
+
|
|
740
|
+
// // Verify the tasks are created without requiring hardcoded config
|
|
741
|
+
// expect(element.audioBufferTask).toBeDefined();
|
|
742
|
+
// expect(element.videoBufferTask).toBeDefined();
|
|
743
|
+
|
|
744
|
+
// // The task configuration should now come directly from element properties
|
|
745
|
+
// // This test ensures no hardcoded config duplication exists
|
|
746
|
+
// expect(element.audioBufferDurationMs).toBe(15000);
|
|
747
|
+
// expect(element.maxAudioBufferFetches).toBe(3);
|
|
748
|
+
// expect(element.enableAudioBuffering).toBe(false);
|
|
749
|
+
|
|
750
|
+
// expect(element.videoBufferDurationMs).toBe(45000);
|
|
751
|
+
// expect(element.maxVideoBufferFetches).toBe(5);
|
|
752
|
+
// expect(element.enableVideoBuffering).toBe(false);
|
|
753
|
+
// });
|
|
754
|
+
// });
|
|
362
755
|
});
|