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
|
@@ -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.2026041501";
|
|
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.2026041501";
|
|
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
|
/**
|
|
@@ -291,4 +291,48 @@ describe("decrypt - global tests - server certificate", () => {
|
|
|
291
291
|
}, 10);
|
|
292
292
|
});
|
|
293
293
|
});
|
|
294
|
+
|
|
295
|
+
it("should continue if setServerCertificate resolves to false and retry later", () => {
|
|
296
|
+
const videoElt = document.createElement("video");
|
|
297
|
+
mockCompat(mocks);
|
|
298
|
+
const mockSetServerCertificate = vi
|
|
299
|
+
.spyOn(MediaKeysImpl.prototype, "setServerCertificate")
|
|
300
|
+
.mockImplementationOnce((_serverCertificate: BufferSource): Promise<false> => {
|
|
301
|
+
return Promise.resolve(false);
|
|
302
|
+
})
|
|
303
|
+
.mockImplementationOnce((_serverCertificate: BufferSource): Promise<true> => {
|
|
304
|
+
return Promise.resolve(true);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const eme = getEmeApiImplementation("auto");
|
|
308
|
+
assert(eme !== null, "Expected to have an EME implementation");
|
|
309
|
+
const firstDecryptor = new ContentDecryptor(eme, videoElt, ksConfigCert);
|
|
310
|
+
|
|
311
|
+
return new Promise<void>((res) => {
|
|
312
|
+
firstDecryptor.addEventListener("stateChange", (state) => {
|
|
313
|
+
if (state === ContentDecryptorState.WaitingForAttachment) {
|
|
314
|
+
firstDecryptor.removeEventListener("stateChange");
|
|
315
|
+
firstDecryptor.attach();
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
setTimeout(() => {
|
|
320
|
+
firstDecryptor.dispose(undefined);
|
|
321
|
+
|
|
322
|
+
const secondDecryptor = new ContentDecryptor(eme, videoElt, ksConfigCert);
|
|
323
|
+
secondDecryptor.addEventListener("stateChange", (state) => {
|
|
324
|
+
if (state === ContentDecryptorState.WaitingForAttachment) {
|
|
325
|
+
secondDecryptor.removeEventListener("stateChange");
|
|
326
|
+
secondDecryptor.attach();
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
setTimeout(() => {
|
|
331
|
+
secondDecryptor.dispose(undefined);
|
|
332
|
+
expect(mockSetServerCertificate).toHaveBeenCalledTimes(2);
|
|
333
|
+
res();
|
|
334
|
+
}, 10);
|
|
335
|
+
}, 10);
|
|
336
|
+
});
|
|
337
|
+
});
|
|
294
338
|
});
|
|
@@ -121,7 +121,7 @@ export class MediaKeyStatusMapImpl {
|
|
|
121
121
|
) => void,
|
|
122
122
|
thisArg?: unknown,
|
|
123
123
|
): void {
|
|
124
|
-
this._map.forEach((value, key) => callbackfn.
|
|
124
|
+
this._map.forEach((value, key) => callbackfn.call(thisArg, value, key, this));
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
public _setKeyStatus(keyId: BufferSource, value: MediaKeyStatus | undefined): void {
|
|
@@ -222,7 +222,7 @@ export class MediaKeysImpl {
|
|
|
222
222
|
return new MediaKeySessionImpl();
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
setServerCertificate(_serverCertificate: BufferSource): Promise<
|
|
225
|
+
setServerCertificate(_serverCertificate: BufferSource): Promise<boolean> {
|
|
226
226
|
return Promise.resolve(true);
|
|
227
227
|
}
|
|
228
228
|
}
|
|
@@ -309,6 +309,11 @@ export default class ContentDecryptor extends EventEmitter<IContentDecryptorEven
|
|
|
309
309
|
);
|
|
310
310
|
if (resSsc.type === "error") {
|
|
311
311
|
this.trigger("warning", resSsc.value);
|
|
312
|
+
} else if (resSsc.type === "not-supported") {
|
|
313
|
+
log.warn(
|
|
314
|
+
"DRM",
|
|
315
|
+
"Server certificate is not supported by the current MediaKeys.",
|
|
316
|
+
);
|
|
312
317
|
}
|
|
313
318
|
}
|
|
314
319
|
|
|
@@ -654,7 +659,7 @@ export default class ContentDecryptor extends EventEmitter<IContentDecryptorEven
|
|
|
654
659
|
this._lockInitDataQueue();
|
|
655
660
|
const indexOf = this._currentSessions.indexOf(sessionInfo);
|
|
656
661
|
if (indexOf >= 0) {
|
|
657
|
-
this._currentSessions.splice(indexOf);
|
|
662
|
+
this._currentSessions.splice(indexOf, 1);
|
|
658
663
|
}
|
|
659
664
|
if (initializationData.content !== undefined) {
|
|
660
665
|
this.trigger("keyIdsCompatibilityUpdate", {
|
|
@@ -400,7 +400,7 @@ export class GetLicenseTimeoutError extends Error {
|
|
|
400
400
|
constructor(message: string) {
|
|
401
401
|
super(message);
|
|
402
402
|
// @see https://stackoverflow.com/questions/41102060/typescript-extending-error-class
|
|
403
|
-
Object.setPrototypeOf(this,
|
|
403
|
+
Object.setPrototypeOf(this, GetLicenseTimeoutError.prototype);
|
|
404
404
|
this.message = message;
|
|
405
405
|
}
|
|
406
406
|
}
|
|
@@ -84,6 +84,7 @@ export default async function trySettingServerCertificate(
|
|
|
84
84
|
): Promise<
|
|
85
85
|
| { type: "success"; value: unknown }
|
|
86
86
|
| { type: "already-has-one" }
|
|
87
|
+
| { type: "not-supported" }
|
|
87
88
|
| { type: "method-not-implemented" }
|
|
88
89
|
| { type: "error"; value: IPlayerError }
|
|
89
90
|
> {
|
|
@@ -112,6 +113,10 @@ export default async function trySettingServerCertificate(
|
|
|
112
113
|
serverCertificate,
|
|
113
114
|
mediaKeySystemAccess,
|
|
114
115
|
);
|
|
116
|
+
if (result === false) {
|
|
117
|
+
log.warn("DRM", "MediaKeys ignored the server certificate. Continuing without it.");
|
|
118
|
+
return { type: "not-supported" };
|
|
119
|
+
}
|
|
115
120
|
ServerCertificateStore.set(mediaKeys, serverCertificate);
|
|
116
121
|
return { type: "success", value: result };
|
|
117
122
|
} catch (error) {
|