rx-player 4.5.0-dev.2026033100 → 4.5.0-dev.2026043000
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 +25 -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/content_time_boundaries_observer.d.ts.map +1 -1
- package/dist/commonjs/core/entry/content_time_boundaries_observer.js +18 -4
- 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/errors/index.d.ts +2 -2
- package/dist/commonjs/errors/index.d.ts.map +1 -1
- package/dist/commonjs/errors/index.js +2 -1
- package/dist/commonjs/errors/media_error.d.ts +19 -4
- package/dist/commonjs/errors/media_error.d.ts.map +1 -1
- package/dist/commonjs/errors/media_error.js +29 -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 +59 -54
- 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/content_time_boundaries_observer.d.ts.map +1 -1
- package/dist/es2017/core/entry/content_time_boundaries_observer.js +18 -4
- 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/errors/index.d.ts +2 -2
- package/dist/es2017/errors/index.d.ts.map +1 -1
- package/dist/es2017/errors/index.js +2 -2
- package/dist/es2017/errors/media_error.d.ts +19 -4
- package/dist/es2017/errors/media_error.d.ts.map +1 -1
- package/dist/es2017/errors/media_error.js +28 -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 +60 -55
- 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 +5 -3
- 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__/content_time_boundaries_observer.test.ts +5 -0
- 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/content_time_boundaries_observer.ts +18 -4
- 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/errors/__tests__/media_error.test.ts +106 -3
- package/src/errors/index.ts +2 -1
- package/src/errors/media_error.ts +63 -7
- 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 +72 -60
- 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
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import
|
|
2
|
+
import type { ISerializedMediaError } from "../media_error";
|
|
3
|
+
import MediaError, { deserializeMediaError } from "../media_error";
|
|
3
4
|
|
|
4
5
|
describe("errors - MediaError", () => {
|
|
5
6
|
it("should format a MediaError", () => {
|
|
6
7
|
const reason = "test";
|
|
7
|
-
const mediaError = new MediaError("MEDIA_TIME_BEFORE_MANIFEST", reason
|
|
8
|
+
const mediaError = new MediaError("MEDIA_TIME_BEFORE_MANIFEST", reason, {
|
|
9
|
+
timeInfo: { position: 5, minPosition: 10, maxPosition: 100 },
|
|
10
|
+
});
|
|
8
11
|
expect(mediaError).toBeInstanceOf(Error);
|
|
9
12
|
expect(mediaError.name).toBe("MediaError");
|
|
10
13
|
expect(mediaError.type).toBe("MEDIA_ERROR");
|
|
@@ -15,7 +18,9 @@ describe("errors - MediaError", () => {
|
|
|
15
18
|
|
|
16
19
|
it("should be able to set it as fatal", () => {
|
|
17
20
|
const reason = "test";
|
|
18
|
-
const mediaError = new MediaError("MEDIA_TIME_AFTER_MANIFEST", reason
|
|
21
|
+
const mediaError = new MediaError("MEDIA_TIME_AFTER_MANIFEST", reason, {
|
|
22
|
+
timeInfo: { position: 5, minPosition: 10, maxPosition: 100 },
|
|
23
|
+
});
|
|
19
24
|
mediaError.fatal = true;
|
|
20
25
|
expect(mediaError).toBeInstanceOf(Error);
|
|
21
26
|
expect(mediaError.name).toBe("MediaError");
|
|
@@ -36,4 +41,102 @@ describe("errors - MediaError", () => {
|
|
|
36
41
|
expect(mediaError.fatal).toBe(true);
|
|
37
42
|
expect(mediaError.message).toBe("MEDIA_ERR_NETWORK: test");
|
|
38
43
|
});
|
|
44
|
+
|
|
45
|
+
it("should expose and serialize custom position metadata", () => {
|
|
46
|
+
const mediaError = new MediaError("MEDIA_TIME_BEFORE_MANIFEST", "test", {
|
|
47
|
+
timeInfo: {
|
|
48
|
+
position: 3,
|
|
49
|
+
minPosition: 10,
|
|
50
|
+
maxPosition: 20,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(mediaError.timeInfo).toEqual({
|
|
55
|
+
position: 3,
|
|
56
|
+
minPosition: 10,
|
|
57
|
+
maxPosition: 20,
|
|
58
|
+
});
|
|
59
|
+
expect(mediaError.serialize()).toEqual({
|
|
60
|
+
isSerializedError: true,
|
|
61
|
+
name: "MediaError",
|
|
62
|
+
code: "MEDIA_TIME_BEFORE_MANIFEST",
|
|
63
|
+
reason: "test",
|
|
64
|
+
tracks: undefined,
|
|
65
|
+
timeInfo: {
|
|
66
|
+
position: 3,
|
|
67
|
+
minPosition: 10,
|
|
68
|
+
maxPosition: 20,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should deserialize a serialized MediaError with timeInfo", () => {
|
|
74
|
+
const serializedError: ISerializedMediaError = {
|
|
75
|
+
isSerializedError: true,
|
|
76
|
+
name: "MediaError",
|
|
77
|
+
code: "MEDIA_TIME_BEFORE_MANIFEST",
|
|
78
|
+
reason: "test",
|
|
79
|
+
tracks: undefined,
|
|
80
|
+
timeInfo: {
|
|
81
|
+
position: 3,
|
|
82
|
+
minPosition: 10,
|
|
83
|
+
maxPosition: 20,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const mediaError = deserializeMediaError(serializedError);
|
|
88
|
+
|
|
89
|
+
expect(mediaError).toBeInstanceOf(MediaError);
|
|
90
|
+
expect(mediaError.code).toBe("MEDIA_TIME_BEFORE_MANIFEST");
|
|
91
|
+
expect(mediaError.message).toBe("MEDIA_TIME_BEFORE_MANIFEST: test");
|
|
92
|
+
expect(mediaError.timeInfo).toEqual(serializedError.timeInfo);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should deserialize a serialized MediaError with tracks", () => {
|
|
96
|
+
const serializedError: ISerializedMediaError = {
|
|
97
|
+
isSerializedError: true,
|
|
98
|
+
name: "MediaError",
|
|
99
|
+
code: "BUFFER_APPEND_ERROR",
|
|
100
|
+
reason: "test",
|
|
101
|
+
tracks: [
|
|
102
|
+
{
|
|
103
|
+
type: "audio",
|
|
104
|
+
track: {
|
|
105
|
+
id: "fra1",
|
|
106
|
+
audioDescription: false,
|
|
107
|
+
language: "fra",
|
|
108
|
+
normalized: "fra",
|
|
109
|
+
representations: [],
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
timeInfo: undefined,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const mediaError = deserializeMediaError(serializedError);
|
|
117
|
+
|
|
118
|
+
expect(mediaError).toBeInstanceOf(MediaError);
|
|
119
|
+
expect(mediaError.code).toBe("BUFFER_APPEND_ERROR");
|
|
120
|
+
expect(mediaError.message).toBe("BUFFER_APPEND_ERROR: test");
|
|
121
|
+
expect(mediaError.tracksInfo).toEqual(serializedError.tracks);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should deserialize a serialized MediaError without metadata", () => {
|
|
125
|
+
const serializedError = {
|
|
126
|
+
isSerializedError: true as const,
|
|
127
|
+
name: "MediaError" as const,
|
|
128
|
+
code: "MEDIA_ERR_NETWORK" as const,
|
|
129
|
+
reason: "test",
|
|
130
|
+
tracks: undefined,
|
|
131
|
+
timeInfo: undefined,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const mediaError = deserializeMediaError(serializedError);
|
|
135
|
+
|
|
136
|
+
expect(mediaError).toBeInstanceOf(MediaError);
|
|
137
|
+
expect(mediaError.code).toBe("MEDIA_ERR_NETWORK");
|
|
138
|
+
expect(mediaError.message).toBe("MEDIA_ERR_NETWORK: test");
|
|
139
|
+
expect(mediaError.timeInfo).toBeUndefined();
|
|
140
|
+
expect(mediaError.tracksInfo).toBeUndefined();
|
|
141
|
+
});
|
|
39
142
|
});
|
package/src/errors/index.ts
CHANGED
|
@@ -22,7 +22,7 @@ import { ErrorCodes, ErrorTypes, NetworkErrorTypes } from "./error_codes";
|
|
|
22
22
|
import formatError from "./format_error";
|
|
23
23
|
import isKnownError from "./is_known_error";
|
|
24
24
|
import type { ISerializedMediaError } from "./media_error";
|
|
25
|
-
import MediaError from "./media_error";
|
|
25
|
+
import MediaError, { deserializeMediaError } from "./media_error";
|
|
26
26
|
import type { ISerializedNetworkError } from "./network_error";
|
|
27
27
|
import NetworkError from "./network_error";
|
|
28
28
|
import type { ISerializedOtherError } from "./other_error";
|
|
@@ -46,6 +46,7 @@ export {
|
|
|
46
46
|
ErrorTypes,
|
|
47
47
|
formatError,
|
|
48
48
|
MediaError,
|
|
49
|
+
deserializeMediaError,
|
|
49
50
|
NetworkError,
|
|
50
51
|
OtherError,
|
|
51
52
|
NetworkErrorTypes,
|
|
@@ -15,16 +15,27 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import type { ITaggedTrack } from "../manifest";
|
|
18
|
+
import assert from "../utils/assert";
|
|
18
19
|
import type { IMediaErrorCode } from "./error_codes";
|
|
19
20
|
import { ErrorTypes } from "./error_codes";
|
|
20
21
|
import errorMessage from "./error_message";
|
|
21
22
|
|
|
22
|
-
type ICodeWithAdaptationType =
|
|
23
|
+
export type ICodeWithAdaptationType =
|
|
23
24
|
| "BUFFER_APPEND_ERROR"
|
|
24
25
|
| "BUFFER_FULL_ERROR"
|
|
25
26
|
| "NO_PLAYABLE_REPRESENTATION"
|
|
26
27
|
| "MANIFEST_INCOMPATIBLE_CODECS_ERROR";
|
|
27
28
|
|
|
29
|
+
export type ICodeWithManifestPositionError =
|
|
30
|
+
| "MEDIA_TIME_BEFORE_MANIFEST"
|
|
31
|
+
| "MEDIA_TIME_AFTER_MANIFEST";
|
|
32
|
+
|
|
33
|
+
interface ITimeInfo {
|
|
34
|
+
position: number;
|
|
35
|
+
minPosition: number;
|
|
36
|
+
maxPosition: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
28
39
|
/**
|
|
29
40
|
* Error linked to the media Playback.
|
|
30
41
|
*
|
|
@@ -36,6 +47,7 @@ export default class MediaError extends Error {
|
|
|
36
47
|
public readonly type: "MEDIA_ERROR";
|
|
37
48
|
public readonly code: IMediaErrorCode;
|
|
38
49
|
public readonly tracksInfo: ITaggedTrack[] | undefined;
|
|
50
|
+
public readonly timeInfo: ITimeInfo | undefined;
|
|
39
51
|
public fatal: boolean;
|
|
40
52
|
private _originalMessage: string;
|
|
41
53
|
|
|
@@ -52,13 +64,18 @@ export default class MediaError extends Error {
|
|
|
52
64
|
},
|
|
53
65
|
);
|
|
54
66
|
constructor(
|
|
55
|
-
code:
|
|
67
|
+
code: ICodeWithManifestPositionError,
|
|
68
|
+
reason: string,
|
|
69
|
+
context: {
|
|
70
|
+
timeInfo: ITimeInfo;
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
constructor(
|
|
74
|
+
code: Exclude<
|
|
75
|
+
IMediaErrorCode,
|
|
76
|
+
ICodeWithAdaptationType | ICodeWithManifestPositionError
|
|
77
|
+
>,
|
|
56
78
|
reason: string,
|
|
57
|
-
context?:
|
|
58
|
-
| {
|
|
59
|
-
tracks?: undefined;
|
|
60
|
-
}
|
|
61
|
-
| undefined,
|
|
62
79
|
);
|
|
63
80
|
constructor(
|
|
64
81
|
code: IMediaErrorCode,
|
|
@@ -66,6 +83,7 @@ export default class MediaError extends Error {
|
|
|
66
83
|
context?:
|
|
67
84
|
| {
|
|
68
85
|
tracks?: ITaggedTrack[] | undefined;
|
|
86
|
+
timeInfo?: ITimeInfo;
|
|
69
87
|
}
|
|
70
88
|
| undefined,
|
|
71
89
|
) {
|
|
@@ -82,6 +100,9 @@ export default class MediaError extends Error {
|
|
|
82
100
|
if (context?.tracks !== undefined && context?.tracks.length > 0) {
|
|
83
101
|
this.tracksInfo = context.tracks;
|
|
84
102
|
}
|
|
103
|
+
if (context?.timeInfo !== undefined) {
|
|
104
|
+
this.timeInfo = context.timeInfo;
|
|
105
|
+
}
|
|
85
106
|
}
|
|
86
107
|
|
|
87
108
|
/**
|
|
@@ -97,10 +118,44 @@ export default class MediaError extends Error {
|
|
|
97
118
|
code: this.code,
|
|
98
119
|
reason: this._originalMessage,
|
|
99
120
|
tracks: this.tracksInfo,
|
|
121
|
+
timeInfo: this.timeInfo,
|
|
100
122
|
};
|
|
101
123
|
}
|
|
102
124
|
}
|
|
103
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Re-create a `MediaError` from a serialized representation.
|
|
128
|
+
* @param {Object} serializedMediaError
|
|
129
|
+
* @returns {MediaError}
|
|
130
|
+
*/
|
|
131
|
+
export function deserializeMediaError(
|
|
132
|
+
serializedMediaError: ISerializedMediaError,
|
|
133
|
+
): MediaError {
|
|
134
|
+
if (
|
|
135
|
+
serializedMediaError.code === "MEDIA_TIME_BEFORE_MANIFEST" ||
|
|
136
|
+
serializedMediaError.code === "MEDIA_TIME_AFTER_MANIFEST"
|
|
137
|
+
) {
|
|
138
|
+
assert(
|
|
139
|
+
serializedMediaError.timeInfo !== undefined,
|
|
140
|
+
`The MediaError with code ${serializedMediaError.code} does not provide "timeinfo"`,
|
|
141
|
+
);
|
|
142
|
+
return new MediaError(serializedMediaError.code, serializedMediaError.reason, {
|
|
143
|
+
timeInfo: serializedMediaError.timeInfo,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
if (
|
|
147
|
+
serializedMediaError.code === "BUFFER_APPEND_ERROR" ||
|
|
148
|
+
serializedMediaError.code === "BUFFER_FULL_ERROR" ||
|
|
149
|
+
serializedMediaError.code === "NO_PLAYABLE_REPRESENTATION" ||
|
|
150
|
+
serializedMediaError.code === "MANIFEST_INCOMPATIBLE_CODECS_ERROR"
|
|
151
|
+
) {
|
|
152
|
+
return new MediaError(serializedMediaError.code, serializedMediaError.reason, {
|
|
153
|
+
tracks: serializedMediaError.tracks,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return new MediaError(serializedMediaError.code, serializedMediaError.reason);
|
|
157
|
+
}
|
|
158
|
+
|
|
104
159
|
/** Serializable object which allows to create a `MediaError` later. */
|
|
105
160
|
export interface ISerializedMediaError {
|
|
106
161
|
isSerializedError: true;
|
|
@@ -108,4 +163,5 @@ export interface ISerializedMediaError {
|
|
|
108
163
|
code: IMediaErrorCode;
|
|
109
164
|
reason: string;
|
|
110
165
|
tracks: ITaggedTrack[] | undefined;
|
|
166
|
+
timeInfo?: ITimeInfo | undefined;
|
|
111
167
|
}
|
|
@@ -15,5 +15,5 @@ is mainly to confine the "library path" of that feature to the
|
|
|
15
15
|
`rx-player/experimental/features` subdirectory.
|
|
16
16
|
|
|
17
17
|
Note that tools NEED to be declared in their own directory inside a `./tools/<TOOL_NAME>`
|
|
18
|
-
directory, with their inner `index.
|
|
18
|
+
directory, with their inner `index.ts` file exporting them, as that's a requirement from
|
|
19
19
|
our exporting strategy.
|
package/src/features/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
This directory regroups the code importing all the "features" of the RxPlayer piece by
|
|
4
4
|
piece.
|
|
5
5
|
|
|
6
|
-
It is mostly used for allowing a library user to only
|
|
7
|
-
|
|
6
|
+
It is mostly used for allowing a library user to import only some features of the RxPlayer
|
|
7
|
+
without importing others.
|
|
8
8
|
|
|
9
9
|
How this is technically done is through a global `features` Object, which will have added
|
|
10
10
|
properties (which corresponds to those features' code) each time a new feature is added.
|
|
@@ -12,4 +12,4 @@ properties (which corresponds to those features' code) each time a new feature i
|
|
|
12
12
|
## For workers
|
|
13
13
|
|
|
14
14
|
The `worker` directory contains features intended for the worker-side that will then be
|
|
15
|
-
exported through the RxPlayer's `worker/features` path.
|
|
15
|
+
exported through the RxPlayer's `experimental/worker/features` path.
|
|
@@ -20,13 +20,12 @@ As such, its main roles are to:
|
|
|
20
20
|
|
|
21
21
|
To facilitate those actions, the API relies on multiple building blocks:
|
|
22
22
|
|
|
23
|
-
- **the `PlaybackObserver` (./playback_observer.ts)**
|
|
24
|
-
|
|
25
|
-
Provide multiple methods allowing to monitor the current playback conditions (e.g. the
|
|
26
|
-
current position and/or the current playback rate). Many RxPlayer modules rely on this
|
|
27
|
-
PlaybackObserver.
|
|
28
|
-
|
|
29
23
|
- **the `option utils` (./option_utils.ts)**
|
|
30
24
|
|
|
31
25
|
Parse options given to some RxPlayer API calls, to add default parameters and provide
|
|
32
|
-
|
|
26
|
+
intelligible warnings/errors
|
|
27
|
+
|
|
28
|
+
- **the `debug` directory (./debug/)**
|
|
29
|
+
|
|
30
|
+
Contains the logic for the debug overlay API, (e.g. that can be rendered through the
|
|
31
|
+
`createDebugElement` RxPlayer API)
|
|
@@ -437,7 +437,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
437
437
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
|
|
438
438
|
videoElement.preload = "auto";
|
|
439
439
|
|
|
440
|
-
this.version = /* PLAYER_VERSION */ "4.5.0-dev.
|
|
440
|
+
this.version = /* PLAYER_VERSION */ "4.5.0-dev.2026043000";
|
|
441
441
|
this.log = log;
|
|
442
442
|
this.state = "STOPPED";
|
|
443
443
|
this.videoElement = videoElement;
|
|
@@ -1244,31 +1244,31 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
1244
1244
|
) {
|
|
1245
1245
|
log.warn(
|
|
1246
1246
|
"API",
|
|
1247
|
-
"You
|
|
1247
|
+
"You set a `representationFilter` function without a `workerId` while loading in multithread mode. That function cannot run in the worker, so it will be ignored.",
|
|
1248
1248
|
);
|
|
1249
1249
|
}
|
|
1250
1250
|
}
|
|
1251
1251
|
if (
|
|
1252
1252
|
transportOptions.manifestLoader !== undefined &&
|
|
1253
|
-
!isNullOrUndefined(transportOptions.manifestLoader.
|
|
1253
|
+
!isNullOrUndefined(transportOptions.manifestLoader.fn)
|
|
1254
1254
|
) {
|
|
1255
1255
|
transportOptions.manifestLoader.fn = undefined;
|
|
1256
|
-
if (isNullOrUndefined(transportOptions.manifestLoader.
|
|
1256
|
+
if (isNullOrUndefined(transportOptions.manifestLoader.workerId)) {
|
|
1257
1257
|
log.warn(
|
|
1258
1258
|
"API",
|
|
1259
|
-
"You
|
|
1259
|
+
"You set a `manifestLoader` function without a `workerId` while loading in multithread mode. That function cannot run in the worker, so it will be ignored.",
|
|
1260
1260
|
);
|
|
1261
1261
|
}
|
|
1262
1262
|
}
|
|
1263
1263
|
if (
|
|
1264
1264
|
transportOptions.segmentLoader !== undefined &&
|
|
1265
|
-
!isNullOrUndefined(transportOptions.segmentLoader.
|
|
1265
|
+
!isNullOrUndefined(transportOptions.segmentLoader.fn)
|
|
1266
1266
|
) {
|
|
1267
1267
|
transportOptions.segmentLoader.fn = undefined;
|
|
1268
|
-
if (isNullOrUndefined(transportOptions.segmentLoader.
|
|
1268
|
+
if (isNullOrUndefined(transportOptions.segmentLoader.workerId)) {
|
|
1269
1269
|
log.warn(
|
|
1270
1270
|
"API",
|
|
1271
|
-
"You
|
|
1271
|
+
"You set a `segmentLoader` function without a `workerId` while loading in multithread mode. That function cannot run in the worker, so it will be ignored.",
|
|
1272
1272
|
);
|
|
1273
1273
|
}
|
|
1274
1274
|
}
|
|
@@ -3029,6 +3029,9 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
3029
3029
|
contentInfos: IPublicApiContentInfos,
|
|
3030
3030
|
updates: IPeriodsUpdateResult,
|
|
3031
3031
|
): void {
|
|
3032
|
+
if (contentInfos.contentId !== this._priv_contentInfos?.contentId) {
|
|
3033
|
+
return; // Event for another content
|
|
3034
|
+
}
|
|
3032
3035
|
if (this._priv_contentInfos === null || this._priv_contentInfos.manifest === null) {
|
|
3033
3036
|
return;
|
|
3034
3037
|
}
|
|
@@ -3210,7 +3213,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
3210
3213
|
"audioRepresentationChange",
|
|
3211
3214
|
isNullOrUndefined(audioRepresentation)
|
|
3212
3215
|
? audioRepresentation
|
|
3213
|
-
:
|
|
3216
|
+
: toAudioRepresentation(audioRepresentation),
|
|
3214
3217
|
cancelSignal,
|
|
3215
3218
|
);
|
|
3216
3219
|
const videoRepresentation = this.__priv_getCurrentRepresentations()?.video ?? null;
|
|
@@ -3747,6 +3750,9 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
3747
3750
|
* to the content for which the error was received.
|
|
3748
3751
|
*/
|
|
3749
3752
|
private _priv_onFatalError(err: unknown, contentInfos: IPublicApiContentInfos): void {
|
|
3753
|
+
if (contentInfos.contentId !== this._priv_contentInfos?.contentId) {
|
|
3754
|
+
return; // Event for another content
|
|
3755
|
+
}
|
|
3750
3756
|
const formattedError = formatError(err, {
|
|
3751
3757
|
defaultCode: "NONE",
|
|
3752
3758
|
defaultReason: "An unknown error stopped content playback.",
|
|
@@ -3831,7 +3837,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
|
|
|
3831
3837
|
return true;
|
|
3832
3838
|
}
|
|
3833
3839
|
}
|
|
3834
|
-
Player.version = /* PLAYER_VERSION */ "4.5.0-dev.
|
|
3840
|
+
Player.version = /* PLAYER_VERSION */ "4.5.0-dev.2026043000";
|
|
3835
3841
|
|
|
3836
3842
|
/** Every events sent by the RxPlayer's public API. */
|
|
3837
3843
|
interface IPublicAPIEvent {
|
|
@@ -12,11 +12,11 @@ imported by outside code).
|
|
|
12
12
|
## Overview
|
|
13
13
|
|
|
14
14
|
This directory exports the `ContentDecryptor`, which allows to easily interface with the
|
|
15
|
-
browser APIs for decrypting
|
|
16
|
-
[Encrypted Media Extensions
|
|
15
|
+
browser APIs for decrypting encrypted content. It follows the
|
|
16
|
+
[Encrypted Media Extensions recommendations](https://www.w3.org/TR/encrypted-media/).
|
|
17
17
|
|
|
18
|
-
The `ContentDecryptor` is a module isolated from the rest of the player taking
|
|
19
|
-
class. It starts initializing decryption capabilities as soon as it is
|
|
18
|
+
The `ContentDecryptor` is a module isolated from the rest of the player taking the form of
|
|
19
|
+
a class. It starts initializing decryption capabilities as soon as it is instantiated and
|
|
20
20
|
emits various events to communicate with external code.
|
|
21
21
|
|
|
22
22
|
A central concept of the `ContentDecryptor` is its states. As decryption initialization
|
|
@@ -1,10 +1,52 @@
|
|
|
1
1
|
import { describe, beforeEach, it, expect, vi } from "vitest";
|
|
2
|
+
import getEmeApiImplementation from "../../../../compat/eme";
|
|
3
|
+
import { EncryptedMediaError } from "../../../../errors";
|
|
4
|
+
import type { IKeySystemOption } from "../../../../public_types";
|
|
5
|
+
import assert from "../../../../utils/assert";
|
|
2
6
|
import { getMissingKeyIds } from "../../content_decryptor";
|
|
7
|
+
import { ContentDecryptorState } from "../../types";
|
|
8
|
+
import { defaultKSConfig, mockCompat } from "./utils";
|
|
9
|
+
|
|
10
|
+
const mocks = vi.hoisted(() => {
|
|
11
|
+
return {
|
|
12
|
+
shouldRenewMediaKeySystemAccess: vi.fn(() => false),
|
|
13
|
+
canReuseMediaKeys: vi.fn(() => true),
|
|
14
|
+
onEncrypted: vi.fn(),
|
|
15
|
+
requestMediaKeySystemAccess: vi.fn(),
|
|
16
|
+
setMediaKeys: vi.fn(),
|
|
17
|
+
getInitData: vi.fn(),
|
|
18
|
+
generateKeyRequest: vi.fn(),
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
vi.mock("../../../../compat/should_renew_media_key_system_access", () => ({
|
|
22
|
+
default: mocks.shouldRenewMediaKeySystemAccess,
|
|
23
|
+
}));
|
|
24
|
+
vi.mock("../../../../compat/can_reuse_media_keys", () => ({
|
|
25
|
+
default: mocks.canReuseMediaKeys,
|
|
26
|
+
}));
|
|
27
|
+
vi.mock("../../../../compat/eme", () => ({
|
|
28
|
+
default: () => ({
|
|
29
|
+
onEncrypted: mocks.onEncrypted,
|
|
30
|
+
requestMediaKeySystemAccess: mocks.requestMediaKeySystemAccess,
|
|
31
|
+
setMediaKeys: mocks.setMediaKeys,
|
|
32
|
+
}),
|
|
33
|
+
getInitData: mocks.getInitData,
|
|
34
|
+
generateKeyRequest: mocks.generateKeyRequest,
|
|
35
|
+
closeSession: vi.fn(),
|
|
36
|
+
loadSession: vi.fn(),
|
|
37
|
+
}));
|
|
3
38
|
|
|
4
39
|
describe("content_decryptor - blacklist missing key Ids", () => {
|
|
5
40
|
beforeEach(() => {
|
|
6
41
|
vi.resetModules();
|
|
7
42
|
vi.restoreAllMocks();
|
|
43
|
+
mocks.shouldRenewMediaKeySystemAccess.mockReset();
|
|
44
|
+
mocks.canReuseMediaKeys.mockReset();
|
|
45
|
+
mocks.onEncrypted.mockReset();
|
|
46
|
+
mocks.requestMediaKeySystemAccess.mockReset();
|
|
47
|
+
mocks.setMediaKeys.mockReset();
|
|
48
|
+
mocks.getInitData.mockReset();
|
|
49
|
+
mocks.generateKeyRequest.mockReset();
|
|
8
50
|
});
|
|
9
51
|
|
|
10
52
|
it("should return an empty array if actualKeyIds contains all expectedKeyIds", () => {
|
|
@@ -43,3 +85,96 @@ describe("content_decryptor - blacklist missing key Ids", () => {
|
|
|
43
85
|
expect(result).toEqual([new Uint8Array([2]), new Uint8Array([4])]);
|
|
44
86
|
});
|
|
45
87
|
});
|
|
88
|
+
|
|
89
|
+
describe("content_decryptor - session decommissioning", () => {
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
vi.resetModules();
|
|
92
|
+
vi.restoreAllMocks();
|
|
93
|
+
mocks.shouldRenewMediaKeySystemAccess.mockReset();
|
|
94
|
+
mocks.canReuseMediaKeys.mockReset();
|
|
95
|
+
mocks.onEncrypted.mockReset();
|
|
96
|
+
mocks.requestMediaKeySystemAccess.mockReset();
|
|
97
|
+
mocks.setMediaKeys.mockReset();
|
|
98
|
+
mocks.getInitData.mockReset();
|
|
99
|
+
mocks.generateKeyRequest.mockReset();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("should only remove the decommissioned session from tracked sessions", async () => {
|
|
103
|
+
vi.resetModules();
|
|
104
|
+
const videoElt = document.createElement("video");
|
|
105
|
+
mockCompat(mocks);
|
|
106
|
+
const sessionCallbacks: Array<{ onError: (err: unknown) => void }> = [];
|
|
107
|
+
vi.doMock("../../session_events_listener", () => ({
|
|
108
|
+
__esModule: true,
|
|
109
|
+
default: vi.fn(
|
|
110
|
+
(_session: unknown, _options: unknown, _access: unknown, callbacks: unknown) => {
|
|
111
|
+
sessionCallbacks.push(callbacks as { onError: (err: unknown) => void });
|
|
112
|
+
},
|
|
113
|
+
),
|
|
114
|
+
BlacklistedSessionError: class BlacklistedSessionError extends Error {},
|
|
115
|
+
}));
|
|
116
|
+
const { DecommissionedSessionError } = await import("../../utils/check_key_statuses");
|
|
117
|
+
const { default: ContentDecryptor } = await import("../../content_decryptor");
|
|
118
|
+
|
|
119
|
+
const mockGetLicense = vi.fn(() => Promise.resolve(new Uint8Array([1, 2, 3, 4])));
|
|
120
|
+
const ksConfig: IKeySystemOption[] = [
|
|
121
|
+
{
|
|
122
|
+
type: "com.widevine.alpha",
|
|
123
|
+
getLicense: mockGetLicense,
|
|
124
|
+
onKeyInternalError: "close-session",
|
|
125
|
+
},
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
const eme = getEmeApiImplementation("auto");
|
|
129
|
+
assert(eme !== null, "Expected to have an EME implementation");
|
|
130
|
+
const contentDecryptor = new ContentDecryptor(eme, videoElt, ksConfig);
|
|
131
|
+
|
|
132
|
+
await new Promise<void>((res, rej) => {
|
|
133
|
+
contentDecryptor.addEventListener("stateChange", (state) => {
|
|
134
|
+
if (state !== ContentDecryptorState.WaitingForAttachment) {
|
|
135
|
+
rej(new Error(`Unexpected state: ${state}`));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
contentDecryptor.removeEventListener("stateChange");
|
|
139
|
+
contentDecryptor.attach();
|
|
140
|
+
res();
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
contentDecryptor.onInitializationData({
|
|
145
|
+
type: "cenc",
|
|
146
|
+
values: [{ systemId: "15", data: new Uint8Array([1, 1, 1]) }],
|
|
147
|
+
});
|
|
148
|
+
contentDecryptor.onInitializationData({
|
|
149
|
+
type: "cenc",
|
|
150
|
+
values: [{ systemId: "15", data: new Uint8Array([2, 2, 2]) }],
|
|
151
|
+
});
|
|
152
|
+
contentDecryptor.onInitializationData({
|
|
153
|
+
type: "cenc",
|
|
154
|
+
values: [{ systemId: "15", data: new Uint8Array([3, 3, 3]) }],
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
await new Promise((res) => setTimeout(res, 120));
|
|
158
|
+
|
|
159
|
+
expect(
|
|
160
|
+
(contentDecryptor as unknown as { _currentSessions: unknown[] })._currentSessions,
|
|
161
|
+
).toHaveLength(3);
|
|
162
|
+
|
|
163
|
+
sessionCallbacks[1].onError(
|
|
164
|
+
new DecommissionedSessionError(
|
|
165
|
+
new EncryptedMediaError("KEY_LOAD_ERROR", "forced decommissioning", {
|
|
166
|
+
keyStatuses: undefined,
|
|
167
|
+
keySystemConfiguration: defaultKSConfig[0],
|
|
168
|
+
keySystem: "com.widevine.alpha",
|
|
169
|
+
}),
|
|
170
|
+
),
|
|
171
|
+
);
|
|
172
|
+
await new Promise((res) => setTimeout(res, 30));
|
|
173
|
+
|
|
174
|
+
expect(
|
|
175
|
+
(contentDecryptor as unknown as { _currentSessions: unknown[] })._currentSessions,
|
|
176
|
+
).toHaveLength(2);
|
|
177
|
+
|
|
178
|
+
contentDecryptor.dispose(undefined);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
@@ -284,6 +284,76 @@ describe("decrypt - global tests - getLicense", () => {
|
|
|
284
284
|
ignoreLicenseRequests: false,
|
|
285
285
|
});
|
|
286
286
|
}, 15000);
|
|
287
|
+
|
|
288
|
+
it("should emit KEY_LOAD_TIMEOUT when getLicense times out", async () => {
|
|
289
|
+
const initData = new Uint8Array([54, 55, 75]);
|
|
290
|
+
const initDataEvent = {
|
|
291
|
+
type: "cenc",
|
|
292
|
+
values: [{ systemId: "15", data: initData }],
|
|
293
|
+
};
|
|
294
|
+
const challenge = formatFakeChallengeFromInitData(initData, "cenc");
|
|
295
|
+
const mediaKeySession = new MediaKeySessionImpl();
|
|
296
|
+
vi.spyOn(MediaKeysImpl.prototype, "createSession").mockReturnValue(mediaKeySession);
|
|
297
|
+
const mockGetLicense = vi.fn(() => {
|
|
298
|
+
return new Promise<BufferSource>((resolve) => {
|
|
299
|
+
setTimeout(() => {
|
|
300
|
+
resolve(challenge);
|
|
301
|
+
}, 30);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const videoElt = document.createElement("video");
|
|
306
|
+
mockCompat(mocks);
|
|
307
|
+
|
|
308
|
+
await new Promise<void>((res, rej) => {
|
|
309
|
+
const ksConfig: IKeySystemOption[] = [
|
|
310
|
+
{
|
|
311
|
+
type: "com.widevine.alpha",
|
|
312
|
+
getLicense: mockGetLicense,
|
|
313
|
+
getLicenseConfig: {
|
|
314
|
+
retry: 0,
|
|
315
|
+
timeout: 5,
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
];
|
|
319
|
+
const eme = getEmeApiImplementation("auto");
|
|
320
|
+
assert(eme !== null);
|
|
321
|
+
const contentDecryptor = new ContentDecryptor(eme, videoElt, ksConfig);
|
|
322
|
+
|
|
323
|
+
contentDecryptor.addEventListener("stateChange", (newState: number) => {
|
|
324
|
+
if (newState !== ContentDecryptorState.WaitingForAttachment) {
|
|
325
|
+
rej(new Error(`Unexpected state: ${newState}`));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
contentDecryptor.removeEventListener("stateChange");
|
|
329
|
+
contentDecryptor.attach();
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
contentDecryptor.addEventListener("warning", (warning: Error) => {
|
|
333
|
+
rej(new Error(`Unexpected warning: ${warning.toString()}`));
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
contentDecryptor.addEventListener("error", (error: Error) => {
|
|
337
|
+
try {
|
|
338
|
+
expect(error).toBeInstanceOf(Error);
|
|
339
|
+
expect((error as IPlayerError).name).toEqual("EncryptedMediaError");
|
|
340
|
+
expect((error as IPlayerError).type).toEqual("ENCRYPTED_MEDIA_ERROR");
|
|
341
|
+
expect((error as IPlayerError).code).toEqual("KEY_LOAD_TIMEOUT");
|
|
342
|
+
expect((error as IPlayerError).message).toEqual(
|
|
343
|
+
"KEY_LOAD_TIMEOUT: The license server took too much time to respond.",
|
|
344
|
+
);
|
|
345
|
+
expect(mockGetLicense).toHaveBeenCalledTimes(1);
|
|
346
|
+
expect(mockGetLicense).toHaveBeenNthCalledWith(1, challenge, "license-request");
|
|
347
|
+
contentDecryptor.dispose(undefined);
|
|
348
|
+
res();
|
|
349
|
+
} catch (e) {
|
|
350
|
+
rej(e);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
contentDecryptor.onInitializationData(initDataEvent);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
287
357
|
});
|
|
288
358
|
|
|
289
359
|
/**
|