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
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { ScoreConfidenceLevel } from "../utils/representation_score_calculator";
|
|
18
|
+
|
|
17
19
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
18
20
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
19
21
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
@@ -47,12 +49,25 @@ describe("BufferBasedChooser", () => {
|
|
|
47
49
|
bufferGap: 0,
|
|
48
50
|
speed: 1,
|
|
49
51
|
currentBitrate: undefined,
|
|
50
|
-
currentScore: 4,
|
|
52
|
+
currentScore: { score: 4, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
53
|
+
})).toEqual(1);
|
|
54
|
+
expect(new BufferBasedChooser([1, 2, 3]).getEstimate({
|
|
55
|
+
bufferGap: 0,
|
|
56
|
+
speed: 1,
|
|
57
|
+
currentBitrate: undefined,
|
|
58
|
+
currentScore: { score: 4, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
59
|
+
})).toEqual(1);
|
|
60
|
+
expect(new BufferBasedChooser([1, 2, 3]).getEstimate({
|
|
61
|
+
bufferGap: 0,
|
|
62
|
+
speed: 1,
|
|
63
|
+
currentBitrate: undefined,
|
|
64
|
+
currentScore: { score: 1, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
51
65
|
})).toEqual(1);
|
|
52
66
|
expect(new BufferBasedChooser([1, 2, 3]).getEstimate({
|
|
53
67
|
bufferGap: 0,
|
|
54
68
|
speed: 1,
|
|
55
|
-
|
|
69
|
+
currentBitrate: undefined,
|
|
70
|
+
currentScore: { score: 1, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
56
71
|
})).toEqual(1);
|
|
57
72
|
});
|
|
58
73
|
|
|
@@ -76,7 +91,7 @@ describe("BufferBasedChooser", () => {
|
|
|
76
91
|
});
|
|
77
92
|
|
|
78
93
|
/* eslint-disable max-len */
|
|
79
|
-
it("should go to the next bitrate if
|
|
94
|
+
it("should not go to the next bitrate if we don't have a high enough maintainability score", () => {
|
|
80
95
|
/* eslint-enable max-len */
|
|
81
96
|
const logger = { debug: jest.fn() };
|
|
82
97
|
jest.mock("../../../log", () => ({ __esModule: true as const,
|
|
@@ -86,82 +101,82 @@ describe("BufferBasedChooser", () => {
|
|
|
86
101
|
bufferGap: 16,
|
|
87
102
|
speed: 1,
|
|
88
103
|
currentBitrate: 10,
|
|
89
|
-
currentScore: 1.
|
|
90
|
-
})).toEqual(
|
|
104
|
+
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
105
|
+
})).toEqual(10);
|
|
91
106
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
92
107
|
bufferGap: 30,
|
|
93
108
|
speed: 1,
|
|
94
109
|
currentBitrate: 20,
|
|
95
|
-
currentScore: 1.
|
|
96
|
-
})).toEqual(
|
|
110
|
+
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
111
|
+
})).toEqual(20);
|
|
97
112
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
98
113
|
bufferGap: 30,
|
|
99
114
|
speed: 1,
|
|
100
115
|
currentBitrate: 20,
|
|
101
|
-
currentScore: 100,
|
|
102
|
-
})).toEqual(
|
|
116
|
+
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
117
|
+
})).toEqual(20);
|
|
103
118
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
104
119
|
bufferGap: 30,
|
|
105
120
|
speed: 2,
|
|
106
121
|
currentBitrate: 20,
|
|
107
|
-
currentScore: 2.
|
|
108
|
-
})).toEqual(
|
|
122
|
+
currentScore: { score: 2.30, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
123
|
+
})).toEqual(20);
|
|
109
124
|
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
|
|
110
125
|
bufferGap: 30,
|
|
111
126
|
speed: 2,
|
|
112
127
|
currentBitrate: 20,
|
|
113
|
-
currentScore: 2.
|
|
114
|
-
})).toEqual(
|
|
128
|
+
currentScore: { score: 2.30, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
129
|
+
})).toEqual(20);
|
|
115
130
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
116
131
|
bufferGap: 30,
|
|
117
132
|
speed: 0, // 0 is a special case
|
|
118
133
|
currentBitrate: 20,
|
|
119
|
-
currentScore: 100,
|
|
120
|
-
})).toEqual(
|
|
134
|
+
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
135
|
+
})).toEqual(20);
|
|
121
136
|
});
|
|
122
137
|
|
|
123
138
|
/* eslint-disable max-len */
|
|
124
|
-
it("should go to the next bitrate if the current one is maintainable and we have
|
|
139
|
+
it("should go to the next bitrate if the current one is maintainable and we have more buffer than the next level", () => {
|
|
125
140
|
/* eslint-enable max-len */
|
|
126
141
|
const logger = { debug: jest.fn() };
|
|
127
142
|
jest.mock("../../../log", () => ({ __esModule: true as const,
|
|
128
143
|
default: logger }));
|
|
129
144
|
const BufferBasedChooser = jest.requireActual("../buffer_based_chooser").default;
|
|
130
145
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
131
|
-
bufferGap:
|
|
146
|
+
bufferGap: 16,
|
|
132
147
|
speed: 1,
|
|
133
148
|
currentBitrate: 10,
|
|
134
|
-
currentScore: 1.
|
|
149
|
+
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
135
150
|
})).toEqual(20);
|
|
136
151
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
137
|
-
bufferGap:
|
|
152
|
+
bufferGap: 30,
|
|
138
153
|
speed: 1,
|
|
139
154
|
currentBitrate: 20,
|
|
140
|
-
currentScore: 1.
|
|
155
|
+
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
141
156
|
})).toEqual(40);
|
|
142
157
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
143
|
-
bufferGap:
|
|
158
|
+
bufferGap: 30,
|
|
144
159
|
speed: 1,
|
|
145
160
|
currentBitrate: 20,
|
|
146
|
-
currentScore: 100,
|
|
161
|
+
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
147
162
|
})).toEqual(40);
|
|
148
163
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
149
|
-
bufferGap:
|
|
164
|
+
bufferGap: 30,
|
|
150
165
|
speed: 2,
|
|
151
166
|
currentBitrate: 20,
|
|
152
|
-
currentScore: 2.
|
|
167
|
+
currentScore: { score: 2.30, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
153
168
|
})).toEqual(40);
|
|
154
169
|
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
|
|
155
|
-
bufferGap:
|
|
170
|
+
bufferGap: 30,
|
|
156
171
|
speed: 2,
|
|
157
172
|
currentBitrate: 20,
|
|
158
|
-
currentScore: 2.
|
|
173
|
+
currentScore: { score: 2.30, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
159
174
|
})).toEqual(40);
|
|
160
175
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
161
|
-
bufferGap:
|
|
176
|
+
bufferGap: 30,
|
|
162
177
|
speed: 0, // 0 is a special case
|
|
163
178
|
currentBitrate: 20,
|
|
164
|
-
currentScore: 100,
|
|
179
|
+
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
165
180
|
})).toEqual(40);
|
|
166
181
|
});
|
|
167
182
|
|
|
@@ -176,31 +191,31 @@ describe("BufferBasedChooser", () => {
|
|
|
176
191
|
bufferGap: 6,
|
|
177
192
|
speed: 1,
|
|
178
193
|
currentBitrate: 10,
|
|
179
|
-
currentScore: 1.
|
|
194
|
+
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
180
195
|
})).toEqual(10);
|
|
181
196
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
182
|
-
bufferGap:
|
|
197
|
+
bufferGap: 13,
|
|
183
198
|
speed: 1,
|
|
184
199
|
currentBitrate: 20,
|
|
185
|
-
currentScore: 1.
|
|
200
|
+
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
186
201
|
})).toEqual(20);
|
|
187
202
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
188
|
-
bufferGap:
|
|
203
|
+
bufferGap: 13,
|
|
189
204
|
speed: 1,
|
|
190
205
|
currentBitrate: 20,
|
|
191
|
-
currentScore: 100,
|
|
206
|
+
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
192
207
|
})).toEqual(20);
|
|
193
208
|
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
|
|
194
|
-
bufferGap:
|
|
209
|
+
bufferGap: 13,
|
|
195
210
|
speed: 1,
|
|
196
211
|
currentBitrate: 20,
|
|
197
|
-
currentScore: 100,
|
|
212
|
+
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
198
213
|
})).toEqual(20);
|
|
199
214
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
200
|
-
bufferGap:
|
|
215
|
+
bufferGap: 13,
|
|
201
216
|
speed: 2,
|
|
202
217
|
currentBitrate: 20,
|
|
203
|
-
currentScore: 2.
|
|
218
|
+
currentScore: { score: 2.30, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
204
219
|
})).toEqual(20);
|
|
205
220
|
});
|
|
206
221
|
|
|
@@ -216,13 +231,13 @@ describe("BufferBasedChooser", () => {
|
|
|
216
231
|
bufferGap: 100000000000,
|
|
217
232
|
speed: 1,
|
|
218
233
|
currentBitrate: 40,
|
|
219
|
-
currentScore: 1000000,
|
|
234
|
+
currentScore: { score: 1000000, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
220
235
|
})).toEqual(40);
|
|
221
236
|
expect(new BufferBasedChooser([10, 20, 40, 40]).getEstimate({
|
|
222
237
|
bufferGap: 100000000000,
|
|
223
238
|
speed: 1,
|
|
224
239
|
currentBitrate: 40,
|
|
225
|
-
currentScore: 1000000,
|
|
240
|
+
currentScore: { score: 1000000, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
226
241
|
})).toEqual(40);
|
|
227
242
|
});
|
|
228
243
|
|
|
@@ -237,31 +252,115 @@ describe("BufferBasedChooser", () => {
|
|
|
237
252
|
bufferGap: 15,
|
|
238
253
|
speed: 2,
|
|
239
254
|
currentBitrate: 10,
|
|
240
|
-
currentScore:
|
|
255
|
+
currentScore: { score: 2, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
241
256
|
})).toEqual(10);
|
|
242
257
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
243
|
-
bufferGap:
|
|
258
|
+
bufferGap: 22,
|
|
244
259
|
speed: 2,
|
|
245
260
|
currentBitrate: 20,
|
|
246
|
-
currentScore:
|
|
261
|
+
currentScore: { score: 2, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
247
262
|
})).toEqual(20);
|
|
248
263
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
249
|
-
bufferGap:
|
|
264
|
+
bufferGap: 22,
|
|
250
265
|
speed: 100,
|
|
251
266
|
currentBitrate: 20,
|
|
252
|
-
currentScore: 100,
|
|
267
|
+
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
253
268
|
})).toEqual(20);
|
|
254
269
|
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
|
|
255
|
-
bufferGap:
|
|
270
|
+
bufferGap: 22,
|
|
256
271
|
speed: 100,
|
|
257
272
|
currentBitrate: 20,
|
|
258
|
-
currentScore: 100,
|
|
273
|
+
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
259
274
|
})).toEqual(20);
|
|
260
275
|
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
261
|
-
bufferGap:
|
|
276
|
+
bufferGap: 22,
|
|
277
|
+
speed: 3,
|
|
278
|
+
currentBitrate: 20,
|
|
279
|
+
currentScore: { score: 3, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
280
|
+
})).toEqual(20);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
/* eslint-disable max-len */
|
|
284
|
+
it("should lower bitrate if the current one is not maintainable due to the speed", () => {
|
|
285
|
+
/* eslint-enable max-len */
|
|
286
|
+
const logger = { debug: jest.fn() };
|
|
287
|
+
jest.mock("../../../log", () => ({ __esModule: true as const,
|
|
288
|
+
default: logger }));
|
|
289
|
+
const BufferBasedChooser = jest.requireActual("../buffer_based_chooser").default;
|
|
290
|
+
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
291
|
+
bufferGap: 15,
|
|
292
|
+
speed: 2,
|
|
293
|
+
currentBitrate: 10,
|
|
294
|
+
currentScore: { score: 1.9, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
295
|
+
})).toEqual(10);
|
|
296
|
+
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
297
|
+
bufferGap: 22,
|
|
298
|
+
speed: 2,
|
|
299
|
+
currentBitrate: 20,
|
|
300
|
+
currentScore: { score: 1.9, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
301
|
+
})).toEqual(10);
|
|
302
|
+
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
303
|
+
bufferGap: 22,
|
|
304
|
+
speed: 100,
|
|
305
|
+
currentBitrate: 20,
|
|
306
|
+
currentScore: { score: 99, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
307
|
+
})).toEqual(10);
|
|
308
|
+
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
|
|
309
|
+
bufferGap: 22,
|
|
310
|
+
speed: 100,
|
|
311
|
+
currentBitrate: 20,
|
|
312
|
+
currentScore: { score: 99, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
313
|
+
})).toEqual(10);
|
|
314
|
+
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
315
|
+
bufferGap: 22,
|
|
316
|
+
speed: 3,
|
|
317
|
+
currentBitrate: 20,
|
|
318
|
+
currentScore: { score: 2.5, confidenceLevel: ScoreConfidenceLevel.HIGH },
|
|
319
|
+
})).toEqual(10);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
/* eslint-disable max-len */
|
|
323
|
+
it("should not lower bitrate if the current one is not maintainable due to the speed but confidence on the score is low", () => {
|
|
324
|
+
/* eslint-enable max-len */
|
|
325
|
+
const logger = { debug: jest.fn() };
|
|
326
|
+
jest.mock("../../../log", () => ({ __esModule: true as const,
|
|
327
|
+
default: logger }));
|
|
328
|
+
const BufferBasedChooser = jest.requireActual("../buffer_based_chooser").default;
|
|
329
|
+
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
330
|
+
bufferGap: 15,
|
|
331
|
+
speed: 2,
|
|
332
|
+
currentBitrate: 10,
|
|
333
|
+
currentScore: { score: 1.9, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
334
|
+
})).toEqual(10);
|
|
335
|
+
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
336
|
+
bufferGap: 22,
|
|
337
|
+
speed: 2,
|
|
338
|
+
currentBitrate: 20,
|
|
339
|
+
currentScore: undefined,
|
|
340
|
+
})).toEqual(20);
|
|
341
|
+
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
342
|
+
bufferGap: 22,
|
|
343
|
+
speed: 2,
|
|
344
|
+
currentBitrate: 20,
|
|
345
|
+
currentScore: { score: 1.9, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
346
|
+
})).toEqual(20);
|
|
347
|
+
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
348
|
+
bufferGap: 22,
|
|
349
|
+
speed: 100,
|
|
350
|
+
currentBitrate: 20,
|
|
351
|
+
currentScore: { score: 99, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
352
|
+
})).toEqual(20);
|
|
353
|
+
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
|
|
354
|
+
bufferGap: 22,
|
|
355
|
+
speed: 100,
|
|
356
|
+
currentBitrate: 20,
|
|
357
|
+
currentScore: { score: 99, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
358
|
+
})).toEqual(20);
|
|
359
|
+
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
|
|
360
|
+
bufferGap: 22,
|
|
262
361
|
speed: 3,
|
|
263
362
|
currentBitrate: 20,
|
|
264
|
-
currentScore: 2.
|
|
363
|
+
currentScore: { score: 2.5, confidenceLevel: ScoreConfidenceLevel.LOW },
|
|
265
364
|
})).toEqual(20);
|
|
266
365
|
});
|
|
267
366
|
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import config from "../../config";
|
|
17
18
|
import log from "../../log";
|
|
18
19
|
import Manifest, {
|
|
19
20
|
Adaptation,
|
|
@@ -189,7 +190,8 @@ function getEstimateReference(
|
|
|
189
190
|
* This TaskCanceller is used both for restarting estimates with a new
|
|
190
191
|
* configuration and to cancel them altogether.
|
|
191
192
|
*/
|
|
192
|
-
let currentEstimatesCanceller = new TaskCanceller(
|
|
193
|
+
let currentEstimatesCanceller = new TaskCanceller();
|
|
194
|
+
currentEstimatesCanceller.linkToSignal(stopAllEstimates);
|
|
193
195
|
|
|
194
196
|
// Create `ISharedReference` on which estimates will be emitted.
|
|
195
197
|
const estimateRef = createEstimateReference(representationsRef.getValue(),
|
|
@@ -259,8 +261,7 @@ function getEstimateReference(
|
|
|
259
261
|
const timeRanges = val.buffered;
|
|
260
262
|
const bufferGap = getLeftSizeOfRange(timeRanges, position.last);
|
|
261
263
|
const { representation } = val.content;
|
|
262
|
-
const
|
|
263
|
-
const currentScore = scoreData?.[0];
|
|
264
|
+
const currentScore = scoreCalculator.getEstimate(representation);
|
|
264
265
|
const currentBitrate = representation.bitrate;
|
|
265
266
|
const observation = { bufferGap, currentBitrate, currentScore, speed };
|
|
266
267
|
currentBufferBasedEstimate = bufferBasedChooser.getEstimate(observation);
|
|
@@ -306,11 +307,14 @@ function getEstimateReference(
|
|
|
306
307
|
lastPlaybackObservation.speed :
|
|
307
308
|
1);
|
|
308
309
|
|
|
309
|
-
|
|
310
|
+
const { ABR_ENTER_BUFFER_BASED_ALGO,
|
|
311
|
+
ABR_EXIT_BUFFER_BASED_ALGO } = config.getCurrent();
|
|
312
|
+
|
|
313
|
+
if (allowBufferBasedEstimates && bufferGap <= ABR_EXIT_BUFFER_BASED_ALGO) {
|
|
310
314
|
allowBufferBasedEstimates = false;
|
|
311
315
|
} else if (!allowBufferBasedEstimates &&
|
|
312
316
|
isFinite(bufferGap) &&
|
|
313
|
-
bufferGap
|
|
317
|
+
bufferGap >= ABR_ENTER_BUFFER_BASED_ALGO)
|
|
314
318
|
{
|
|
315
319
|
allowBufferBasedEstimates = true;
|
|
316
320
|
}
|
|
@@ -428,7 +432,8 @@ function getEstimateReference(
|
|
|
428
432
|
function restartEstimatesProductionFromCurrentConditions() : void {
|
|
429
433
|
const representations = representationsRef.getValue();
|
|
430
434
|
currentEstimatesCanceller.cancel();
|
|
431
|
-
currentEstimatesCanceller = new TaskCanceller(
|
|
435
|
+
currentEstimatesCanceller = new TaskCanceller();
|
|
436
|
+
currentEstimatesCanceller.linkToSignal(stopAllEstimates);
|
|
432
437
|
const newRef = createEstimateReference(representations,
|
|
433
438
|
currentEstimatesCanceller.signal);
|
|
434
439
|
|
|
@@ -17,6 +17,54 @@
|
|
|
17
17
|
import log from "../../log";
|
|
18
18
|
import arrayFindIndex from "../../utils/array_find_index";
|
|
19
19
|
import getBufferLevels from "./utils/get_buffer_levels";
|
|
20
|
+
import {
|
|
21
|
+
IRepresentationMaintainabilityScore,
|
|
22
|
+
ScoreConfidenceLevel,
|
|
23
|
+
} from "./utils/representation_score_calculator";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Minimum amount of time, in milliseconds, during which we are blocked from
|
|
27
|
+
* raising in quality after it had been considered as too high.
|
|
28
|
+
*/
|
|
29
|
+
const MINIMUM_BLOCK_RAISE_DELAY = 6000;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Maximum amount of time, in milliseconds, during which we are blocked from
|
|
33
|
+
* raising in quality after it had been considered as too high.
|
|
34
|
+
*/
|
|
35
|
+
const MAXIMUM_BLOCK_RAISE_DELAY = 15000;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Amount of time, in milliseconds, with which the blocking time in raising
|
|
39
|
+
* the quality will be incremented if the current quality estimate is seen
|
|
40
|
+
* as too unstable.
|
|
41
|
+
*/
|
|
42
|
+
const RAISE_BLOCKING_DELAY_INCREMENT = 3000;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Amount of time, in milliseconds, with which the blocking time in raising
|
|
46
|
+
* the quality will be dcremented if the current quality estimate is seen
|
|
47
|
+
* as relatively stable, until `MINIMUM_BLOCK_RAISE_DELAY` is reached.
|
|
48
|
+
*/
|
|
49
|
+
const RAISE_BLOCKING_DELAY_DECREMENT = 1000;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Amount of time, in milliseconds, after the "raise blocking delay" currently
|
|
53
|
+
* in place (during which it is forbidden to raise up in quality), during which
|
|
54
|
+
* we might want to raise the "raise blocking delay" if the last chosen quality
|
|
55
|
+
* seems unsuitable.
|
|
56
|
+
*
|
|
57
|
+
* For example, let's consider that the current raise blocking delay is at
|
|
58
|
+
* `4000`, or 4 seconds, and that this `STABILITY_CHECK_DELAY` is at `5000`, or
|
|
59
|
+
* 5 seconds.
|
|
60
|
+
* Here it means that if the estimated quality is found to be unsuitable less
|
|
61
|
+
* than 4+5 = 9 seconds after it last was, we will increment the raise blocking
|
|
62
|
+
* delay by `RAISE_BLOCKING_DELAY_INCREMENT` (unless `MAXIMUM_BLOCK_RAISE_DELAY`
|
|
63
|
+
* is reached).
|
|
64
|
+
* Else, if takes more than 9 seconds, the raise blocking delay might be
|
|
65
|
+
* decremented.
|
|
66
|
+
*/
|
|
67
|
+
const STABILITY_CHECK_DELAY = 9000;
|
|
20
68
|
|
|
21
69
|
/**
|
|
22
70
|
* Choose a bitrate based on the currently available buffer.
|
|
@@ -29,18 +77,41 @@ import getBufferLevels from "./utils/get_buffer_levels";
|
|
|
29
77
|
* "maintanable" or not.
|
|
30
78
|
* If so, we may switch to a better quality, or conversely to a worse quality.
|
|
31
79
|
*
|
|
80
|
+
* It also rely on mechanisms to avoid fluctuating too much between qualities.
|
|
81
|
+
*
|
|
32
82
|
* @class BufferBasedChooser
|
|
33
83
|
*/
|
|
34
84
|
export default class BufferBasedChooser {
|
|
35
85
|
private _levelsMap : number[];
|
|
36
86
|
private _bitrates : number[];
|
|
37
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Laast timestamp, in terms of `performance.now`, at which the current
|
|
90
|
+
* quality was seen as too high by this algorithm.
|
|
91
|
+
* Begins at `undefined`.
|
|
92
|
+
*/
|
|
93
|
+
private _lastUnsuitableQualityTimestamp: number | undefined;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* After lowering in quality, we forbid raising during a set amount of time.
|
|
97
|
+
* This amount is adaptive may continue to raise if it seems that quality
|
|
98
|
+
* is switching too much between low and high qualities.
|
|
99
|
+
*
|
|
100
|
+
* `_blockRaiseDelay` represents this time in milliseconds.
|
|
101
|
+
*/
|
|
102
|
+
private _blockRaiseDelay: number;
|
|
103
|
+
|
|
38
104
|
/**
|
|
39
105
|
* @param {Array.<number>} bitrates
|
|
40
106
|
*/
|
|
41
107
|
constructor(bitrates : number[]) {
|
|
42
|
-
this._levelsMap = getBufferLevels(bitrates)
|
|
108
|
+
this._levelsMap = getBufferLevels(bitrates).map(bl => {
|
|
109
|
+
return bl + 4; // Add some buffer security as it will be used conjointly with
|
|
110
|
+
// other algorithms anyway
|
|
111
|
+
});
|
|
43
112
|
this._bitrates = bitrates;
|
|
113
|
+
this._lastUnsuitableQualityTimestamp = undefined;
|
|
114
|
+
this._blockRaiseDelay = MINIMUM_BLOCK_RAISE_DELAY;
|
|
44
115
|
log.debug("ABR: Steps for buffer based chooser.",
|
|
45
116
|
this._levelsMap.map((l, i) => `bufferLevel: ${l}, bitrate: ${bitrates[i]}`)
|
|
46
117
|
.join(" ,"));
|
|
@@ -59,43 +130,90 @@ export default class BufferBasedChooser {
|
|
|
59
130
|
if (currentBitrate == null) {
|
|
60
131
|
return bitrates[0];
|
|
61
132
|
}
|
|
62
|
-
|
|
133
|
+
|
|
134
|
+
let currentBitrateIndex = -1;
|
|
135
|
+
for (let i = 0; i < bitrates.length; i++) {
|
|
136
|
+
// There could be bitrate duplicates. Only take the last one to simplify
|
|
137
|
+
const bitrate = bitrates[i];
|
|
138
|
+
if (bitrate === currentBitrate) {
|
|
139
|
+
currentBitrateIndex = i;
|
|
140
|
+
} else if (bitrate > currentBitrate) {
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
63
145
|
if (currentBitrateIndex < 0 || bitrates.length !== bufferLevels.length) {
|
|
64
146
|
log.error("ABR: Current Bitrate not found in the calculated levels");
|
|
65
147
|
return bitrates[0];
|
|
66
148
|
}
|
|
67
149
|
|
|
68
150
|
let scaledScore : number|undefined;
|
|
69
|
-
if (currentScore
|
|
70
|
-
scaledScore = speed === 0 ? currentScore : (currentScore / speed);
|
|
151
|
+
if (currentScore !== undefined) {
|
|
152
|
+
scaledScore = speed === 0 ? currentScore.score : (currentScore.score / speed);
|
|
71
153
|
}
|
|
72
154
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
155
|
+
const actualBufferGap = isFinite(bufferGap) ?
|
|
156
|
+
bufferGap :
|
|
157
|
+
0;
|
|
158
|
+
|
|
159
|
+
const now = performance.now();
|
|
160
|
+
|
|
161
|
+
if (
|
|
162
|
+
actualBufferGap < bufferLevels[currentBitrateIndex] ||
|
|
163
|
+
(
|
|
164
|
+
scaledScore !== undefined && scaledScore < 1 &&
|
|
165
|
+
currentScore?.confidenceLevel === ScoreConfidenceLevel.HIGH
|
|
166
|
+
)
|
|
167
|
+
) {
|
|
168
|
+
const timeSincePrev = this._lastUnsuitableQualityTimestamp === undefined ?
|
|
169
|
+
-1 :
|
|
170
|
+
now - this._lastUnsuitableQualityTimestamp;
|
|
171
|
+
if (timeSincePrev < this._blockRaiseDelay + STABILITY_CHECK_DELAY) {
|
|
172
|
+
const newDelay = this._blockRaiseDelay + RAISE_BLOCKING_DELAY_INCREMENT;
|
|
173
|
+
this._blockRaiseDelay = Math.min(newDelay, MAXIMUM_BLOCK_RAISE_DELAY);
|
|
174
|
+
log.debug("ABR: Incrementing blocking raise in BufferBasedChooser due " +
|
|
175
|
+
"to unstable quality",
|
|
176
|
+
this._blockRaiseDelay);
|
|
177
|
+
} else {
|
|
178
|
+
const newDelay = this._blockRaiseDelay - RAISE_BLOCKING_DELAY_DECREMENT;
|
|
179
|
+
this._blockRaiseDelay = Math.max(MINIMUM_BLOCK_RAISE_DELAY, newDelay);
|
|
180
|
+
log.debug("ABR: Lowering quality in BufferBasedChooser", this._blockRaiseDelay);
|
|
181
|
+
}
|
|
182
|
+
this._lastUnsuitableQualityTimestamp = now;
|
|
183
|
+
// Security if multiple bitrates are equal, we now take the first one
|
|
184
|
+
const baseIndex = arrayFindIndex(bitrates, (b) => b === currentBitrate);
|
|
185
|
+
for (let i = baseIndex - 1; i >= 0; i--) {
|
|
186
|
+
if (actualBufferGap >= bufferLevels[i]) {
|
|
187
|
+
return bitrates[i];
|
|
86
188
|
}
|
|
87
189
|
}
|
|
190
|
+
return bitrates[0];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (
|
|
194
|
+
(
|
|
195
|
+
this._lastUnsuitableQualityTimestamp !== undefined &&
|
|
196
|
+
now - this._lastUnsuitableQualityTimestamp < this._blockRaiseDelay
|
|
197
|
+
) ||
|
|
198
|
+
scaledScore === undefined || scaledScore < 1.15 ||
|
|
199
|
+
currentScore?.confidenceLevel !== ScoreConfidenceLevel.HIGH
|
|
200
|
+
) {
|
|
201
|
+
return currentBitrate;
|
|
88
202
|
}
|
|
89
203
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return bitrates[i];
|
|
96
|
-
}
|
|
204
|
+
const currentBufferLevel = bufferLevels[currentBitrateIndex];
|
|
205
|
+
const nextIndex = (() => {
|
|
206
|
+
for (let i = currentBitrateIndex + 1; i < bufferLevels.length; i++) {
|
|
207
|
+
if (bufferLevels[i] > currentBufferLevel) {
|
|
208
|
+
return i;
|
|
97
209
|
}
|
|
98
|
-
|
|
210
|
+
}
|
|
211
|
+
})();
|
|
212
|
+
if (nextIndex !== undefined) {
|
|
213
|
+
const nextBufferLevel = bufferLevels[nextIndex];
|
|
214
|
+
if (bufferGap >= nextBufferLevel) {
|
|
215
|
+
log.debug("ABR: Raising quality in BufferBasedChooser", bitrates[nextIndex]);
|
|
216
|
+
return bitrates[nextIndex];
|
|
99
217
|
}
|
|
100
218
|
}
|
|
101
219
|
return currentBitrate;
|
|
@@ -113,7 +231,7 @@ export interface IBufferBasedChooserPlaybackObservation {
|
|
|
113
231
|
/** The bitrate of the currently downloaded segments, in bps. */
|
|
114
232
|
currentBitrate? : number | undefined;
|
|
115
233
|
/** The "maintainability score" of the currently downloaded segments. */
|
|
116
|
-
currentScore? :
|
|
234
|
+
currentScore? : IRepresentationMaintainabilityScore | undefined;
|
|
117
235
|
/** Playback rate wanted (e.g. `1` is regular playback, `2` is double speed etc.). */
|
|
118
236
|
speed : number;
|
|
119
237
|
}
|
|
@@ -23,6 +23,7 @@ import LastEstimateStorage, {
|
|
|
23
23
|
} from "./utils/last_estimate_storage";
|
|
24
24
|
import { IRequestInfo } from "./utils/pending_requests_store";
|
|
25
25
|
import RepresentationScoreCalculator, {
|
|
26
|
+
IRepresentationMaintainabilityScore,
|
|
26
27
|
ScoreConfidenceLevel,
|
|
27
28
|
} from "./utils/representation_score_calculator";
|
|
28
29
|
|
|
@@ -178,11 +179,11 @@ export default class GuessBasedChooser {
|
|
|
178
179
|
private _canGuessHigher(
|
|
179
180
|
bufferGap : number,
|
|
180
181
|
speed : number,
|
|
181
|
-
|
|
182
|
+
{ score, confidenceLevel } : IRepresentationMaintainabilityScore
|
|
182
183
|
) : boolean {
|
|
183
184
|
return isFinite(bufferGap) && bufferGap >= 2.5 &&
|
|
184
185
|
performance.now() > this._blockGuessesUntil &&
|
|
185
|
-
|
|
186
|
+
confidenceLevel === ScoreConfidenceLevel.HIGH &&
|
|
186
187
|
score / speed > 1.01;
|
|
187
188
|
}
|
|
188
189
|
|
|
@@ -197,13 +198,13 @@ export default class GuessBasedChooser {
|
|
|
197
198
|
*/
|
|
198
199
|
private _shouldStopGuess(
|
|
199
200
|
lastGuess : Representation,
|
|
200
|
-
scoreData :
|
|
201
|
+
scoreData : IRepresentationMaintainabilityScore | undefined,
|
|
201
202
|
bufferGap : number,
|
|
202
203
|
requests : IRequestInfo[]
|
|
203
204
|
) : boolean {
|
|
204
|
-
if (scoreData !== undefined && scoreData
|
|
205
|
+
if (scoreData !== undefined && scoreData.score < 1.01) {
|
|
205
206
|
return true;
|
|
206
|
-
} else if ((scoreData === undefined || scoreData
|
|
207
|
+
} else if ((scoreData === undefined || scoreData.score < 1.2) && bufferGap < 0.6) {
|
|
207
208
|
return true;
|
|
208
209
|
}
|
|
209
210
|
|
|
@@ -233,11 +234,11 @@ export default class GuessBasedChooser {
|
|
|
233
234
|
private _isLastGuessValidated(
|
|
234
235
|
lastGuess : Representation,
|
|
235
236
|
incomingBestBitrate : number,
|
|
236
|
-
scoreData :
|
|
237
|
+
scoreData : IRepresentationMaintainabilityScore | undefined
|
|
237
238
|
) : boolean {
|
|
238
239
|
if (scoreData !== undefined &&
|
|
239
|
-
scoreData
|
|
240
|
-
scoreData
|
|
240
|
+
scoreData.confidenceLevel === ScoreConfidenceLevel.HIGH &&
|
|
241
|
+
scoreData.score > 1.5)
|
|
241
242
|
{
|
|
242
243
|
return true;
|
|
243
244
|
}
|