rx-player 4.5.0-dev.2026033100 → 4.5.0-dev.2026041501
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/CHANGELOG.md +22 -5
- package/VERSION +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.js +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_worker.js +1 -1
- package/dist/commonjs/compat/can_patch_out_pssh.d.ts +42 -0
- package/dist/commonjs/compat/can_patch_out_pssh.d.ts.map +1 -0
- package/dist/commonjs/compat/can_patch_out_pssh.js +53 -0
- package/dist/commonjs/compat/env_detector.d.ts +2 -0
- package/dist/commonjs/compat/env_detector.d.ts.map +1 -1
- package/dist/commonjs/compat/env_detector.js +5 -0
- package/dist/commonjs/core/adaptive/network_analyzer.d.ts +1 -2
- package/dist/commonjs/core/adaptive/network_analyzer.d.ts.map +1 -1
- package/dist/commonjs/core/adaptive/network_analyzer.js +3 -3
- package/dist/commonjs/core/adaptive/utils/representation_score_calculator.js +2 -2
- package/dist/commonjs/core/cmcd/cmcd_data_builder.d.ts.map +1 -1
- package/dist/commonjs/core/cmcd/cmcd_data_builder.js +9 -3
- package/dist/commonjs/core/entry/content_preparer.d.ts.map +1 -1
- package/dist/commonjs/core/entry/content_preparer.js +5 -7
- package/dist/commonjs/core/entry/core_entry.d.ts.map +1 -1
- package/dist/commonjs/core/entry/core_entry.js +6 -2
- package/dist/commonjs/core/entry/core_text_displayer_interface.js +3 -3
- package/dist/commonjs/core/fetchers/manifest/manifest_fetcher.d.ts.map +1 -1
- package/dist/commonjs/core/fetchers/manifest/manifest_fetcher.js +12 -0
- package/dist/commonjs/core/fetchers/thumbnails/thumbnail_fetcher.js +1 -1
- package/dist/commonjs/core/fetchers/utils/schedule_request.d.ts.map +1 -1
- package/dist/commonjs/core/fetchers/utils/schedule_request.js +4 -3
- package/dist/commonjs/core/segment_sinks/garbage_collector.d.ts +0 -2
- package/dist/commonjs/core/segment_sinks/garbage_collector.d.ts.map +1 -1
- package/dist/commonjs/core/segment_sinks/garbage_collector.js +0 -3
- package/dist/commonjs/core/segment_sinks/implementations/text/text_segment_sink.d.ts +1 -1
- package/dist/commonjs/core/segment_sinks/implementations/text/text_segment_sink.d.ts.map +1 -1
- package/dist/commonjs/core/segment_sinks/implementations/text/text_segment_sink.js +2 -2
- package/dist/commonjs/core/stream/adaptation/adaptation_stream.d.ts.map +1 -1
- package/dist/commonjs/core/stream/adaptation/adaptation_stream.js +6 -6
- package/dist/commonjs/core/stream/orchestrator/stream_orchestrator.d.ts.map +1 -1
- package/dist/commonjs/core/stream/orchestrator/stream_orchestrator.js +37 -40
- package/dist/commonjs/default_config.d.ts +5 -0
- package/dist/commonjs/default_config.d.ts.map +1 -1
- package/dist/commonjs/default_config.js +5 -0
- package/dist/commonjs/main_thread/api/public_api.d.ts.map +1 -1
- package/dist/commonjs/main_thread/api/public_api.js +23 -16
- package/dist/commonjs/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
- package/dist/commonjs/main_thread/decrypt/content_decryptor.js +4 -1
- package/dist/commonjs/main_thread/decrypt/session_events_listener.js +1 -1
- package/dist/commonjs/main_thread/decrypt/set_server_certificate.d.ts +2 -0
- package/dist/commonjs/main_thread/decrypt/set_server_certificate.d.ts.map +1 -1
- package/dist/commonjs/main_thread/decrypt/set_server_certificate.js +4 -0
- package/dist/commonjs/main_thread/init/media_source_content_initializer.d.ts +0 -8
- package/dist/commonjs/main_thread/init/media_source_content_initializer.d.ts.map +1 -1
- package/dist/commonjs/main_thread/init/media_source_content_initializer.js +58 -50
- package/dist/commonjs/main_thread/init/utils/stream_events_emitter/stream_events_emitter.d.ts +35 -5
- package/dist/commonjs/main_thread/init/utils/stream_events_emitter/stream_events_emitter.d.ts.map +1 -1
- package/dist/commonjs/main_thread/init/utils/stream_events_emitter/stream_events_emitter.js +60 -19
- package/dist/commonjs/main_thread/render_thumbnail.d.ts.map +1 -1
- package/dist/commonjs/main_thread/render_thumbnail.js +4 -0
- package/dist/commonjs/main_thread/tracks_store/media_element_tracks_store.d.ts.map +1 -1
- package/dist/commonjs/main_thread/tracks_store/media_element_tracks_store.js +1 -0
- package/dist/commonjs/main_thread/tracks_store/tracks_store.d.ts +1 -1
- package/dist/commonjs/main_thread/tracks_store/tracks_store.js +1 -1
- package/dist/{es2017/parsers/containers/isobmff/take_pssh_out.d.ts → commonjs/parsers/containers/isobmff/extract_pssh.d.ts} +6 -4
- package/dist/commonjs/parsers/containers/isobmff/extract_pssh.d.ts.map +1 -0
- package/dist/commonjs/parsers/containers/isobmff/{take_pssh_out.js → extract_pssh.js} +22 -17
- package/dist/commonjs/parsers/containers/isobmff/index.d.ts +2 -2
- package/dist/commonjs/parsers/containers/isobmff/index.d.ts.map +1 -1
- package/dist/commonjs/parsers/containers/isobmff/index.js +4 -4
- package/dist/commonjs/playback_observer/core_playback_observer.d.ts +4 -4
- package/dist/commonjs/playback_observer/core_playback_observer.d.ts.map +1 -1
- package/dist/commonjs/playback_observer/media_element_playback_observer.d.ts +1 -2
- package/dist/commonjs/playback_observer/media_element_playback_observer.d.ts.map +1 -1
- package/dist/commonjs/transports/dash/segment_parser.js +1 -1
- package/dist/commonjs/transports/local/segment_parser.js +1 -1
- package/dist/commonjs/utils/test-utils.d.ts +30 -0
- package/dist/commonjs/utils/test-utils.d.ts.map +1 -0
- package/dist/commonjs/utils/test-utils.js +79 -0
- package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
- package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.js +1 -1
- package/dist/es2017/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
- package/dist/es2017/__GENERATED_CODE/embedded_worker.js +1 -1
- package/dist/es2017/compat/can_patch_out_pssh.d.ts +42 -0
- package/dist/es2017/compat/can_patch_out_pssh.d.ts.map +1 -0
- package/dist/es2017/compat/can_patch_out_pssh.js +50 -0
- package/dist/es2017/compat/env_detector.d.ts +2 -0
- package/dist/es2017/compat/env_detector.d.ts.map +1 -1
- package/dist/es2017/compat/env_detector.js +5 -0
- package/dist/es2017/core/adaptive/network_analyzer.d.ts +1 -2
- package/dist/es2017/core/adaptive/network_analyzer.d.ts.map +1 -1
- package/dist/es2017/core/adaptive/network_analyzer.js +3 -3
- package/dist/es2017/core/adaptive/utils/representation_score_calculator.js +2 -2
- package/dist/es2017/core/cmcd/cmcd_data_builder.d.ts.map +1 -1
- package/dist/es2017/core/cmcd/cmcd_data_builder.js +9 -3
- package/dist/es2017/core/entry/content_preparer.d.ts.map +1 -1
- package/dist/es2017/core/entry/content_preparer.js +3 -5
- package/dist/es2017/core/entry/core_entry.d.ts.map +1 -1
- package/dist/es2017/core/entry/core_entry.js +6 -2
- package/dist/es2017/core/entry/core_text_displayer_interface.js +3 -3
- package/dist/es2017/core/fetchers/manifest/manifest_fetcher.d.ts.map +1 -1
- package/dist/es2017/core/fetchers/manifest/manifest_fetcher.js +12 -0
- package/dist/es2017/core/fetchers/thumbnails/thumbnail_fetcher.js +1 -1
- package/dist/es2017/core/fetchers/utils/schedule_request.d.ts.map +1 -1
- package/dist/es2017/core/fetchers/utils/schedule_request.js +2 -3
- package/dist/es2017/core/segment_sinks/garbage_collector.d.ts +0 -2
- package/dist/es2017/core/segment_sinks/garbage_collector.d.ts.map +1 -1
- package/dist/es2017/core/segment_sinks/garbage_collector.js +0 -3
- package/dist/es2017/core/segment_sinks/implementations/text/text_segment_sink.d.ts +1 -1
- package/dist/es2017/core/segment_sinks/implementations/text/text_segment_sink.d.ts.map +1 -1
- package/dist/es2017/core/segment_sinks/implementations/text/text_segment_sink.js +2 -2
- package/dist/es2017/core/stream/adaptation/adaptation_stream.d.ts.map +1 -1
- package/dist/es2017/core/stream/adaptation/adaptation_stream.js +6 -6
- package/dist/es2017/core/stream/orchestrator/stream_orchestrator.d.ts.map +1 -1
- package/dist/es2017/core/stream/orchestrator/stream_orchestrator.js +40 -39
- package/dist/es2017/default_config.d.ts +5 -0
- package/dist/es2017/default_config.d.ts.map +1 -1
- package/dist/es2017/default_config.js +5 -0
- package/dist/es2017/main_thread/api/public_api.d.ts.map +1 -1
- package/dist/es2017/main_thread/api/public_api.js +20 -13
- package/dist/es2017/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
- package/dist/es2017/main_thread/decrypt/content_decryptor.js +4 -1
- package/dist/es2017/main_thread/decrypt/session_events_listener.js +1 -1
- package/dist/es2017/main_thread/decrypt/set_server_certificate.d.ts +2 -0
- package/dist/es2017/main_thread/decrypt/set_server_certificate.d.ts.map +1 -1
- package/dist/es2017/main_thread/decrypt/set_server_certificate.js +4 -0
- package/dist/es2017/main_thread/init/media_source_content_initializer.d.ts +0 -8
- package/dist/es2017/main_thread/init/media_source_content_initializer.d.ts.map +1 -1
- package/dist/es2017/main_thread/init/media_source_content_initializer.js +58 -50
- package/dist/es2017/main_thread/init/utils/stream_events_emitter/stream_events_emitter.d.ts +35 -5
- package/dist/es2017/main_thread/init/utils/stream_events_emitter/stream_events_emitter.d.ts.map +1 -1
- package/dist/es2017/main_thread/init/utils/stream_events_emitter/stream_events_emitter.js +60 -19
- package/dist/es2017/main_thread/render_thumbnail.d.ts.map +1 -1
- package/dist/es2017/main_thread/render_thumbnail.js +4 -0
- package/dist/es2017/main_thread/tracks_store/media_element_tracks_store.d.ts.map +1 -1
- package/dist/es2017/main_thread/tracks_store/media_element_tracks_store.js +1 -0
- package/dist/es2017/main_thread/tracks_store/tracks_store.d.ts +1 -1
- package/dist/es2017/main_thread/tracks_store/tracks_store.js +1 -1
- package/dist/{commonjs/parsers/containers/isobmff/take_pssh_out.d.ts → es2017/parsers/containers/isobmff/extract_pssh.d.ts} +6 -4
- package/dist/es2017/parsers/containers/isobmff/extract_pssh.d.ts.map +1 -0
- package/dist/es2017/parsers/containers/isobmff/{take_pssh_out.js → extract_pssh.js} +21 -16
- package/dist/es2017/parsers/containers/isobmff/index.d.ts +2 -2
- package/dist/es2017/parsers/containers/isobmff/index.d.ts.map +1 -1
- package/dist/es2017/parsers/containers/isobmff/index.js +2 -2
- package/dist/es2017/playback_observer/core_playback_observer.d.ts +4 -4
- package/dist/es2017/playback_observer/core_playback_observer.d.ts.map +1 -1
- package/dist/es2017/playback_observer/media_element_playback_observer.d.ts +1 -2
- package/dist/es2017/playback_observer/media_element_playback_observer.d.ts.map +1 -1
- package/dist/es2017/transports/dash/segment_parser.js +2 -2
- package/dist/es2017/transports/local/segment_parser.js +2 -2
- package/dist/es2017/utils/test-utils.d.ts +30 -0
- package/dist/es2017/utils/test-utils.d.ts.map +1 -0
- package/dist/es2017/utils/test-utils.js +36 -0
- package/dist/mpd-parser.wasm +0 -0
- package/dist/worker.js +6 -6
- package/package.json +4 -2
- package/src/README.md +7 -7
- package/src/__GENERATED_CODE/embedded_dash_wasm.ts +1 -1
- package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
- package/src/compat/__tests__/can_patch_out_pssh.test.ts +40 -0
- package/src/compat/can_patch_out_pssh.ts +53 -0
- package/src/compat/env_detector.ts +4 -0
- package/src/core/README.md +1 -1
- package/src/core/adaptive/README.md +3 -3
- package/src/core/adaptive/__tests__/adaptive_representation_selector.test.ts +181 -110
- package/src/core/adaptive/__tests__/guess_based_chooser.test.ts +229 -123
- package/src/core/adaptive/__tests__/mocks.ts +100 -0
- package/src/core/adaptive/__tests__/network_analyzer.test.ts +152 -59
- package/src/core/adaptive/network_analyzer.ts +4 -4
- package/src/core/adaptive/utils/__tests__/filter_by_bitrate.test.ts +11 -19
- package/src/core/adaptive/utils/__tests__/filter_by_resolution.test.ts +12 -12
- package/src/core/adaptive/utils/__tests__/last_estimate_storage.test.ts +25 -12
- package/src/core/adaptive/utils/__tests__/pending_requests_store.test.ts +13 -9
- package/src/core/adaptive/utils/__tests__/representation_score_calculator.test.ts +11 -11
- package/src/core/adaptive/utils/__tests__/select_optimal_representation.test.ts +13 -23
- package/src/core/adaptive/utils/representation_score_calculator.ts +2 -2
- package/src/core/cmcd/__tests__/cmcd_data_builder.test.ts +60 -15
- package/src/core/cmcd/cmcd_data_builder.ts +9 -3
- package/src/core/entry/README.md +2 -2
- package/src/core/entry/__tests__/core_text_displayer_interface.test.ts +20 -0
- package/src/core/entry/content_preparer.ts +2 -5
- package/src/core/entry/core_entry.ts +6 -2
- package/src/core/entry/core_text_displayer_interface.ts +3 -3
- package/src/core/fetchers/manifest/__tests__/manifest_fetcher.test.ts +52 -3
- package/src/core/fetchers/manifest/manifest_fetcher.ts +12 -0
- package/src/core/fetchers/thumbnails/__tests__/thumbnail_fetcher.test.ts +70 -0
- package/src/core/fetchers/thumbnails/thumbnail_fetcher.ts +1 -1
- package/src/core/fetchers/utils/schedule_request.ts +5 -3
- package/src/core/segment_sinks/__tests__/garbage_collector.test.ts +434 -0
- package/src/core/segment_sinks/__tests__/mocks.ts +49 -0
- package/src/core/segment_sinks/garbage_collector.ts +0 -3
- package/src/core/segment_sinks/implementations/text/__tests__/text_segment_sink.test.ts +177 -0
- package/src/core/segment_sinks/implementations/text/text_segment_sink.ts +2 -2
- package/src/core/segment_sinks/inventory/__tests__/buffered_history.test.ts +215 -0
- package/src/core/segment_sinks/inventory/__tests__/segment_inventory.test.ts +448 -0
- package/src/core/stream/adaptation/__tests__/adaptation_stream.test.ts +973 -0
- package/src/core/stream/adaptation/__tests__/get_representations_switch_strategy.test.ts +283 -374
- package/src/core/stream/adaptation/adaptation_stream.ts +6 -8
- package/src/core/stream/orchestrator/README.md +4 -4
- package/src/core/stream/orchestrator/__tests__/stream_orchestrator.test.ts +707 -0
- package/src/core/stream/orchestrator/stream_orchestrator.ts +41 -46
- package/src/core/stream/period/utils/__tests__/get_adaptation_switch_strategy.test.ts +290 -220
- package/src/core/stream/representation/__tests__/encryption_data_notifier.test.ts +93 -63
- package/src/core/stream/representation/utils/__tests__/append_segment_to_buffer.test.ts +106 -63
- package/src/core/stream/representation/utils/__tests__/check_for_discontinuity.test.ts +179 -204
- package/src/core/stream/representation/utils/__tests__/get_segment_priority.test.ts +7 -7
- package/src/core/stream/representation/utils/__tests__/push_init_segment.test.ts +103 -60
- package/src/core/stream/representation/utils/__tests__/push_media_segment.test.ts +231 -165
- package/src/default_config.ts +6 -0
- package/src/experimental/README.md +1 -1
- package/src/features/README.md +3 -3
- package/src/main_thread/api/README.md +6 -7
- package/src/main_thread/api/public_api.ts +16 -10
- package/src/main_thread/decrypt/README.md +4 -4
- package/src/main_thread/decrypt/__tests__/__global__/content_decryptor.test.ts +135 -0
- package/src/main_thread/decrypt/__tests__/__global__/get_license.test.ts +70 -0
- package/src/main_thread/decrypt/__tests__/__global__/server_certificate.test.ts +44 -0
- package/src/main_thread/decrypt/__tests__/__global__/utils.ts +2 -2
- package/src/main_thread/decrypt/content_decryptor.ts +6 -1
- package/src/main_thread/decrypt/session_events_listener.ts +1 -1
- package/src/main_thread/decrypt/set_server_certificate.ts +5 -0
- package/src/main_thread/init/media_source_content_initializer.ts +69 -55
- package/src/main_thread/init/utils/__tests__/stream_events_emitter.test.ts +175 -0
- package/src/main_thread/init/utils/stream_events_emitter/stream_events_emitter.ts +90 -26
- package/src/main_thread/render_thumbnail.ts +4 -0
- package/src/main_thread/tracks_store/README.md +12 -0
- package/src/main_thread/tracks_store/__tests__/media_element_tracks_store.test.ts +25 -18
- package/src/main_thread/tracks_store/media_element_tracks_store.ts +1 -0
- package/src/main_thread/tracks_store/tracks_store.ts +1 -1
- package/src/manifest/classes/__tests__/mocks.ts +202 -0
- package/src/parsers/containers/isobmff/__tests__/extract_pssh.test.ts +199 -0
- package/src/parsers/containers/isobmff/{take_pssh_out.ts → extract_pssh.ts} +21 -17
- package/src/parsers/containers/isobmff/index.ts +2 -2
- package/src/parsers/manifest/dash/wasm-parser/README.md +9 -9
- package/src/playback_observer/__tests__/mocks.ts +152 -0
- package/src/playback_observer/core_playback_observer.ts +4 -4
- package/src/playback_observer/media_element_playback_observer.ts +1 -1
- package/src/tools/README.md +2 -2
- package/src/transports/README.md +5 -5
- package/src/transports/dash/segment_parser.ts +2 -2
- package/src/transports/local/segment_parser.ts +2 -2
- package/src/transports/metaplaylist/README.md +4 -4
- package/src/utils/README.md +3 -3
- package/src/utils/test-utils.ts +50 -0
- package/dist/commonjs/core/entry/synchronize_sinks_on_observation.d.ts +0 -11
- package/dist/commonjs/core/entry/synchronize_sinks_on_observation.d.ts.map +0 -1
- package/dist/commonjs/core/entry/synchronize_sinks_on_observation.js +0 -20
- package/dist/commonjs/parsers/containers/isobmff/take_pssh_out.d.ts.map +0 -1
- package/dist/es2017/core/entry/synchronize_sinks_on_observation.d.ts +0 -11
- package/dist/es2017/core/entry/synchronize_sinks_on_observation.d.ts.map +0 -1
- package/dist/es2017/core/entry/synchronize_sinks_on_observation.js +0 -17
- package/dist/es2017/parsers/containers/isobmff/take_pssh_out.d.ts.map +0 -1
- package/src/core/adaptive/utils/__tests__/bandwith_estimator.test.ts +0 -117
- package/src/core/entry/synchronize_sinks_on_observation.ts +0 -22
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import type { ITextDisplayerData } from "../../../../../main_thread/text_displayer/types";
|
|
3
|
+
import {
|
|
4
|
+
DummyAdaptation,
|
|
5
|
+
DummyPeriod,
|
|
6
|
+
DummyRepresentation,
|
|
7
|
+
createSegment,
|
|
8
|
+
} from "../../../../../manifest/classes/__tests__/mocks";
|
|
9
|
+
import type { IRange } from "../../../../../utils/ranges";
|
|
10
|
+
import SegmentInventory from "../../../inventory";
|
|
11
|
+
import type { IPushChunkInfos } from "../../types";
|
|
12
|
+
import { SegmentSinkOperation } from "../../types";
|
|
13
|
+
import TextSegmentSink, { type ITextDisplayerInterface } from "../text_segment_sink";
|
|
14
|
+
|
|
15
|
+
function createSender() {
|
|
16
|
+
const pushTextData = vi.fn<(infos: ITextDisplayerData) => Promise<IRange[]>>();
|
|
17
|
+
const remove = vi.fn<(start: number, end: number) => Promise<IRange[]>>();
|
|
18
|
+
const reset = vi.fn<() => void>();
|
|
19
|
+
const stop = vi.fn<(reason: string | undefined) => void>();
|
|
20
|
+
return {
|
|
21
|
+
pushTextData,
|
|
22
|
+
remove,
|
|
23
|
+
reset,
|
|
24
|
+
stop,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function createChunkInfos(): IPushChunkInfos<unknown> {
|
|
29
|
+
return {
|
|
30
|
+
data: {
|
|
31
|
+
chunk: {
|
|
32
|
+
data: "WEBVTT",
|
|
33
|
+
type: "vtt",
|
|
34
|
+
initTimescale: null,
|
|
35
|
+
start: 0,
|
|
36
|
+
end: 2,
|
|
37
|
+
},
|
|
38
|
+
timestampOffset: 0,
|
|
39
|
+
appendWindow: [undefined, undefined],
|
|
40
|
+
codec: undefined,
|
|
41
|
+
initSegmentUniqueId: null,
|
|
42
|
+
},
|
|
43
|
+
inventoryInfos: {
|
|
44
|
+
adaptation: new DummyAdaptation({ type: "text" }),
|
|
45
|
+
period: new DummyPeriod(),
|
|
46
|
+
representation: new DummyRepresentation({ trackType: "text" }),
|
|
47
|
+
segment: createSegment({ id: "seg-1", isInit: false, complete: true }),
|
|
48
|
+
chunkSize: 12,
|
|
49
|
+
start: 0,
|
|
50
|
+
end: 2,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function createCompleteSegmentInfo() {
|
|
56
|
+
return {
|
|
57
|
+
adaptation: new DummyAdaptation({ type: "text" }),
|
|
58
|
+
period: new DummyPeriod(),
|
|
59
|
+
representation: new DummyRepresentation({ trackType: "text" }),
|
|
60
|
+
segment: createSegment({ id: "seg-1", isInit: false, complete: true }),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function createDeferred<T>() {
|
|
65
|
+
let resolve!: (value: T | PromiseLike<T>) => void;
|
|
66
|
+
let reject!: (reason?: unknown) => void;
|
|
67
|
+
const promise = new Promise<T>((res, rej) => {
|
|
68
|
+
resolve = res;
|
|
69
|
+
reject = rej;
|
|
70
|
+
});
|
|
71
|
+
return { promise, resolve, reject };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
class TestTextSegmentSink extends TextSegmentSink {
|
|
75
|
+
public constructor(sender: ITextDisplayerInterface, inventory: SegmentInventory) {
|
|
76
|
+
super(sender);
|
|
77
|
+
this._segmentInventory = inventory;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
describe("TextSegmentSink", () => {
|
|
82
|
+
it("resets the text displayer on construction", () => {
|
|
83
|
+
const sender = createSender();
|
|
84
|
+
new TextSegmentSink(sender);
|
|
85
|
+
|
|
86
|
+
expect(sender.reset).toHaveBeenCalledTimes(1);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("forwards dispose to the text displayer stop method", () => {
|
|
90
|
+
const sender = createSender();
|
|
91
|
+
|
|
92
|
+
const sink = new TextSegmentSink(sender);
|
|
93
|
+
sink.dispose("test reason");
|
|
94
|
+
|
|
95
|
+
expect(sender.reset).toHaveBeenCalledTimes(1);
|
|
96
|
+
expect(sender.stop).toHaveBeenCalledTimes(1);
|
|
97
|
+
expect(sender.stop).toHaveBeenCalledWith("test reason");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("pushes text data, tracks the pending operation, and updates inventory", async () => {
|
|
101
|
+
const sender = createSender();
|
|
102
|
+
const deferred = createDeferred<IRange[]>();
|
|
103
|
+
sender.pushTextData.mockReturnValue(deferred.promise);
|
|
104
|
+
const inventory = new SegmentInventory();
|
|
105
|
+
const sink = new TestTextSegmentSink(sender, inventory);
|
|
106
|
+
const infos = createChunkInfos();
|
|
107
|
+
const insertChunk = vi.spyOn(inventory, "insertChunk");
|
|
108
|
+
const synchronizeBuffered = vi.spyOn(inventory, "synchronizeBuffered");
|
|
109
|
+
|
|
110
|
+
const pushPromise = sink.pushChunk(infos);
|
|
111
|
+
|
|
112
|
+
expect(sender.pushTextData).toHaveBeenCalledWith(infos.data);
|
|
113
|
+
expect(sink.getPendingOperations()).toEqual([
|
|
114
|
+
{ type: SegmentSinkOperation.Push, value: infos },
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
deferred.resolve([{ start: 0, end: 2 }]);
|
|
118
|
+
await expect(pushPromise).resolves.toEqual([{ start: 0, end: 2 }]);
|
|
119
|
+
expect(insertChunk).toHaveBeenCalledTimes(1);
|
|
120
|
+
expect(insertChunk).toHaveBeenCalledWith(
|
|
121
|
+
infos.inventoryInfos,
|
|
122
|
+
true,
|
|
123
|
+
expect.any(Number),
|
|
124
|
+
);
|
|
125
|
+
expect(synchronizeBuffered).toHaveBeenCalledWith([{ start: 0, end: 2 }]);
|
|
126
|
+
expect(sink.getPendingOperations()).toEqual([]);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("removes text data, tracks the pending operation, and synchronizes inventory", async () => {
|
|
130
|
+
const sender = createSender();
|
|
131
|
+
const deferred = createDeferred<IRange[]>();
|
|
132
|
+
sender.remove.mockReturnValue(deferred.promise);
|
|
133
|
+
const inventory = new SegmentInventory();
|
|
134
|
+
const sink = new TestTextSegmentSink(sender, inventory);
|
|
135
|
+
const synchronizeBuffered = vi.spyOn(inventory, "synchronizeBuffered");
|
|
136
|
+
|
|
137
|
+
const removePromise = sink.removeBuffer(10, 20);
|
|
138
|
+
|
|
139
|
+
expect(sender.remove).toHaveBeenCalledWith(10, 20);
|
|
140
|
+
expect(sink.getPendingOperations()).toEqual([
|
|
141
|
+
{ type: SegmentSinkOperation.Remove, value: { start: 10, end: 20 } },
|
|
142
|
+
]);
|
|
143
|
+
|
|
144
|
+
deferred.resolve([{ start: 10, end: 20 }]);
|
|
145
|
+
await expect(removePromise).resolves.toEqual([{ start: 10, end: 20 }]);
|
|
146
|
+
expect(synchronizeBuffered).toHaveBeenCalledWith([{ start: 10, end: 20 }]);
|
|
147
|
+
expect(sink.getPendingOperations()).toEqual([]);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("waits for the previous operation before completing a segment", async () => {
|
|
151
|
+
const sender = createSender();
|
|
152
|
+
const deferred = createDeferred<IRange[]>();
|
|
153
|
+
sender.pushTextData.mockReturnValue(deferred.promise);
|
|
154
|
+
const inventory = new SegmentInventory();
|
|
155
|
+
const sink = new TestTextSegmentSink(sender, inventory);
|
|
156
|
+
const completeSegment = vi.spyOn(inventory, "completeSegment");
|
|
157
|
+
const pushInfos = createChunkInfos();
|
|
158
|
+
const completionInfos = createCompleteSegmentInfo();
|
|
159
|
+
|
|
160
|
+
const pushPromise = sink.pushChunk(pushInfos);
|
|
161
|
+
const signalPromise = sink.signalSegmentComplete(completionInfos);
|
|
162
|
+
|
|
163
|
+
expect(sink.getPendingOperations()).toEqual([
|
|
164
|
+
{ type: SegmentSinkOperation.Push, value: pushInfos },
|
|
165
|
+
{ type: SegmentSinkOperation.SignalSegmentComplete, value: completionInfos },
|
|
166
|
+
]);
|
|
167
|
+
expect(completeSegment).not.toHaveBeenCalled();
|
|
168
|
+
|
|
169
|
+
deferred.resolve([{ start: 0, end: 2 }]);
|
|
170
|
+
await pushPromise;
|
|
171
|
+
await signalPromise;
|
|
172
|
+
|
|
173
|
+
expect(completeSegment).toHaveBeenCalledTimes(1);
|
|
174
|
+
expect(completeSegment).toHaveBeenCalledWith(completionInfos);
|
|
175
|
+
expect(sink.getPendingOperations()).toEqual([]);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
@@ -128,9 +128,9 @@ export default class TextSegmentSink extends SegmentSink {
|
|
|
128
128
|
return this._pendingOperations.map((p) => p.operation);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
public dispose(): void {
|
|
131
|
+
public dispose(reason: string | undefined): void {
|
|
132
132
|
log.debug("Stream", "Disposing TextSegmentSink");
|
|
133
|
-
this._sender.
|
|
133
|
+
this._sender.stop(reason);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
private _addToOperationQueue(
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
DummyAdaptation,
|
|
4
|
+
DummyRepresentation,
|
|
5
|
+
DummyPeriod,
|
|
6
|
+
createSegment,
|
|
7
|
+
} from "../../../../manifest/classes/__tests__/mocks";
|
|
8
|
+
import BufferedHistory from "../buffered_history";
|
|
9
|
+
import type { IChunkContext } from "../types";
|
|
10
|
+
|
|
11
|
+
const { mockAreSameContent, mockGetMonotonicTimeStamp } = vi.hoisted(() => {
|
|
12
|
+
return { mockAreSameContent: vi.fn(), mockGetMonotonicTimeStamp: vi.fn() };
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
vi.mock("../../../../manifest", () => ({
|
|
16
|
+
areSameContent: mockAreSameContent,
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
vi.mock("../../../../utils/monotonic_timestamp", () => ({
|
|
20
|
+
default: mockGetMonotonicTimeStamp,
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
const makeContext = (id: string): IChunkContext => ({
|
|
24
|
+
adaptation: new DummyAdaptation({ id }),
|
|
25
|
+
representation: new DummyRepresentation({ id }),
|
|
26
|
+
period: new DummyPeriod({ id }),
|
|
27
|
+
segment: createSegment({ id }),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("BufferedHistory", () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
vi.resetAllMocks();
|
|
33
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1000);
|
|
34
|
+
mockAreSameContent.mockReturnValue(false);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe("constructor", () => {
|
|
38
|
+
it("should initialize with an empty history", () => {
|
|
39
|
+
const history = new BufferedHistory(5000, 10);
|
|
40
|
+
expect(history.getHistoryFor(makeContext("1"))).toHaveLength(0);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe("addBufferedSegment", () => {
|
|
45
|
+
it("should add an entry with the current timestamp and buffered range", () => {
|
|
46
|
+
mockGetMonotonicTimeStamp.mockReturnValue(2000);
|
|
47
|
+
mockAreSameContent.mockReturnValue(true);
|
|
48
|
+
|
|
49
|
+
const history = new BufferedHistory(5000, 10);
|
|
50
|
+
const context = makeContext("1");
|
|
51
|
+
const buffered = { start: 0, end: 10 };
|
|
52
|
+
|
|
53
|
+
history.addBufferedSegment(context, buffered);
|
|
54
|
+
|
|
55
|
+
const entries = history.getHistoryFor(context);
|
|
56
|
+
expect(entries).toHaveLength(1);
|
|
57
|
+
expect(entries[0].date).toBe(2000);
|
|
58
|
+
expect(entries[0].buffered).toEqual({ start: 0, end: 10 });
|
|
59
|
+
expect(entries[0].context).toBe(context);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should accept null as a buffered value", () => {
|
|
63
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1000);
|
|
64
|
+
mockAreSameContent.mockReturnValue(true);
|
|
65
|
+
|
|
66
|
+
const history = new BufferedHistory(5000, 10);
|
|
67
|
+
const context = makeContext("1");
|
|
68
|
+
|
|
69
|
+
history.addBufferedSegment(context, null);
|
|
70
|
+
|
|
71
|
+
const entries = history.getHistoryFor(context);
|
|
72
|
+
expect(entries).toHaveLength(1);
|
|
73
|
+
expect(entries[0].buffered).toBeNull();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should store multiple entries in chronological order", () => {
|
|
77
|
+
const history = new BufferedHistory(5000, 10);
|
|
78
|
+
mockAreSameContent.mockReturnValue(true);
|
|
79
|
+
|
|
80
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1000);
|
|
81
|
+
history.addBufferedSegment(makeContext("1"), { start: 0, end: 5 });
|
|
82
|
+
|
|
83
|
+
mockGetMonotonicTimeStamp.mockReturnValue(2000);
|
|
84
|
+
history.addBufferedSegment(makeContext("1"), { start: 5, end: 10 });
|
|
85
|
+
|
|
86
|
+
const entries = history.getHistoryFor(makeContext("1"));
|
|
87
|
+
expect(entries).toHaveLength(2);
|
|
88
|
+
expect(entries[0].date).toBe(1000);
|
|
89
|
+
expect(entries[1].date).toBe(2000);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("getHistoryFor", () => {
|
|
94
|
+
it("should return only entries matching the given context", () => {
|
|
95
|
+
const contextA = makeContext("1");
|
|
96
|
+
const contextB = makeContext("2");
|
|
97
|
+
|
|
98
|
+
mockAreSameContent.mockImplementation((a, b) => a === b);
|
|
99
|
+
|
|
100
|
+
const history = new BufferedHistory(5000, 10);
|
|
101
|
+
history.addBufferedSegment(contextA, { start: 0, end: 5 });
|
|
102
|
+
history.addBufferedSegment(contextB, { start: 5, end: 10 });
|
|
103
|
+
history.addBufferedSegment(contextA, { start: 10, end: 15 });
|
|
104
|
+
|
|
105
|
+
expect(history.getHistoryFor(contextA)).toHaveLength(2);
|
|
106
|
+
expect(history.getHistoryFor(contextB)).toHaveLength(1);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should return an empty array when no entry matches", () => {
|
|
110
|
+
mockAreSameContent.mockReturnValue(false);
|
|
111
|
+
|
|
112
|
+
const history = new BufferedHistory(5000, 10);
|
|
113
|
+
history.addBufferedSegment(makeContext("1"), { start: 0, end: 5 });
|
|
114
|
+
|
|
115
|
+
expect(history.getHistoryFor(makeContext("99"))).toHaveLength(0);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("_cleanHistory (lifetime enforcement)", () => {
|
|
120
|
+
it("should remove entries older than the lifetime on addBufferedSegment", () => {
|
|
121
|
+
mockAreSameContent.mockReturnValue(true);
|
|
122
|
+
|
|
123
|
+
const history = new BufferedHistory(500, 10);
|
|
124
|
+
|
|
125
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1000);
|
|
126
|
+
history.addBufferedSegment(makeContext("1"), { start: 0, end: 5 });
|
|
127
|
+
|
|
128
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1200);
|
|
129
|
+
history.addBufferedSegment(makeContext("1"), { start: 5, end: 10 });
|
|
130
|
+
|
|
131
|
+
// now = 1600, lifetime = 500 → entries before 1100 should be dropped
|
|
132
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1600);
|
|
133
|
+
history.addBufferedSegment(makeContext("1"), { start: 10, end: 15 });
|
|
134
|
+
|
|
135
|
+
const entries = history.getHistoryFor(makeContext("1"));
|
|
136
|
+
expect(entries.every((e) => e.date >= 1100)).toBe(true);
|
|
137
|
+
// eslint-disable-next-line no-restricted-properties
|
|
138
|
+
expect(entries.find((e) => e.date === 1000)).toBeUndefined();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("should keep entries whose date is exactly at the lifetime boundary", () => {
|
|
142
|
+
mockAreSameContent.mockReturnValue(true);
|
|
143
|
+
|
|
144
|
+
const history = new BufferedHistory(500, 10);
|
|
145
|
+
|
|
146
|
+
// entry at t=1000, boundary when now=1500 is exactly 1000 — NOT expired
|
|
147
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1000);
|
|
148
|
+
history.addBufferedSegment(makeContext("1"), { start: 0, end: 5 });
|
|
149
|
+
|
|
150
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1500);
|
|
151
|
+
history.addBufferedSegment(makeContext("1"), { start: 5, end: 10 });
|
|
152
|
+
|
|
153
|
+
const entries = history.getHistoryFor(makeContext("1"));
|
|
154
|
+
// eslint-disable-next-line no-restricted-properties
|
|
155
|
+
expect(entries.find((e) => e.date === 1000)).toBeDefined();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe("_cleanHistory (maxHistoryLength enforcement)", () => {
|
|
160
|
+
it("should remove oldest entries when exceeding maxHistoryLength", () => {
|
|
161
|
+
mockAreSameContent.mockReturnValue(true);
|
|
162
|
+
|
|
163
|
+
const history = new BufferedHistory(99999, 3);
|
|
164
|
+
|
|
165
|
+
for (let i = 0; i < 4; i++) {
|
|
166
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1000 + i);
|
|
167
|
+
history.addBufferedSegment(makeContext("1"), { start: i, end: i + 1 });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const entries = history.getHistoryFor(makeContext("1"));
|
|
171
|
+
expect(entries).toHaveLength(3);
|
|
172
|
+
// The oldest entry (date=1000) should have been evicted
|
|
173
|
+
// eslint-disable-next-line no-restricted-properties
|
|
174
|
+
expect(entries.find((e) => e.date === 1000)).toBeUndefined();
|
|
175
|
+
expect(entries[0].date).toBe(1001);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("should keep exactly maxHistoryLength entries when at the limit", () => {
|
|
179
|
+
mockAreSameContent.mockReturnValue(true);
|
|
180
|
+
|
|
181
|
+
const history = new BufferedHistory(99999, 3);
|
|
182
|
+
|
|
183
|
+
for (let i = 0; i < 3; i++) {
|
|
184
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1000 + i);
|
|
185
|
+
history.addBufferedSegment(makeContext("1"), { start: i, end: i + 1 });
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const entries = history.getHistoryFor(makeContext("1"));
|
|
189
|
+
expect(entries).toHaveLength(3);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe("combined lifetime and maxHistoryLength", () => {
|
|
194
|
+
it("should apply both constraints independently", () => {
|
|
195
|
+
mockAreSameContent.mockReturnValue(true);
|
|
196
|
+
|
|
197
|
+
const history = new BufferedHistory(500, 2);
|
|
198
|
+
|
|
199
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1000);
|
|
200
|
+
history.addBufferedSegment(makeContext("1"), { start: 0, end: 1 });
|
|
201
|
+
|
|
202
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1100);
|
|
203
|
+
history.addBufferedSegment(makeContext("1"), { start: 1, end: 2 });
|
|
204
|
+
|
|
205
|
+
// now=1600 → t=1000 expired by lifetime; then only 1 entry remains, under max
|
|
206
|
+
mockGetMonotonicTimeStamp.mockReturnValue(1600);
|
|
207
|
+
history.addBufferedSegment(makeContext("1"), { start: 2, end: 3 });
|
|
208
|
+
|
|
209
|
+
const entries = history.getHistoryFor(makeContext("1"));
|
|
210
|
+
expect(entries).toHaveLength(2);
|
|
211
|
+
// eslint-disable-next-line no-restricted-properties
|
|
212
|
+
expect(entries.find((e) => e.date === 1000)).toBeUndefined();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
});
|