rx-player 4.0.0-beta.0 → 4.0.0-beta.2
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/.eslintrc.js +8 -0
- package/CHANGELOG.md +93 -0
- package/CONTRIBUTING.md +48 -168
- package/FILES.md +40 -92
- package/VERSION +1 -1
- package/dist/_esm5.processed/compat/browser_detection.d.ts +25 -12
- package/dist/_esm5.processed/compat/browser_detection.js +85 -38
- package/dist/_esm5.processed/compat/can_reuse_media_keys.js +2 -2
- package/dist/_esm5.processed/compat/eme/close_session.js +2 -2
- package/dist/_esm5.processed/compat/eme/load_session.js +1 -1
- package/dist/_esm5.processed/compat/event_listeners.js +1 -1
- package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.d.ts +21 -0
- package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.js +26 -0
- package/dist/_esm5.processed/config.d.ts +4 -0
- package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +9 -6
- package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.d.ts +18 -1
- package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.js +106 -25
- package/dist/_esm5.processed/core/adaptive/guess_based_chooser.js +6 -6
- package/dist/_esm5.processed/core/adaptive/network_analyzer.js +8 -5
- package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.d.ts +19 -1
- package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.js +1 -1
- package/dist/_esm5.processed/core/api/debug/buffer_graph.d.ts +28 -0
- package/dist/_esm5.processed/core/api/debug/buffer_graph.js +175 -0
- package/dist/_esm5.processed/core/api/debug/buffer_size_graph.d.ts +10 -0
- package/dist/_esm5.processed/core/api/debug/buffer_size_graph.js +104 -0
- package/dist/_esm5.processed/core/api/debug/constants.d.ts +2 -0
- package/dist/_esm5.processed/core/api/debug/constants.js +2 -0
- package/dist/_esm5.processed/core/api/debug/index.d.ts +2 -0
- package/dist/_esm5.processed/core/api/debug/index.js +2 -0
- package/dist/_esm5.processed/core/api/debug/modules/general_info.d.ts +3 -0
- package/dist/_esm5.processed/core/api/debug/modules/general_info.js +180 -0
- package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.d.ts +4 -0
- package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.js +121 -0
- package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.d.ts +3 -0
- package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.js +35 -0
- package/dist/_esm5.processed/core/api/debug/render.d.ts +3 -0
- package/dist/_esm5.processed/core/api/debug/render.js +32 -0
- package/dist/_esm5.processed/core/api/debug/utils.d.ts +39 -0
- package/dist/_esm5.processed/core/api/debug/utils.js +57 -0
- package/dist/_esm5.processed/core/api/playback_observer.js +4 -2
- package/dist/_esm5.processed/core/api/public_api.d.ts +60 -3
- package/dist/_esm5.processed/core/api/public_api.js +280 -60
- package/dist/_esm5.processed/core/api/track_management/media_element_tracks_store.js +10 -1
- package/dist/_esm5.processed/core/api/track_management/track_dispatcher.d.ts +13 -1
- package/dist/_esm5.processed/core/api/track_management/track_dispatcher.js +30 -15
- package/dist/_esm5.processed/core/api/track_management/tracks_store.d.ts +3 -1
- package/dist/_esm5.processed/core/api/track_management/tracks_store.js +67 -152
- package/dist/_esm5.processed/core/api/utils.d.ts +10 -0
- package/dist/_esm5.processed/core/api/utils.js +23 -3
- package/dist/_esm5.processed/core/decrypt/__tests__/__global__/utils.d.ts +27 -8
- package/dist/_esm5.processed/core/decrypt/__tests__/__global__/utils.js +28 -7
- package/dist/_esm5.processed/core/decrypt/attach_media_keys.js +1 -1
- package/dist/_esm5.processed/core/decrypt/content_decryptor.js +1 -1
- package/dist/_esm5.processed/core/decrypt/find_key_system.js +29 -6
- package/dist/_esm5.processed/core/decrypt/session_events_listener.js +42 -32
- package/dist/_esm5.processed/core/decrypt/utils/check_key_statuses.js +4 -0
- package/dist/_esm5.processed/core/decrypt/utils/clean_old_loaded_sessions.js +2 -0
- package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +5 -1
- package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.d.ts +17 -8
- package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.js +10 -6
- package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.js +5 -4
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +22 -5
- package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +37 -21
- package/dist/_esm5.processed/core/fetchers/segment/task_prioritizer.js +21 -23
- package/dist/_esm5.processed/core/fetchers/utils/schedule_request.js +17 -7
- package/dist/_esm5.processed/core/init/directfile_content_initializer.js +2 -2
- package/dist/_esm5.processed/core/init/media_source_content_initializer.js +74 -41
- package/dist/_esm5.processed/core/init/types.d.ts +9 -1
- package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.d.ts +28 -1
- package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.js +24 -11
- package/dist/_esm5.processed/core/init/utils/create_media_source.js +3 -12
- package/dist/_esm5.processed/core/init/utils/end_of_stream.js +6 -3
- package/dist/_esm5.processed/core/init/utils/get_loaded_reference.js +2 -1
- package/dist/_esm5.processed/core/init/utils/initial_seek_and_play.js +9 -5
- package/dist/_esm5.processed/core/init/utils/initialize_content_decryption.js +2 -1
- package/dist/_esm5.processed/core/init/utils/media_source_duration_updater.d.ts +58 -0
- package/dist/_esm5.processed/core/init/utils/{media_duration_updater.js → media_source_duration_updater.js} +87 -86
- package/dist/_esm5.processed/core/init/utils/rebuffering_controller.d.ts +36 -2
- package/dist/_esm5.processed/core/init/utils/rebuffering_controller.js +83 -3
- package/dist/_esm5.processed/core/init/utils/stream_events_emitter/stream_events_emitter.js +6 -4
- package/dist/_esm5.processed/core/init/utils/throw_on_media_error.js +1 -1
- package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.d.ts +18 -7
- package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +38 -50
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.d.ts +8 -0
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +16 -2
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.d.ts +8 -0
- package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.js +12 -0
- package/dist/_esm5.processed/core/segment_buffers/implementations/types.d.ts +11 -4
- package/dist/_esm5.processed/core/segment_buffers/index.d.ts +2 -2
- package/dist/_esm5.processed/core/segment_buffers/segment_buffers_store.js +13 -9
- package/dist/_esm5.processed/core/stream/adaptation/adaptation_stream.js +30 -16
- package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.d.ts +47 -0
- package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.js +70 -0
- package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +41 -20
- package/dist/_esm5.processed/core/stream/period/period_stream.js +12 -11
- package/dist/_esm5.processed/core/stream/representation/representation_stream.js +37 -28
- package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.d.ts +4 -2
- package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.js +3 -3
- package/dist/_esm5.processed/core/stream/representation/utils/downloading_queue.js +16 -6
- package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.d.ts +3 -2
- package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.js +8 -8
- package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.d.ts +2 -2
- package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.js +2 -3
- package/dist/_esm5.processed/core/stream/utils/create_reload_request.js +1 -1
- package/dist/_esm5.processed/default_config.d.ts +41 -0
- package/dist/_esm5.processed/default_config.js +46 -2
- package/dist/_esm5.processed/errors/index.d.ts +2 -2
- package/dist/_esm5.processed/errors/media_error.d.ts +23 -1
- package/dist/_esm5.processed/errors/media_error.js +18 -5
- package/dist/_esm5.processed/experimental/features/debug_element.d.ts +8 -0
- package/dist/_esm5.processed/experimental/features/debug_element.js +10 -0
- package/dist/_esm5.processed/experimental/features/index.d.ts +1 -0
- package/dist/_esm5.processed/experimental/features/index.js +1 -0
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.d.ts +1 -1
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.js +8 -7
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.js +7 -4
- package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +24 -12
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/index.js +0 -2
- package/dist/_esm5.processed/features/features_object.js +1 -0
- package/dist/_esm5.processed/features/initialize_features.js +13 -10
- package/dist/_esm5.processed/features/types.d.ts +3 -0
- package/dist/_esm5.processed/manifest/adaptation.d.ts +21 -2
- package/dist/_esm5.processed/manifest/adaptation.js +80 -1
- package/dist/_esm5.processed/manifest/manifest.js +2 -0
- package/dist/_esm5.processed/manifest/period.js +2 -2
- package/dist/_esm5.processed/manifest/representation.d.ts +33 -2
- package/dist/_esm5.processed/manifest/representation.js +32 -4
- package/dist/_esm5.processed/manifest/utils.js +1 -3
- package/dist/_esm5.processed/parsers/manifest/dash/common/parse_adaptation_sets.js +105 -137
- package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +25 -5
- package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.d.ts +1 -1
- package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.js +1 -1
- package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.js +1 -0
- package/dist/_esm5.processed/public_types.d.ts +13 -3
- package/dist/_esm5.processed/tools/TextTrackRenderer/text_track_renderer.js +1 -1
- package/dist/_esm5.processed/transports/dash/add_segment_integrity_checks_to_loader.js +15 -11
- package/dist/_esm5.processed/transports/dash/low_latency_segment_loader.js +2 -2
- package/dist/_esm5.processed/transports/dash/manifest_parser.js +1 -1
- package/dist/_esm5.processed/transports/dash/segment_loader.js +4 -4
- package/dist/_esm5.processed/transports/local/segment_loader.js +13 -26
- package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.d.ts +4 -6
- package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.js +4 -6
- package/dist/_esm5.processed/transports/smooth/segment_loader.js +4 -4
- package/dist/_esm5.processed/transports/utils/call_custom_manifest_loader.js +3 -3
- package/dist/_esm5.processed/utils/cancellable_sleep.js +4 -10
- package/dist/_esm5.processed/utils/create_cancellable_promise.d.ts +26 -0
- package/dist/_esm5.processed/utils/create_cancellable_promise.js +52 -0
- package/dist/_esm5.processed/utils/is_null_or_undefined.d.ts +1 -1
- package/dist/_esm5.processed/utils/is_null_or_undefined.js +1 -1
- package/dist/_esm5.processed/utils/reference.js +6 -0
- package/dist/_esm5.processed/utils/request/xhr.js +1 -1
- package/dist/_esm5.processed/utils/task_canceller.d.ts +34 -15
- package/dist/_esm5.processed/utils/task_canceller.js +55 -22
- package/dist/mpd-parser.wasm +0 -0
- package/dist/rx-player.js +5424 -4712
- package/dist/rx-player.min.js +1 -1
- package/jest.config.js +1 -5
- package/package.json +44 -40
- package/scripts/build/constants.d.ts +1 -0
- package/scripts/build/generate_build.js +1 -1
- package/scripts/fast_demo_build.js +40 -40
- package/scripts/generate_full_demo.js +1 -1
- package/sonar-project.properties +1 -1
- package/src/compat/browser_detection.ts +105 -52
- package/src/compat/can_reuse_media_keys.ts +5 -2
- package/src/compat/eme/close_session.ts +2 -2
- package/src/compat/eme/load_session.ts +1 -1
- package/src/compat/event_listeners.ts +1 -1
- package/src/compat/has_issues_with_high_media_source_duration.ts +27 -0
- package/src/core/adaptive/__tests__/buffer_based_chooser.test.ts +147 -48
- package/src/core/adaptive/adaptive_representation_selector.ts +11 -6
- package/src/core/adaptive/buffer_based_chooser.ts +144 -26
- package/src/core/adaptive/guess_based_chooser.ts +9 -8
- package/src/core/adaptive/network_analyzer.ts +9 -4
- package/src/core/adaptive/utils/representation_score_calculator.ts +22 -2
- package/src/core/api/debug/buffer_graph.ts +247 -0
- package/src/core/api/debug/buffer_size_graph.ts +130 -0
- package/src/core/api/debug/constants.ts +2 -0
- package/src/core/api/debug/index.ts +3 -0
- package/src/core/api/debug/modules/general_info.ts +184 -0
- package/src/core/api/debug/modules/segment_buffer_content.ts +155 -0
- package/src/core/api/debug/modules/segment_buffer_size.ts +48 -0
- package/src/core/api/debug/render.ts +40 -0
- package/src/core/api/debug/utils.ts +103 -0
- package/src/core/api/playback_observer.ts +5 -2
- package/src/core/api/public_api.ts +334 -73
- package/src/core/api/track_management/media_element_tracks_store.ts +17 -8
- package/src/core/api/track_management/track_dispatcher.ts +37 -14
- package/src/core/api/track_management/tracks_store.ts +77 -167
- package/src/core/api/utils.ts +29 -3
- package/src/core/decrypt/__tests__/__global__/utils.ts +61 -40
- package/src/core/decrypt/attach_media_keys.ts +1 -1
- package/src/core/decrypt/content_decryptor.ts +1 -1
- package/src/core/decrypt/find_key_system.ts +25 -11
- package/src/core/decrypt/session_events_listener.ts +45 -39
- package/src/core/decrypt/utils/check_key_statuses.ts +6 -0
- package/src/core/decrypt/utils/clean_old_loaded_sessions.ts +2 -1
- package/src/core/decrypt/utils/loaded_sessions_store.ts +8 -1
- package/src/core/fetchers/cdn_prioritizer.ts +18 -9
- package/src/core/fetchers/manifest/manifest_fetcher.ts +5 -4
- package/src/core/fetchers/segment/segment_fetcher.ts +36 -14
- package/src/core/fetchers/segment/task_prioritizer.ts +25 -30
- package/src/core/fetchers/utils/schedule_request.ts +18 -7
- package/src/core/init/directfile_content_initializer.ts +2 -1
- package/src/core/init/media_source_content_initializer.ts +89 -50
- package/src/core/init/types.ts +9 -1
- package/src/core/init/utils/content_time_boundaries_observer.ts +48 -12
- package/src/core/init/utils/create_media_source.ts +4 -16
- package/src/core/init/utils/end_of_stream.ts +6 -3
- package/src/core/init/utils/get_loaded_reference.ts +2 -1
- package/src/core/init/utils/initial_seek_and_play.ts +9 -5
- package/src/core/init/utils/initialize_content_decryption.ts +2 -1
- package/src/core/init/utils/{media_duration_updater.ts → media_source_duration_updater.ts} +103 -110
- package/src/core/init/utils/rebuffering_controller.ts +115 -4
- package/src/core/init/utils/stream_events_emitter/stream_events_emitter.ts +6 -4
- package/src/core/init/utils/throw_on_media_error.ts +1 -1
- package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +63 -66
- package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +20 -2
- package/src/core/segment_buffers/implementations/text/native/native_text_segment_buffer.ts +16 -0
- package/src/core/segment_buffers/implementations/types.ts +16 -4
- package/src/core/segment_buffers/index.ts +2 -0
- package/src/core/segment_buffers/segment_buffers_store.ts +16 -13
- package/src/core/stream/adaptation/adaptation_stream.ts +33 -19
- package/src/core/stream/adaptation/utils/create_representation_estimator.ts +114 -0
- package/src/core/stream/orchestrator/stream_orchestrator.ts +42 -20
- package/src/core/stream/period/period_stream.ts +13 -11
- package/src/core/stream/representation/representation_stream.ts +49 -37
- package/src/core/stream/representation/utils/append_segment_to_buffer.ts +9 -4
- package/src/core/stream/representation/utils/downloading_queue.ts +16 -4
- package/src/core/stream/representation/utils/push_init_segment.ts +11 -6
- package/src/core/stream/representation/utils/push_media_segment.ts +3 -3
- package/src/core/stream/utils/create_reload_request.ts +1 -1
- package/src/default_config.ts +59 -11
- package/src/errors/__tests__/media_error.test.ts +6 -6
- package/src/errors/index.ts +4 -1
- package/src/errors/media_error.ts +67 -1
- package/src/experimental/features/__tests__/debug_element.test.ts +26 -0
- package/src/experimental/features/debug_element.ts +13 -0
- package/src/experimental/features/index.ts +1 -0
- package/src/experimental/tools/VideoThumbnailLoader/load_and_push_segment.ts +10 -7
- package/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts +7 -4
- package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +25 -10
- package/src/experimental/tools/mediaCapabilitiesProber/index.ts +0 -4
- package/src/features/__tests__/initialize_features.test.ts +11 -0
- package/src/features/features_object.ts +1 -0
- package/src/features/initialize_features.ts +15 -10
- package/src/features/types.ts +9 -0
- package/src/manifest/__tests__/manifest.test.ts +7 -7
- package/src/manifest/__tests__/period.test.ts +90 -45
- package/src/manifest/adaptation.ts +96 -1
- package/src/manifest/manifest.ts +4 -0
- package/src/manifest/period.ts +4 -2
- package/src/manifest/representation.ts +77 -5
- package/src/manifest/utils.ts +1 -3
- package/src/parsers/manifest/dash/common/parse_adaptation_sets.ts +116 -151
- package/src/parsers/manifest/dash/common/parse_representations.ts +21 -4
- package/src/parsers/manifest/dash/js-parser/parse_from_document.ts +1 -1
- package/src/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.ts +1 -0
- package/src/parsers/texttracks/ttml/parse_ttml.ts +1 -1
- package/src/public_types.ts +16 -1
- package/src/tools/TextTrackRenderer/text_track_renderer.ts +1 -1
- package/src/transports/dash/add_segment_integrity_checks_to_loader.ts +31 -22
- package/src/transports/dash/low_latency_segment_loader.ts +2 -2
- package/src/transports/dash/manifest_parser.ts +1 -1
- package/src/transports/dash/segment_loader.ts +4 -4
- package/src/transports/local/segment_loader.ts +14 -30
- package/src/transports/smooth/isobmff/create_boxes.ts +4 -6
- package/src/transports/smooth/segment_loader.ts +4 -4
- package/src/transports/utils/call_custom_manifest_loader.ts +3 -3
- package/src/typings/globals.d.ts +21 -19
- package/src/utils/cancellable_sleep.ts +5 -14
- package/src/utils/create_cancellable_promise.ts +69 -0
- package/src/utils/is_null_or_undefined.ts +1 -1
- package/src/utils/reference.ts +6 -0
- package/src/utils/request/xhr.ts +1 -1
- package/src/utils/task_canceller.ts +63 -34
- package/tsconfig.json +1 -1
- package/tsconfig.modules.json +1 -1
- package/dist/_esm5.processed/core/init/utils/media_duration_updater.d.ts +0 -56
- package/locked_reps.js +0 -46
- package/scripts/doc-generator/construct_table_of_contents.js +0 -76
- package/scripts/doc-generator/convert_MD_to_HMTL.js +0 -26
- package/scripts/doc-generator/create_documentation.js +0 -331
- package/scripts/doc-generator/create_documentation_page.js +0 -209
- package/scripts/doc-generator/create_page.js +0 -210
- package/scripts/doc-generator/generate_header_html.js +0 -147
- package/scripts/doc-generator/generate_page_html.js +0 -115
- package/scripts/doc-generator/generate_page_list_html.js +0 -92
- package/scripts/doc-generator/generate_sidebar_html.js +0 -85
- package/scripts/doc-generator/get_search_data_for_content.js +0 -137
- package/scripts/doc-generator/index.js +0 -34
- package/scripts/doc-generator/parse_doc_configs.js +0 -327
- package/scripts/doc-generator/scripts/lunr.js +0 -10
- package/scripts/doc-generator/scripts/script.js +0 -451
- package/scripts/doc-generator/styles/code.css +0 -99
- package/scripts/doc-generator/styles/style.css +0 -835
- package/scripts/doc-generator/utils.js +0 -74
|
@@ -26,7 +26,8 @@ import TaskCanceller from "../../../utils/task_canceller";
|
|
|
26
26
|
* @returns {Object}
|
|
27
27
|
*/
|
|
28
28
|
export default function getLoadedReference(playbackObserver, mediaElement, isDirectfile, cancelSignal) {
|
|
29
|
-
var listenCanceller = new TaskCanceller(
|
|
29
|
+
var listenCanceller = new TaskCanceller();
|
|
30
|
+
listenCanceller.linkToSignal(cancelSignal);
|
|
30
31
|
var isLoaded = createSharedReference(false, listenCanceller.signal);
|
|
31
32
|
playbackObserver.listen(function (observation) {
|
|
32
33
|
if (observation.rebuffering !== null ||
|
|
@@ -42,7 +42,7 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
|
|
|
42
42
|
if (mediaElement.readyState >= READY_STATES.HAVE_METADATA) {
|
|
43
43
|
onLoadedMetadata();
|
|
44
44
|
}
|
|
45
|
-
cancelSignal.register(function (err) {
|
|
45
|
+
var deregisterCancellation = cancelSignal.register(function (err) {
|
|
46
46
|
mediaElement.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
47
47
|
rejectAutoPlay(err);
|
|
48
48
|
});
|
|
@@ -60,7 +60,7 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
|
|
|
60
60
|
"falsely announced having loaded the content.");
|
|
61
61
|
onWarning(error);
|
|
62
62
|
}
|
|
63
|
-
if (cancelSignal.isCancelled) {
|
|
63
|
+
if (cancelSignal.isCancelled()) {
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
playbackObserver.listen(function (observation, stopListening) {
|
|
@@ -82,6 +82,7 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
|
|
|
82
82
|
}
|
|
83
83
|
initialPlayPerformed.setValue(true);
|
|
84
84
|
initialPlayPerformed.finish();
|
|
85
|
+
deregisterCancellation();
|
|
85
86
|
return resolveAutoPlay({ type: "skipped" });
|
|
86
87
|
}
|
|
87
88
|
var playResult;
|
|
@@ -89,19 +90,22 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
|
|
|
89
90
|
playResult = (_a = mediaElement.play()) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
90
91
|
}
|
|
91
92
|
catch (playError) {
|
|
93
|
+
deregisterCancellation();
|
|
92
94
|
return rejectAutoPlay(playError);
|
|
93
95
|
}
|
|
94
96
|
playResult
|
|
95
97
|
.then(function () {
|
|
96
|
-
if (cancelSignal.isCancelled) {
|
|
98
|
+
if (cancelSignal.isCancelled()) {
|
|
97
99
|
return;
|
|
98
100
|
}
|
|
99
101
|
initialPlayPerformed.setValue(true);
|
|
100
102
|
initialPlayPerformed.finish();
|
|
103
|
+
deregisterCancellation();
|
|
101
104
|
return resolveAutoPlay({ type: "autoplay" });
|
|
102
105
|
})
|
|
103
106
|
.catch(function (playError) {
|
|
104
|
-
|
|
107
|
+
deregisterCancellation();
|
|
108
|
+
if (cancelSignal.isCancelled()) {
|
|
105
109
|
return;
|
|
106
110
|
}
|
|
107
111
|
if (playError instanceof Error && playError.name === "NotAllowedError") {
|
|
@@ -111,7 +115,7 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
|
|
|
111
115
|
var error = new MediaError("MEDIA_ERR_BLOCKED_AUTOPLAY", "Cannot trigger auto-play automatically: " +
|
|
112
116
|
"your browser does not allow it.");
|
|
113
117
|
onWarning(error);
|
|
114
|
-
if (cancelSignal.isCancelled) {
|
|
118
|
+
if (cancelSignal.isCancelled()) {
|
|
115
119
|
return;
|
|
116
120
|
}
|
|
117
121
|
return resolveAutoPlay({ type: "autoplay-blocked" });
|
|
@@ -62,7 +62,8 @@ export default function initializeContentDecryption(mediaElement, keySystems, pr
|
|
|
62
62
|
ref.finish(); // We know that no new value will be triggered
|
|
63
63
|
return ref;
|
|
64
64
|
}
|
|
65
|
-
var decryptorCanceller = new TaskCanceller(
|
|
65
|
+
var decryptorCanceller = new TaskCanceller();
|
|
66
|
+
decryptorCanceller.linkToSignal(cancelSignal);
|
|
66
67
|
var drmStatusRef = createSharedReference({
|
|
67
68
|
initializationState: { type: "uninitialized", value: null },
|
|
68
69
|
drmSystemId: undefined,
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2015 CANAL+ Group
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Keep the MediaSource's `duration` attribute up-to-date with the duration of
|
|
18
|
+
* the content played on it.
|
|
19
|
+
* @class MediaSourceDurationUpdater
|
|
20
|
+
*/
|
|
21
|
+
export default class MediaSourceDurationUpdater {
|
|
22
|
+
/**
|
|
23
|
+
* `MediaSource` on which we're going to update the `duration` attribute.
|
|
24
|
+
*/
|
|
25
|
+
private _mediaSource;
|
|
26
|
+
/**
|
|
27
|
+
* Abort the current duration-setting logic.
|
|
28
|
+
* `null` if no such logic is pending.
|
|
29
|
+
*/
|
|
30
|
+
private _currentMediaSourceDurationUpdateCanceller;
|
|
31
|
+
/**
|
|
32
|
+
* Create a new `MediaSourceDurationUpdater`,
|
|
33
|
+
* @param {MediaSource} mediaSource - The MediaSource on which the content is
|
|
34
|
+
* played.
|
|
35
|
+
*/
|
|
36
|
+
constructor(mediaSource: MediaSource);
|
|
37
|
+
/**
|
|
38
|
+
* Indicate to the `MediaSourceDurationUpdater` the currently known duration
|
|
39
|
+
* of the content.
|
|
40
|
+
*
|
|
41
|
+
* The `MediaSourceDurationUpdater` will then use that value to determine
|
|
42
|
+
* which `duration` attribute should be set on the `MediaSource` associated
|
|
43
|
+
*
|
|
44
|
+
* @param {number} newDuration
|
|
45
|
+
* @param {boolean} isRealEndKnown - If set to `false`, the current content is
|
|
46
|
+
* a dynamic content (it might evolve in the future) and the `newDuration`
|
|
47
|
+
* communicated might be greater still. In effect the
|
|
48
|
+
* `MediaSourceDurationUpdater` will actually set a much higher value to the
|
|
49
|
+
* `MediaSource`'s duration to prevent being annoyed by the HTML-related
|
|
50
|
+
* side-effects of having a too low duration (such as the impossibility to
|
|
51
|
+
* seek over that value).
|
|
52
|
+
*/
|
|
53
|
+
updateDuration(newDuration: number, isRealEndKnown: boolean): void;
|
|
54
|
+
/**
|
|
55
|
+
* Abort the last duration-setting operation and free its resources.
|
|
56
|
+
*/
|
|
57
|
+
stopUpdating(): void;
|
|
58
|
+
}
|
|
@@ -14,94 +14,91 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { onSourceOpen, onSourceEnded, onSourceClose, } from "../../../compat/event_listeners";
|
|
17
|
+
/* eslint-disable-next-line max-len */
|
|
18
|
+
import hasIssuesWithHighMediaSourceDuration from "../../../compat/has_issues_with_high_media_source_duration";
|
|
17
19
|
import log from "../../../log";
|
|
18
20
|
import createSharedReference from "../../../utils/reference";
|
|
19
21
|
import TaskCanceller from "../../../utils/task_canceller";
|
|
20
22
|
/** Number of seconds in a regular year. */
|
|
21
23
|
var YEAR_IN_SECONDS = 365 * 24 * 3600;
|
|
22
24
|
/**
|
|
23
|
-
* Keep the MediaSource's duration up-to-date with
|
|
24
|
-
*
|
|
25
|
+
* Keep the MediaSource's `duration` attribute up-to-date with the duration of
|
|
26
|
+
* the content played on it.
|
|
27
|
+
* @class MediaSourceDurationUpdater
|
|
25
28
|
*/
|
|
26
|
-
var
|
|
29
|
+
var MediaSourceDurationUpdater = /** @class */ (function () {
|
|
27
30
|
/**
|
|
28
|
-
* Create a new `
|
|
29
|
-
* duration as soon as possible.
|
|
30
|
-
* This duration will be updated until the `stop` method is called.
|
|
31
|
-
* @param {Object} manifest - The Manifest currently played.
|
|
32
|
-
* For another content, you will have to create another `MediaDurationUpdater`.
|
|
31
|
+
* Create a new `MediaSourceDurationUpdater`,
|
|
33
32
|
* @param {MediaSource} mediaSource - The MediaSource on which the content is
|
|
34
|
-
*
|
|
33
|
+
* played.
|
|
35
34
|
*/
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
function MediaSourceDurationUpdater(mediaSource) {
|
|
36
|
+
this._mediaSource = mediaSource;
|
|
37
|
+
this._currentMediaSourceDurationUpdateCanceller = null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Indicate to the `MediaSourceDurationUpdater` the currently known duration
|
|
41
|
+
* of the content.
|
|
42
|
+
*
|
|
43
|
+
* The `MediaSourceDurationUpdater` will then use that value to determine
|
|
44
|
+
* which `duration` attribute should be set on the `MediaSource` associated
|
|
45
|
+
*
|
|
46
|
+
* @param {number} newDuration
|
|
47
|
+
* @param {boolean} isRealEndKnown - If set to `false`, the current content is
|
|
48
|
+
* a dynamic content (it might evolve in the future) and the `newDuration`
|
|
49
|
+
* communicated might be greater still. In effect the
|
|
50
|
+
* `MediaSourceDurationUpdater` will actually set a much higher value to the
|
|
51
|
+
* `MediaSource`'s duration to prevent being annoyed by the HTML-related
|
|
52
|
+
* side-effects of having a too low duration (such as the impossibility to
|
|
53
|
+
* seek over that value).
|
|
54
|
+
*/
|
|
55
|
+
MediaSourceDurationUpdater.prototype.updateDuration = function (newDuration, isRealEndKnown) {
|
|
56
|
+
if (this._currentMediaSourceDurationUpdateCanceller !== null) {
|
|
57
|
+
this._currentMediaSourceDurationUpdateCanceller.cancel();
|
|
58
|
+
}
|
|
59
|
+
this._currentMediaSourceDurationUpdateCanceller = new TaskCanceller();
|
|
60
|
+
var mediaSource = this._mediaSource;
|
|
61
|
+
var currentSignal = this._currentMediaSourceDurationUpdateCanceller.signal;
|
|
62
|
+
var isMediaSourceOpened = createMediaSourceOpenReference(mediaSource, currentSignal);
|
|
63
|
+
/** TaskCanceller triggered each time the MediaSource switches to and from "open". */
|
|
64
|
+
var msOpenStatusCanceller = new TaskCanceller();
|
|
65
|
+
msOpenStatusCanceller.linkToSignal(currentSignal);
|
|
44
66
|
isMediaSourceOpened.onUpdate(onMediaSourceOpenedStatusChanged, { emitCurrentValue: true,
|
|
45
|
-
clearSignal:
|
|
67
|
+
clearSignal: currentSignal });
|
|
46
68
|
function onMediaSourceOpenedStatusChanged() {
|
|
47
|
-
|
|
69
|
+
msOpenStatusCanceller.cancel();
|
|
48
70
|
if (!isMediaSourceOpened.getValue()) {
|
|
49
71
|
return;
|
|
50
72
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
var
|
|
54
|
-
cancelOn: msUpdateCanceller.signal,
|
|
55
|
-
});
|
|
56
|
-
var reSetDuration = function () {
|
|
57
|
-
durationChangeCanceller.cancel();
|
|
58
|
-
durationChangeCanceller = new TaskCanceller({
|
|
59
|
-
cancelOn: msUpdateCanceller.signal,
|
|
60
|
-
});
|
|
61
|
-
onDurationMayHaveChanged(durationChangeCanceller.signal);
|
|
62
|
-
};
|
|
63
|
-
currentKnownDuration.onUpdate(reSetDuration, { emitCurrentValue: false,
|
|
64
|
-
clearSignal: msUpdateCanceller.signal });
|
|
65
|
-
manifest.addEventListener("manifestUpdate", reSetDuration, msUpdateCanceller.signal);
|
|
66
|
-
onDurationMayHaveChanged(durationChangeCanceller.signal);
|
|
67
|
-
}
|
|
68
|
-
function onDurationMayHaveChanged(cancelSignal) {
|
|
69
|
-
var areSourceBuffersUpdating = createSourceBuffersUpdatingReference(mediaSource.sourceBuffers, cancelSignal);
|
|
73
|
+
msOpenStatusCanceller = new TaskCanceller();
|
|
74
|
+
msOpenStatusCanceller.linkToSignal(currentSignal);
|
|
75
|
+
var areSourceBuffersUpdating = createSourceBuffersUpdatingReference(mediaSource.sourceBuffers, msOpenStatusCanceller.signal);
|
|
70
76
|
/** TaskCanceller triggered each time SourceBuffers' updating status changes */
|
|
71
|
-
var sourceBuffersUpdatingCanceller = new TaskCanceller(
|
|
77
|
+
var sourceBuffersUpdatingCanceller = new TaskCanceller();
|
|
78
|
+
sourceBuffersUpdatingCanceller.linkToSignal(msOpenStatusCanceller.signal);
|
|
72
79
|
return areSourceBuffersUpdating.onUpdate(function (areUpdating) {
|
|
73
80
|
sourceBuffersUpdatingCanceller.cancel();
|
|
74
|
-
sourceBuffersUpdatingCanceller = new TaskCanceller(
|
|
81
|
+
sourceBuffersUpdatingCanceller = new TaskCanceller();
|
|
82
|
+
sourceBuffersUpdatingCanceller.linkToSignal(msOpenStatusCanceller.signal);
|
|
75
83
|
if (areUpdating) {
|
|
76
84
|
return;
|
|
77
85
|
}
|
|
78
|
-
recursivelyForceDurationUpdate(mediaSource,
|
|
79
|
-
}, { clearSignal:
|
|
86
|
+
recursivelyForceDurationUpdate(mediaSource, newDuration, isRealEndKnown, sourceBuffersUpdatingCanceller.signal);
|
|
87
|
+
}, { clearSignal: msOpenStatusCanceller.signal, emitCurrentValue: true });
|
|
80
88
|
}
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* By default, the `MediaDurationUpdater` only set a safe estimate for the
|
|
84
|
-
* MediaSource's duration.
|
|
85
|
-
* A more precize duration can be set by communicating to it a more precize
|
|
86
|
-
* media duration through `updateKnownDuration`.
|
|
87
|
-
* If the duration becomes unknown, `undefined` can be given to it so the
|
|
88
|
-
* `MediaDurationUpdater` goes back to a safe estimate.
|
|
89
|
-
* @param {number | undefined} newDuration
|
|
90
|
-
*/
|
|
91
|
-
MediaDurationUpdater.prototype.updateKnownDuration = function (newDuration) {
|
|
92
|
-
this._currentKnownDuration.setValueIfChanged(newDuration);
|
|
93
89
|
};
|
|
94
90
|
/**
|
|
95
|
-
*
|
|
96
|
-
* Once stopped, it is not possible to start it again, beside creating another
|
|
97
|
-
* `MediaDurationUpdater`.
|
|
91
|
+
* Abort the last duration-setting operation and free its resources.
|
|
98
92
|
*/
|
|
99
|
-
|
|
100
|
-
this.
|
|
93
|
+
MediaSourceDurationUpdater.prototype.stopUpdating = function () {
|
|
94
|
+
if (this._currentMediaSourceDurationUpdateCanceller !== null) {
|
|
95
|
+
this._currentMediaSourceDurationUpdateCanceller.cancel();
|
|
96
|
+
this._currentMediaSourceDurationUpdateCanceller = null;
|
|
97
|
+
}
|
|
101
98
|
};
|
|
102
|
-
return
|
|
99
|
+
return MediaSourceDurationUpdater;
|
|
103
100
|
}());
|
|
104
|
-
export default
|
|
101
|
+
export default MediaSourceDurationUpdater;
|
|
105
102
|
/**
|
|
106
103
|
* Checks that duration can be updated on the MediaSource, and then
|
|
107
104
|
* sets it.
|
|
@@ -111,26 +108,16 @@ export default MediaDurationUpdater;
|
|
|
111
108
|
* - `null` if it hasn'nt been updated
|
|
112
109
|
*
|
|
113
110
|
* @param {MediaSource} mediaSource
|
|
114
|
-
* @param {
|
|
111
|
+
* @param {number} duration
|
|
112
|
+
* @param {boolean} isRealEndKnown
|
|
115
113
|
* @returns {string}
|
|
116
114
|
*/
|
|
117
|
-
function setMediaSourceDuration(mediaSource,
|
|
118
|
-
var
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
// Some targets poorly support setting a very high number for durations.
|
|
124
|
-
// Yet, in dynamic contents, we would prefer setting a value as high as possible
|
|
125
|
-
// to still be able to seek anywhere we want to (even ahead of the Manifest if
|
|
126
|
-
// we want to). As such, we put it at a safe default value of 2^32 excepted
|
|
127
|
-
// when the maximum position is already relatively close to that value, where
|
|
128
|
-
// we authorize exceptionally going over it.
|
|
129
|
-
newDuration = Math.max(Math.pow(2, 32), maxPotentialPos + YEAR_IN_SECONDS);
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
newDuration = manifest.getMaximumSafePosition();
|
|
133
|
-
}
|
|
115
|
+
function setMediaSourceDuration(mediaSource, duration, isRealEndKnown) {
|
|
116
|
+
var newDuration = duration;
|
|
117
|
+
if (!isRealEndKnown) {
|
|
118
|
+
newDuration = hasIssuesWithHighMediaSourceDuration() ?
|
|
119
|
+
Infinity :
|
|
120
|
+
getMaximumLiveSeekablePosition(duration);
|
|
134
121
|
}
|
|
135
122
|
var maxBufferedEnd = 0;
|
|
136
123
|
for (var i = 0; i < mediaSource.sourceBuffers.length; i++) {
|
|
@@ -149,7 +136,7 @@ function setMediaSourceDuration(mediaSource, manifest, knownDuration) {
|
|
|
149
136
|
if (maxBufferedEnd < mediaSource.duration) {
|
|
150
137
|
try {
|
|
151
138
|
log.info("Init: Updating duration to what is currently buffered", maxBufferedEnd);
|
|
152
|
-
mediaSource.duration =
|
|
139
|
+
mediaSource.duration = maxBufferedEnd;
|
|
153
140
|
}
|
|
154
141
|
catch (err) {
|
|
155
142
|
log.warn("Duration Updater: Can't update duration on the MediaSource.", err instanceof Error ? err : "");
|
|
@@ -163,6 +150,9 @@ function setMediaSourceDuration(mediaSource, manifest, knownDuration) {
|
|
|
163
150
|
try {
|
|
164
151
|
log.info("Init: Updating duration", newDuration);
|
|
165
152
|
mediaSource.duration = newDuration;
|
|
153
|
+
if (mediaSource.readyState === "open" && !isFinite(newDuration)) {
|
|
154
|
+
mediaSource.setLiveSeekableRange(0, getMaximumLiveSeekablePosition(duration));
|
|
155
|
+
}
|
|
166
156
|
}
|
|
167
157
|
catch (err) {
|
|
168
158
|
log.warn("Duration Updater: Can't update duration on the MediaSource.", err instanceof Error ? err : "");
|
|
@@ -238,25 +228,36 @@ function createMediaSourceOpenReference(mediaSource, cancelSignal) {
|
|
|
238
228
|
}
|
|
239
229
|
/**
|
|
240
230
|
* Immediately tries to set the MediaSource's duration to the most appropriate
|
|
241
|
-
* one
|
|
231
|
+
* one.
|
|
242
232
|
*
|
|
243
233
|
* If it fails, wait 2 seconds and retries.
|
|
244
234
|
*
|
|
245
235
|
* @param {MediaSource} mediaSource
|
|
246
|
-
* @param {
|
|
247
|
-
* @param {
|
|
236
|
+
* @param {number} duration
|
|
237
|
+
* @param {boolean} isRealEndKnown
|
|
248
238
|
* @param {Object} cancelSignal
|
|
249
239
|
*/
|
|
250
|
-
function recursivelyForceDurationUpdate(mediaSource,
|
|
251
|
-
var res = setMediaSourceDuration(mediaSource,
|
|
240
|
+
function recursivelyForceDurationUpdate(mediaSource, duration, isRealEndKnown, cancelSignal) {
|
|
241
|
+
var res = setMediaSourceDuration(mediaSource, duration, isRealEndKnown);
|
|
252
242
|
if (res === "success" /* MediaSourceDurationUpdateStatus.Success */) {
|
|
253
243
|
return;
|
|
254
244
|
}
|
|
255
245
|
var timeoutId = setTimeout(function () {
|
|
256
246
|
unregisterClear();
|
|
257
|
-
recursivelyForceDurationUpdate(mediaSource,
|
|
247
|
+
recursivelyForceDurationUpdate(mediaSource, duration, isRealEndKnown, cancelSignal);
|
|
258
248
|
}, 2000);
|
|
259
249
|
var unregisterClear = cancelSignal.register(function () {
|
|
260
250
|
clearTimeout(timeoutId);
|
|
261
251
|
});
|
|
262
252
|
}
|
|
253
|
+
function getMaximumLiveSeekablePosition(contentLastPosition) {
|
|
254
|
+
// Some targets poorly support setting a very high number for seekable
|
|
255
|
+
// ranges.
|
|
256
|
+
// Yet, in contents whose end is not yet known (e.g. live contents), we
|
|
257
|
+
// would prefer setting a value as high as possible to still be able to
|
|
258
|
+
// seek anywhere we want to (even ahead of the Manifest if we want to).
|
|
259
|
+
// As such, we put it at a safe default value of 2^32 excepted when the
|
|
260
|
+
// maximum position is already relatively close to that value, where we
|
|
261
|
+
// authorize exceptionally going over it.
|
|
262
|
+
return Math.max(Math.pow(2, 32), contentLastPosition + YEAR_IN_SECONDS);
|
|
263
|
+
}
|
|
@@ -18,7 +18,7 @@ import { IPlayerError } from "../../../public_types";
|
|
|
18
18
|
import EventEmitter from "../../../utils/event_emitter";
|
|
19
19
|
import { IReadOnlySharedReference } from "../../../utils/reference";
|
|
20
20
|
import { PlaybackObserver } from "../../api";
|
|
21
|
-
import { IBufferType } from "../../segment_buffers";
|
|
21
|
+
import SegmentBuffersStore, { IBufferType } from "../../segment_buffers";
|
|
22
22
|
import { IStallingSituation } from "../types";
|
|
23
23
|
/**
|
|
24
24
|
* Monitor playback, trying to avoid stalling situation.
|
|
@@ -32,6 +32,7 @@ export default class RebufferingController extends EventEmitter<IRebufferingCont
|
|
|
32
32
|
/** Emit the current playback conditions */
|
|
33
33
|
private _playbackObserver;
|
|
34
34
|
private _manifest;
|
|
35
|
+
private _segmentBuffersStore;
|
|
35
36
|
private _speed;
|
|
36
37
|
private _isStarted;
|
|
37
38
|
/**
|
|
@@ -40,12 +41,23 @@ export default class RebufferingController extends EventEmitter<IRebufferingCont
|
|
|
40
41
|
*/
|
|
41
42
|
private _discontinuitiesStore;
|
|
42
43
|
private _canceller;
|
|
44
|
+
/**
|
|
45
|
+
* If set to something else than `null`, this is the DOMHighResTimestamp as
|
|
46
|
+
* outputed by `performance.now()` when playback begin to seem to not start
|
|
47
|
+
* despite having decipherable data in the buffer(s).
|
|
48
|
+
*
|
|
49
|
+
* If enough time in that condition is spent, special considerations are
|
|
50
|
+
* taken at which point `_currentFreezeTimestamp` is reset to `null`.
|
|
51
|
+
*
|
|
52
|
+
* It is also reset to `null` when and if there is no such issue anymore.
|
|
53
|
+
*/
|
|
54
|
+
private _currentFreezeTimestamp;
|
|
43
55
|
/**
|
|
44
56
|
* @param {object} playbackObserver - emit the current playback conditions.
|
|
45
57
|
* @param {Object} manifest - The Manifest of the currently-played content.
|
|
46
58
|
* @param {Object} speed - The last speed set by the user
|
|
47
59
|
*/
|
|
48
|
-
constructor(playbackObserver: PlaybackObserver, manifest: Manifest | null, speed: IReadOnlySharedReference<number>);
|
|
60
|
+
constructor(playbackObserver: PlaybackObserver, manifest: Manifest | null, segmentBuffersStore: SegmentBuffersStore | null, speed: IReadOnlySharedReference<number>);
|
|
49
61
|
start(): void;
|
|
50
62
|
/**
|
|
51
63
|
* Update information on an upcoming discontinuity for a given buffer type and
|
|
@@ -68,10 +80,32 @@ export default class RebufferingController extends EventEmitter<IRebufferingCont
|
|
|
68
80
|
* forever.
|
|
69
81
|
*/
|
|
70
82
|
destroy(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Support of contents with DRM on all the platforms out there is a pain in
|
|
85
|
+
* the *ss considering all the DRM-related bugs there are.
|
|
86
|
+
*
|
|
87
|
+
* We found out a frequent issue which is to be unable to play despite having
|
|
88
|
+
* all the decryption keys to play what is currently buffered.
|
|
89
|
+
* When this happens, re-creating the buffers from scratch, with a reload, is
|
|
90
|
+
* usually sufficient to unlock the situation.
|
|
91
|
+
*
|
|
92
|
+
* Although we prefer providing more targeted fixes or telling to platform
|
|
93
|
+
* developpers to fix their implementation, it's not always possible.
|
|
94
|
+
* We thus resorted to developping an heuristic which detects such situation
|
|
95
|
+
* and reload in that case.
|
|
96
|
+
*
|
|
97
|
+
* @param {Object} observation - The last playback observation produced, it
|
|
98
|
+
* has to be recent (just triggered for example).
|
|
99
|
+
* @returns {boolean} - Returns `true` if it seems to be such kind of
|
|
100
|
+
* decipherability freeze, in which case this method already performed the
|
|
101
|
+
* right handling steps.
|
|
102
|
+
*/
|
|
103
|
+
private _checkDecipherabilityFreeze;
|
|
71
104
|
}
|
|
72
105
|
export interface IRebufferingControllerEvent {
|
|
73
106
|
stalled: IStallingSituation;
|
|
74
107
|
unstalled: null;
|
|
108
|
+
needsReload: null;
|
|
75
109
|
warning: IPlayerError;
|
|
76
110
|
}
|
|
77
111
|
/**
|
|
@@ -55,14 +55,16 @@ var RebufferingController = /** @class */ (function (_super) {
|
|
|
55
55
|
* @param {Object} manifest - The Manifest of the currently-played content.
|
|
56
56
|
* @param {Object} speed - The last speed set by the user
|
|
57
57
|
*/
|
|
58
|
-
function RebufferingController(playbackObserver, manifest, speed) {
|
|
58
|
+
function RebufferingController(playbackObserver, manifest, segmentBuffersStore, speed) {
|
|
59
59
|
var _this = _super.call(this) || this;
|
|
60
60
|
_this._playbackObserver = playbackObserver;
|
|
61
61
|
_this._manifest = manifest;
|
|
62
|
+
_this._segmentBuffersStore = segmentBuffersStore;
|
|
62
63
|
_this._speed = speed;
|
|
63
64
|
_this._discontinuitiesStore = [];
|
|
64
65
|
_this._isStarted = false;
|
|
65
66
|
_this._canceller = new TaskCanceller();
|
|
67
|
+
_this._currentFreezeTimestamp = null;
|
|
66
68
|
return _this;
|
|
67
69
|
}
|
|
68
70
|
RebufferingController.prototype.start = function () {
|
|
@@ -100,7 +102,7 @@ var RebufferingController = /** @class */ (function (_super) {
|
|
|
100
102
|
this._canceller.signal.register(function () {
|
|
101
103
|
playbackRateUpdater.dispose();
|
|
102
104
|
});
|
|
103
|
-
var prevFreezingState;
|
|
105
|
+
var prevFreezingState = null;
|
|
104
106
|
this._playbackObserver.listen(function (observation) {
|
|
105
107
|
var _a;
|
|
106
108
|
var discontinuitiesStore = _this._discontinuitiesStore;
|
|
@@ -117,6 +119,9 @@ var RebufferingController = /** @class */ (function (_super) {
|
|
|
117
119
|
lastSeekingPosition = observation.seeking ?
|
|
118
120
|
Math.max((_a = observation.pendingInternalSeek) !== null && _a !== void 0 ? _a : 0, observation.position) :
|
|
119
121
|
null;
|
|
122
|
+
if (_this._checkDecipherabilityFreeze(observation)) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
120
125
|
if (freezing !== null) {
|
|
121
126
|
var now = performance.now();
|
|
122
127
|
var referenceTimestamp = prevFreezingState === null ?
|
|
@@ -175,7 +180,7 @@ var RebufferingController = /** @class */ (function (_super) {
|
|
|
175
180
|
return;
|
|
176
181
|
}
|
|
177
182
|
else {
|
|
178
|
-
log.warn("Init: ignored stall for too long,
|
|
183
|
+
log.warn("Init: ignored stall for too long, considering it", now - ignoredStallTimeStamp);
|
|
179
184
|
}
|
|
180
185
|
}
|
|
181
186
|
ignoredStallTimeStamp = null;
|
|
@@ -291,6 +296,81 @@ var RebufferingController = /** @class */ (function (_super) {
|
|
|
291
296
|
RebufferingController.prototype.destroy = function () {
|
|
292
297
|
this._canceller.cancel();
|
|
293
298
|
};
|
|
299
|
+
/**
|
|
300
|
+
* Support of contents with DRM on all the platforms out there is a pain in
|
|
301
|
+
* the *ss considering all the DRM-related bugs there are.
|
|
302
|
+
*
|
|
303
|
+
* We found out a frequent issue which is to be unable to play despite having
|
|
304
|
+
* all the decryption keys to play what is currently buffered.
|
|
305
|
+
* When this happens, re-creating the buffers from scratch, with a reload, is
|
|
306
|
+
* usually sufficient to unlock the situation.
|
|
307
|
+
*
|
|
308
|
+
* Although we prefer providing more targeted fixes or telling to platform
|
|
309
|
+
* developpers to fix their implementation, it's not always possible.
|
|
310
|
+
* We thus resorted to developping an heuristic which detects such situation
|
|
311
|
+
* and reload in that case.
|
|
312
|
+
*
|
|
313
|
+
* @param {Object} observation - The last playback observation produced, it
|
|
314
|
+
* has to be recent (just triggered for example).
|
|
315
|
+
* @returns {boolean} - Returns `true` if it seems to be such kind of
|
|
316
|
+
* decipherability freeze, in which case this method already performed the
|
|
317
|
+
* right handling steps.
|
|
318
|
+
*/
|
|
319
|
+
RebufferingController.prototype._checkDecipherabilityFreeze = function (observation) {
|
|
320
|
+
var readyState = observation.readyState, rebuffering = observation.rebuffering, freezing = observation.freezing;
|
|
321
|
+
var bufferGap = observation.bufferGap !== undefined &&
|
|
322
|
+
isFinite(observation.bufferGap) ? observation.bufferGap :
|
|
323
|
+
0;
|
|
324
|
+
if (this._segmentBuffersStore === null ||
|
|
325
|
+
bufferGap < 6 ||
|
|
326
|
+
(rebuffering === null && freezing === null) ||
|
|
327
|
+
readyState > 1) {
|
|
328
|
+
this._currentFreezeTimestamp = null;
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
var now = performance.now();
|
|
332
|
+
if (this._currentFreezeTimestamp === null) {
|
|
333
|
+
this._currentFreezeTimestamp = now;
|
|
334
|
+
}
|
|
335
|
+
var rebufferingForTooLong = rebuffering !== null && now - rebuffering.timestamp > 4000;
|
|
336
|
+
var frozenForTooLong = freezing !== null && now - freezing.timestamp > 4000;
|
|
337
|
+
if ((rebufferingForTooLong || frozenForTooLong) &&
|
|
338
|
+
performance.now() - this._currentFreezeTimestamp > 4000) {
|
|
339
|
+
var statusAudio = this._segmentBuffersStore.getStatus("audio");
|
|
340
|
+
var statusVideo = this._segmentBuffersStore.getStatus("video");
|
|
341
|
+
var hasOnlyDecipherableSegments = true;
|
|
342
|
+
var isClear = true;
|
|
343
|
+
for (var _i = 0, _a = [statusAudio, statusVideo]; _i < _a.length; _i++) {
|
|
344
|
+
var status_1 = _a[_i];
|
|
345
|
+
if (status_1.type === "initialized") {
|
|
346
|
+
for (var _b = 0, _c = status_1.value.getInventory(); _b < _c.length; _b++) {
|
|
347
|
+
var segment = _c[_b];
|
|
348
|
+
var representation = segment.infos.representation;
|
|
349
|
+
if (representation.decipherable === false) {
|
|
350
|
+
log.warn("Init: we have undecipherable segments left in the buffer, reloading");
|
|
351
|
+
this._currentFreezeTimestamp = null;
|
|
352
|
+
this.trigger("needsReload", null);
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
else if (representation.contentProtections !== undefined) {
|
|
356
|
+
isClear = false;
|
|
357
|
+
if (representation.decipherable !== true) {
|
|
358
|
+
hasOnlyDecipherableSegments = false;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (!isClear && hasOnlyDecipherableSegments) {
|
|
365
|
+
log.warn("Init: we are frozen despite only having decipherable " +
|
|
366
|
+
"segments left in the buffer, reloading");
|
|
367
|
+
this._currentFreezeTimestamp = null;
|
|
368
|
+
this.trigger("needsReload", null);
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return false;
|
|
373
|
+
};
|
|
294
374
|
return RebufferingController;
|
|
295
375
|
}(EventEmitter));
|
|
296
376
|
export default RebufferingController;
|
|
@@ -35,13 +35,15 @@ export default function streamEventsEmitter(manifest, mediaElement, playbackObse
|
|
|
35
35
|
scheduledEventsRef.setValue(refreshScheduledEventsList(prev, manifest));
|
|
36
36
|
}, cancelSignal);
|
|
37
37
|
var isPollingEvents = false;
|
|
38
|
-
var cancelCurrentPolling = new TaskCanceller(
|
|
38
|
+
var cancelCurrentPolling = new TaskCanceller();
|
|
39
|
+
cancelCurrentPolling.linkToSignal(cancelSignal);
|
|
39
40
|
scheduledEventsRef.onUpdate(function (_a) {
|
|
40
41
|
var scheduledEventsLength = _a.length;
|
|
41
42
|
if (scheduledEventsLength === 0) {
|
|
42
43
|
if (isPollingEvents) {
|
|
43
44
|
cancelCurrentPolling.cancel();
|
|
44
|
-
cancelCurrentPolling = new TaskCanceller(
|
|
45
|
+
cancelCurrentPolling = new TaskCanceller();
|
|
46
|
+
cancelCurrentPolling.linkToSignal(cancelSignal);
|
|
45
47
|
isPollingEvents = false;
|
|
46
48
|
}
|
|
47
49
|
return;
|
|
@@ -127,7 +129,7 @@ export default function streamEventsEmitter(manifest, mediaElement, playbackObse
|
|
|
127
129
|
else {
|
|
128
130
|
onEventSkip(event_2.value);
|
|
129
131
|
}
|
|
130
|
-
if (stopSignal.isCancelled) {
|
|
132
|
+
if (stopSignal.isCancelled()) {
|
|
131
133
|
return;
|
|
132
134
|
}
|
|
133
135
|
}
|
|
@@ -138,7 +140,7 @@ export default function streamEventsEmitter(manifest, mediaElement, playbackObse
|
|
|
138
140
|
if (typeof event_3.onExit === "function") {
|
|
139
141
|
event_3.onExit();
|
|
140
142
|
}
|
|
141
|
-
if (stopSignal.isCancelled) {
|
|
143
|
+
if (stopSignal.isCancelled()) {
|
|
142
144
|
return;
|
|
143
145
|
}
|
|
144
146
|
}
|
|
@@ -21,7 +21,7 @@ import isNullOrUndefined from "../../../utils/is_null_or_undefined";
|
|
|
21
21
|
* @param {Object} cancelSignal
|
|
22
22
|
*/
|
|
23
23
|
export default function listenToMediaError(mediaElement, onError, cancelSignal) {
|
|
24
|
-
if (cancelSignal.isCancelled) {
|
|
24
|
+
if (cancelSignal.isCancelled()) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
mediaElement.addEventListener("error", onMediaError);
|