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
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
import { IRepresentationMaintainabilityScore } from "./utils/representation_score_calculator";
|
|
16
17
|
/**
|
|
17
18
|
* Choose a bitrate based on the currently available buffer.
|
|
18
19
|
*
|
|
@@ -24,11 +25,27 @@
|
|
|
24
25
|
* "maintanable" or not.
|
|
25
26
|
* If so, we may switch to a better quality, or conversely to a worse quality.
|
|
26
27
|
*
|
|
28
|
+
* It also rely on mechanisms to avoid fluctuating too much between qualities.
|
|
29
|
+
*
|
|
27
30
|
* @class BufferBasedChooser
|
|
28
31
|
*/
|
|
29
32
|
export default class BufferBasedChooser {
|
|
30
33
|
private _levelsMap;
|
|
31
34
|
private _bitrates;
|
|
35
|
+
/**
|
|
36
|
+
* Laast timestamp, in terms of `performance.now`, at which the current
|
|
37
|
+
* quality was seen as too high by this algorithm.
|
|
38
|
+
* Begins at `undefined`.
|
|
39
|
+
*/
|
|
40
|
+
private _lastUnsuitableQualityTimestamp;
|
|
41
|
+
/**
|
|
42
|
+
* After lowering in quality, we forbid raising during a set amount of time.
|
|
43
|
+
* This amount is adaptive may continue to raise if it seems that quality
|
|
44
|
+
* is switching too much between low and high qualities.
|
|
45
|
+
*
|
|
46
|
+
* `_blockRaiseDelay` represents this time in milliseconds.
|
|
47
|
+
*/
|
|
48
|
+
private _blockRaiseDelay;
|
|
32
49
|
/**
|
|
33
50
|
* @param {Array.<number>} bitrates
|
|
34
51
|
*/
|
|
@@ -50,7 +67,7 @@ export interface IBufferBasedChooserPlaybackObservation {
|
|
|
50
67
|
/** The bitrate of the currently downloaded segments, in bps. */
|
|
51
68
|
currentBitrate?: number | undefined;
|
|
52
69
|
/** The "maintainability score" of the currently downloaded segments. */
|
|
53
|
-
currentScore?:
|
|
70
|
+
currentScore?: IRepresentationMaintainabilityScore | undefined;
|
|
54
71
|
/** Playback rate wanted (e.g. `1` is regular playback, `2` is double speed etc.). */
|
|
55
72
|
speed: number;
|
|
56
73
|
}
|
|
@@ -16,6 +16,45 @@
|
|
|
16
16
|
import log from "../../log";
|
|
17
17
|
import arrayFindIndex from "../../utils/array_find_index";
|
|
18
18
|
import getBufferLevels from "./utils/get_buffer_levels";
|
|
19
|
+
/**
|
|
20
|
+
* Minimum amount of time, in milliseconds, during which we are blocked from
|
|
21
|
+
* raising in quality after it had been considered as too high.
|
|
22
|
+
*/
|
|
23
|
+
var MINIMUM_BLOCK_RAISE_DELAY = 6000;
|
|
24
|
+
/**
|
|
25
|
+
* Maximum amount of time, in milliseconds, during which we are blocked from
|
|
26
|
+
* raising in quality after it had been considered as too high.
|
|
27
|
+
*/
|
|
28
|
+
var MAXIMUM_BLOCK_RAISE_DELAY = 15000;
|
|
29
|
+
/**
|
|
30
|
+
* Amount of time, in milliseconds, with which the blocking time in raising
|
|
31
|
+
* the quality will be incremented if the current quality estimate is seen
|
|
32
|
+
* as too unstable.
|
|
33
|
+
*/
|
|
34
|
+
var RAISE_BLOCKING_DELAY_INCREMENT = 3000;
|
|
35
|
+
/**
|
|
36
|
+
* Amount of time, in milliseconds, with which the blocking time in raising
|
|
37
|
+
* the quality will be dcremented if the current quality estimate is seen
|
|
38
|
+
* as relatively stable, until `MINIMUM_BLOCK_RAISE_DELAY` is reached.
|
|
39
|
+
*/
|
|
40
|
+
var RAISE_BLOCKING_DELAY_DECREMENT = 1000;
|
|
41
|
+
/**
|
|
42
|
+
* Amount of time, in milliseconds, after the "raise blocking delay" currently
|
|
43
|
+
* in place (during which it is forbidden to raise up in quality), during which
|
|
44
|
+
* we might want to raise the "raise blocking delay" if the last chosen quality
|
|
45
|
+
* seems unsuitable.
|
|
46
|
+
*
|
|
47
|
+
* For example, let's consider that the current raise blocking delay is at
|
|
48
|
+
* `4000`, or 4 seconds, and that this `STABILITY_CHECK_DELAY` is at `5000`, or
|
|
49
|
+
* 5 seconds.
|
|
50
|
+
* Here it means that if the estimated quality is found to be unsuitable less
|
|
51
|
+
* than 4+5 = 9 seconds after it last was, we will increment the raise blocking
|
|
52
|
+
* delay by `RAISE_BLOCKING_DELAY_INCREMENT` (unless `MAXIMUM_BLOCK_RAISE_DELAY`
|
|
53
|
+
* is reached).
|
|
54
|
+
* Else, if takes more than 9 seconds, the raise blocking delay might be
|
|
55
|
+
* decremented.
|
|
56
|
+
*/
|
|
57
|
+
var STABILITY_CHECK_DELAY = 9000;
|
|
19
58
|
/**
|
|
20
59
|
* Choose a bitrate based on the currently available buffer.
|
|
21
60
|
*
|
|
@@ -27,6 +66,8 @@ import getBufferLevels from "./utils/get_buffer_levels";
|
|
|
27
66
|
* "maintanable" or not.
|
|
28
67
|
* If so, we may switch to a better quality, or conversely to a worse quality.
|
|
29
68
|
*
|
|
69
|
+
* It also rely on mechanisms to avoid fluctuating too much between qualities.
|
|
70
|
+
*
|
|
30
71
|
* @class BufferBasedChooser
|
|
31
72
|
*/
|
|
32
73
|
var BufferBasedChooser = /** @class */ (function () {
|
|
@@ -34,8 +75,13 @@ var BufferBasedChooser = /** @class */ (function () {
|
|
|
34
75
|
* @param {Array.<number>} bitrates
|
|
35
76
|
*/
|
|
36
77
|
function BufferBasedChooser(bitrates) {
|
|
37
|
-
this._levelsMap = getBufferLevels(bitrates)
|
|
78
|
+
this._levelsMap = getBufferLevels(bitrates).map(function (bl) {
|
|
79
|
+
return bl + 4; // Add some buffer security as it will be used conjointly with
|
|
80
|
+
// other algorithms anyway
|
|
81
|
+
});
|
|
38
82
|
this._bitrates = bitrates;
|
|
83
|
+
this._lastUnsuitableQualityTimestamp = undefined;
|
|
84
|
+
this._blockRaiseDelay = MINIMUM_BLOCK_RAISE_DELAY;
|
|
39
85
|
log.debug("ABR: Steps for buffer based chooser.", this._levelsMap.map(function (l, i) { return "bufferLevel: ".concat(l, ", bitrate: ").concat(bitrates[i]); })
|
|
40
86
|
.join(" ,"));
|
|
41
87
|
}
|
|
@@ -50,40 +96,75 @@ var BufferBasedChooser = /** @class */ (function () {
|
|
|
50
96
|
if (currentBitrate == null) {
|
|
51
97
|
return bitrates[0];
|
|
52
98
|
}
|
|
53
|
-
var currentBitrateIndex =
|
|
99
|
+
var currentBitrateIndex = -1;
|
|
100
|
+
for (var i = 0; i < bitrates.length; i++) {
|
|
101
|
+
// There could be bitrate duplicates. Only take the last one to simplify
|
|
102
|
+
var bitrate = bitrates[i];
|
|
103
|
+
if (bitrate === currentBitrate) {
|
|
104
|
+
currentBitrateIndex = i;
|
|
105
|
+
}
|
|
106
|
+
else if (bitrate > currentBitrate) {
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
54
110
|
if (currentBitrateIndex < 0 || bitrates.length !== bufferLevels.length) {
|
|
55
111
|
log.error("ABR: Current Bitrate not found in the calculated levels");
|
|
56
112
|
return bitrates[0];
|
|
57
113
|
}
|
|
58
114
|
var scaledScore;
|
|
59
|
-
if (currentScore
|
|
60
|
-
scaledScore = speed === 0 ? currentScore : (currentScore / speed);
|
|
115
|
+
if (currentScore !== undefined) {
|
|
116
|
+
scaledScore = speed === 0 ? currentScore.score : (currentScore.score / speed);
|
|
61
117
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
118
|
+
var actualBufferGap = isFinite(bufferGap) ?
|
|
119
|
+
bufferGap :
|
|
120
|
+
0;
|
|
121
|
+
var now = performance.now();
|
|
122
|
+
if (actualBufferGap < bufferLevels[currentBitrateIndex] ||
|
|
123
|
+
(scaledScore !== undefined && scaledScore < 1 &&
|
|
124
|
+
(currentScore === null || currentScore === void 0 ? void 0 : currentScore.confidenceLevel) === 1 /* ScoreConfidenceLevel.HIGH */)) {
|
|
125
|
+
var timeSincePrev = this._lastUnsuitableQualityTimestamp === undefined ?
|
|
126
|
+
-1 :
|
|
127
|
+
now - this._lastUnsuitableQualityTimestamp;
|
|
128
|
+
if (timeSincePrev < this._blockRaiseDelay + STABILITY_CHECK_DELAY) {
|
|
129
|
+
var newDelay = this._blockRaiseDelay + RAISE_BLOCKING_DELAY_INCREMENT;
|
|
130
|
+
this._blockRaiseDelay = Math.min(newDelay, MAXIMUM_BLOCK_RAISE_DELAY);
|
|
131
|
+
log.debug("ABR: Incrementing blocking raise in BufferBasedChooser due " +
|
|
132
|
+
"to unstable quality", this._blockRaiseDelay);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
var newDelay = this._blockRaiseDelay - RAISE_BLOCKING_DELAY_DECREMENT;
|
|
136
|
+
this._blockRaiseDelay = Math.max(MINIMUM_BLOCK_RAISE_DELAY, newDelay);
|
|
137
|
+
log.debug("ABR: Lowering quality in BufferBasedChooser", this._blockRaiseDelay);
|
|
138
|
+
}
|
|
139
|
+
this._lastUnsuitableQualityTimestamp = now;
|
|
140
|
+
// Security if multiple bitrates are equal, we now take the first one
|
|
141
|
+
var baseIndex = arrayFindIndex(bitrates, function (b) { return b === currentBitrate; });
|
|
142
|
+
for (var i = baseIndex - 1; i >= 0; i--) {
|
|
143
|
+
if (actualBufferGap >= bufferLevels[i]) {
|
|
144
|
+
return bitrates[i];
|
|
75
145
|
}
|
|
76
146
|
}
|
|
147
|
+
return bitrates[0];
|
|
77
148
|
}
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
149
|
+
if ((this._lastUnsuitableQualityTimestamp !== undefined &&
|
|
150
|
+
now - this._lastUnsuitableQualityTimestamp < this._blockRaiseDelay) ||
|
|
151
|
+
scaledScore === undefined || scaledScore < 1.15 ||
|
|
152
|
+
(currentScore === null || currentScore === void 0 ? void 0 : currentScore.confidenceLevel) !== 1 /* ScoreConfidenceLevel.HIGH */) {
|
|
153
|
+
return currentBitrate;
|
|
154
|
+
}
|
|
155
|
+
var currentBufferLevel = bufferLevels[currentBitrateIndex];
|
|
156
|
+
var nextIndex = (function () {
|
|
157
|
+
for (var i = currentBitrateIndex + 1; i < bufferLevels.length; i++) {
|
|
158
|
+
if (bufferLevels[i] > currentBufferLevel) {
|
|
159
|
+
return i;
|
|
85
160
|
}
|
|
86
|
-
|
|
161
|
+
}
|
|
162
|
+
})();
|
|
163
|
+
if (nextIndex !== undefined) {
|
|
164
|
+
var nextBufferLevel = bufferLevels[nextIndex];
|
|
165
|
+
if (bufferGap >= nextBufferLevel) {
|
|
166
|
+
log.debug("ABR: Raising quality in BufferBasedChooser", bitrates[nextIndex]);
|
|
167
|
+
return bitrates[nextIndex];
|
|
87
168
|
}
|
|
88
169
|
}
|
|
89
170
|
return currentBitrate;
|
|
@@ -127,10 +127,10 @@ var GuessBasedChooser = /** @class */ (function () {
|
|
|
127
127
|
* @returns {boolean}
|
|
128
128
|
*/
|
|
129
129
|
GuessBasedChooser.prototype._canGuessHigher = function (bufferGap, speed, _a) {
|
|
130
|
-
var score = _a
|
|
130
|
+
var score = _a.score, confidenceLevel = _a.confidenceLevel;
|
|
131
131
|
return isFinite(bufferGap) && bufferGap >= 2.5 &&
|
|
132
132
|
performance.now() > this._blockGuessesUntil &&
|
|
133
|
-
|
|
133
|
+
confidenceLevel === 1 /* ScoreConfidenceLevel.HIGH */ &&
|
|
134
134
|
score / speed > 1.01;
|
|
135
135
|
};
|
|
136
136
|
/**
|
|
@@ -143,10 +143,10 @@ var GuessBasedChooser = /** @class */ (function () {
|
|
|
143
143
|
* @returns {boolean}
|
|
144
144
|
*/
|
|
145
145
|
GuessBasedChooser.prototype._shouldStopGuess = function (lastGuess, scoreData, bufferGap, requests) {
|
|
146
|
-
if (scoreData !== undefined && scoreData
|
|
146
|
+
if (scoreData !== undefined && scoreData.score < 1.01) {
|
|
147
147
|
return true;
|
|
148
148
|
}
|
|
149
|
-
else if ((scoreData === undefined || scoreData
|
|
149
|
+
else if ((scoreData === undefined || scoreData.score < 1.2) && bufferGap < 0.6) {
|
|
150
150
|
return true;
|
|
151
151
|
}
|
|
152
152
|
var guessedRepresentationRequests = requests.filter(function (req) {
|
|
@@ -175,8 +175,8 @@ var GuessBasedChooser = /** @class */ (function () {
|
|
|
175
175
|
};
|
|
176
176
|
GuessBasedChooser.prototype._isLastGuessValidated = function (lastGuess, incomingBestBitrate, scoreData) {
|
|
177
177
|
if (scoreData !== undefined &&
|
|
178
|
-
scoreData
|
|
179
|
-
scoreData
|
|
178
|
+
scoreData.confidenceLevel === 1 /* ScoreConfidenceLevel.HIGH */ &&
|
|
179
|
+
scoreData.score > 1.5) {
|
|
180
180
|
return true;
|
|
181
181
|
}
|
|
182
182
|
return incomingBestBitrate >= lastGuess.bitrate &&
|
|
@@ -126,6 +126,12 @@ function estimateStarvationModeBitrate(pendingRequests, playbackInfo, currentRep
|
|
|
126
126
|
}
|
|
127
127
|
var concernedRequest = concernedRequests[0];
|
|
128
128
|
var now = performance.now();
|
|
129
|
+
var minimumRequestTime = concernedRequest.content.segment.duration * 1.5;
|
|
130
|
+
minimumRequestTime = Math.min(minimumRequestTime, 3000);
|
|
131
|
+
minimumRequestTime = Math.max(minimumRequestTime, 12000);
|
|
132
|
+
if (now - concernedRequest.requestTimestamp < minimumRequestTime) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
129
135
|
var lastProgressEvent = concernedRequest.progress.length > 0 ?
|
|
130
136
|
concernedRequest.progress[concernedRequest.progress.length - 1] :
|
|
131
137
|
undefined;
|
|
@@ -138,7 +144,7 @@ function estimateStarvationModeBitrate(pendingRequests, playbackInfo, currentRep
|
|
|
138
144
|
// Calculate estimated time spent rebuffering if we continue doing that request.
|
|
139
145
|
var expectedRebufferingTime = remainingTime -
|
|
140
146
|
(realBufferGap / speed);
|
|
141
|
-
if (expectedRebufferingTime >
|
|
147
|
+
if (expectedRebufferingTime > 2500) {
|
|
142
148
|
return bandwidthEstimate;
|
|
143
149
|
}
|
|
144
150
|
}
|
|
@@ -320,12 +326,9 @@ var NetworkAnalyzer = /** @class */ (function () {
|
|
|
320
326
|
if (currentRepresentation === null) {
|
|
321
327
|
return true;
|
|
322
328
|
}
|
|
323
|
-
else if (bitrate
|
|
329
|
+
else if (bitrate >= currentRepresentation.bitrate) {
|
|
324
330
|
return false;
|
|
325
331
|
}
|
|
326
|
-
else if (bitrate > currentRepresentation.bitrate) {
|
|
327
|
-
return !this._inStarvationMode;
|
|
328
|
-
}
|
|
329
332
|
return shouldDirectlySwitchToLowBitrate(playbackInfo, currentRequests, this._lowLatencyMode);
|
|
330
333
|
};
|
|
331
334
|
return NetworkAnalyzer;
|
|
@@ -14,6 +14,24 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { Representation } from "../../../manifest";
|
|
17
|
+
/**
|
|
18
|
+
* Object representing a maintainability score as calculated by the
|
|
19
|
+
* `RepresentationScoreCalculator`.
|
|
20
|
+
*/
|
|
21
|
+
export interface IRepresentationMaintainabilityScore {
|
|
22
|
+
/**
|
|
23
|
+
* Weighted mean of dividing the loaded segment's duration by the time to make
|
|
24
|
+
* their request.
|
|
25
|
+
*/
|
|
26
|
+
score: number;
|
|
27
|
+
/**
|
|
28
|
+
* The confidence we have on the calculated `score` in reflecting a useful
|
|
29
|
+
* maintainability hint for the concerned Representation.
|
|
30
|
+
*
|
|
31
|
+
* Basically, the more segments have been loaded, the higher the confidence.
|
|
32
|
+
*/
|
|
33
|
+
confidenceLevel: ScoreConfidenceLevel;
|
|
34
|
+
}
|
|
17
35
|
/**
|
|
18
36
|
* Calculate the "maintainability score" of a given Representation:
|
|
19
37
|
* - A score higher than 1 means that the Representation can theorically
|
|
@@ -62,7 +80,7 @@ export default class RepresentationScoreCalculator {
|
|
|
62
80
|
* @param {Representation} representation
|
|
63
81
|
* @returns {number|undefined}
|
|
64
82
|
*/
|
|
65
|
-
getEstimate(representation: Representation):
|
|
83
|
+
getEstimate(representation: Representation): IRepresentationMaintainabilityScore | undefined;
|
|
66
84
|
/**
|
|
67
85
|
* Returns last Representation which had reached a score superior to 1.
|
|
68
86
|
* This Representation is the last known one which could be maintained.
|
|
@@ -96,7 +96,7 @@ var RepresentationScoreCalculator = /** @class */ (function () {
|
|
|
96
96
|
var confidenceLevel = loadedSegments >= 5 &&
|
|
97
97
|
loadedDuration >= 10 ? 1 /* ScoreConfidenceLevel.HIGH */ :
|
|
98
98
|
0 /* ScoreConfidenceLevel.LOW */;
|
|
99
|
-
return
|
|
99
|
+
return { score: estimate, confidenceLevel: confidenceLevel };
|
|
100
100
|
};
|
|
101
101
|
/**
|
|
102
102
|
* Returns last Representation which had reached a score superior to 1.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { IBufferedChunk } from "../../segment_buffers";
|
|
2
|
+
export interface ISegmentBufferGrapUpdateData {
|
|
3
|
+
currentTime: number;
|
|
4
|
+
inventory: IBufferedChunk[];
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
minimumPosition: number | undefined;
|
|
8
|
+
maximumPosition: number | undefined;
|
|
9
|
+
}
|
|
10
|
+
export default class SegmentBufferGraph {
|
|
11
|
+
/** Link buffered Representation to their corresponding color. */
|
|
12
|
+
private readonly _colorMap;
|
|
13
|
+
/** Current amount of colors chosen to represent the various Representation. */
|
|
14
|
+
private _currNbColors;
|
|
15
|
+
/** Canvas that will contain the buffer graph itself. */
|
|
16
|
+
private readonly _canvasElt;
|
|
17
|
+
private readonly _canvasCtxt;
|
|
18
|
+
constructor(canvasElt: HTMLCanvasElement);
|
|
19
|
+
clear(): void;
|
|
20
|
+
update(data: ISegmentBufferGrapUpdateData): void;
|
|
21
|
+
/**
|
|
22
|
+
* Paint a given range in the canvas
|
|
23
|
+
* @param {Object} rangeScaled - Buffered segment information with added
|
|
24
|
+
* "scaling" information to know where it fits in the canvas.
|
|
25
|
+
*/
|
|
26
|
+
private _paintRange;
|
|
27
|
+
private _getColorForRepresentation;
|
|
28
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
var BUFFER_WIDTH_IN_SECONDS = 10000;
|
|
2
|
+
var COLORS = [
|
|
3
|
+
"#2ab7ca",
|
|
4
|
+
"#fed766",
|
|
5
|
+
"#4dd248",
|
|
6
|
+
"#a22c28",
|
|
7
|
+
"#556b2f",
|
|
8
|
+
"#add8e6",
|
|
9
|
+
"#90ee90",
|
|
10
|
+
"#444444",
|
|
11
|
+
"#40bfc1",
|
|
12
|
+
"#57557e",
|
|
13
|
+
"#fbe555",
|
|
14
|
+
];
|
|
15
|
+
var SegmentBufferGraph = /** @class */ (function () {
|
|
16
|
+
function SegmentBufferGraph(canvasElt) {
|
|
17
|
+
this._colorMap = new WeakMap();
|
|
18
|
+
this._currNbColors = 0;
|
|
19
|
+
this._canvasElt = canvasElt;
|
|
20
|
+
this._canvasCtxt = this._canvasElt.getContext("2d");
|
|
21
|
+
this.clear();
|
|
22
|
+
}
|
|
23
|
+
SegmentBufferGraph.prototype.clear = function () {
|
|
24
|
+
if (this._canvasCtxt !== null) {
|
|
25
|
+
this._canvasCtxt.clearRect(0, 0, this._canvasElt.width, this._canvasElt.height);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
SegmentBufferGraph.prototype.update = function (data) {
|
|
29
|
+
var _a, _b, _c, _d;
|
|
30
|
+
if (this._canvasCtxt === null) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
var inventory = data.inventory, currentTime = data.currentTime, width = data.width, height = data.height;
|
|
34
|
+
this._canvasElt.style.width = "".concat(width, "px");
|
|
35
|
+
this._canvasElt.style.height = "".concat(height, "px");
|
|
36
|
+
this._canvasElt.width = width;
|
|
37
|
+
this._canvasElt.height = height;
|
|
38
|
+
this.clear();
|
|
39
|
+
var minimumPoint;
|
|
40
|
+
if (data.minimumPosition !== undefined) {
|
|
41
|
+
if (inventory.length > 0) {
|
|
42
|
+
minimumPoint = Math.min(data.minimumPosition, inventory[0].start);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
minimumPoint = data.minimumPosition;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
minimumPoint = (_b = (_a = inventory[0]) === null || _a === void 0 ? void 0 : _a.start) !== null && _b !== void 0 ? _b : 0;
|
|
50
|
+
}
|
|
51
|
+
var maximumPoint;
|
|
52
|
+
if (data.maximumPosition !== undefined) {
|
|
53
|
+
if (inventory.length > 0) {
|
|
54
|
+
maximumPoint = Math.max(data.maximumPosition, inventory[inventory.length - 1].end);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
maximumPoint = data.maximumPosition;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
maximumPoint = (_d = (_c = inventory[inventory.length - 1]) === null || _c === void 0 ? void 0 : _c.end) !== null && _d !== void 0 ? _d : 1000;
|
|
62
|
+
}
|
|
63
|
+
minimumPoint = Math.min(currentTime, minimumPoint);
|
|
64
|
+
maximumPoint = Math.max(currentTime, maximumPoint);
|
|
65
|
+
var minimumPosition;
|
|
66
|
+
var maximumPosition;
|
|
67
|
+
if (maximumPoint - minimumPoint > BUFFER_WIDTH_IN_SECONDS) {
|
|
68
|
+
if (currentTime === undefined) {
|
|
69
|
+
minimumPosition = minimumPoint;
|
|
70
|
+
maximumPosition = maximumPoint;
|
|
71
|
+
}
|
|
72
|
+
else if (maximumPoint - currentTime < BUFFER_WIDTH_IN_SECONDS / 2) {
|
|
73
|
+
maximumPosition = maximumPoint;
|
|
74
|
+
minimumPosition = maximumPoint - BUFFER_WIDTH_IN_SECONDS;
|
|
75
|
+
}
|
|
76
|
+
else if (currentTime - minimumPoint < BUFFER_WIDTH_IN_SECONDS / 2) {
|
|
77
|
+
minimumPosition = minimumPoint;
|
|
78
|
+
maximumPosition = minimumPoint + BUFFER_WIDTH_IN_SECONDS;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
minimumPosition = currentTime - BUFFER_WIDTH_IN_SECONDS / 2;
|
|
82
|
+
maximumPosition = currentTime + BUFFER_WIDTH_IN_SECONDS / 2;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
minimumPosition = minimumPoint;
|
|
87
|
+
maximumPosition = maximumPoint;
|
|
88
|
+
}
|
|
89
|
+
if (minimumPosition >= maximumPosition) {
|
|
90
|
+
this.clear();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
var currentRangesScaled = scaleSegments(inventory, minimumPosition, maximumPosition);
|
|
94
|
+
for (var i = 0; i < currentRangesScaled.length; i++) {
|
|
95
|
+
this._paintRange(currentRangesScaled[i], width, height);
|
|
96
|
+
}
|
|
97
|
+
if (currentTime !== undefined) {
|
|
98
|
+
paintCurrentPosition(currentTime, minimumPosition, maximumPosition, this._canvasCtxt, width, height);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Paint a given range in the canvas
|
|
103
|
+
* @param {Object} rangeScaled - Buffered segment information with added
|
|
104
|
+
* "scaling" information to know where it fits in the canvas.
|
|
105
|
+
*/
|
|
106
|
+
SegmentBufferGraph.prototype._paintRange = function (rangeScaled, width, height) {
|
|
107
|
+
if (this._canvasCtxt === null) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
var startX = rangeScaled.scaledStart * width;
|
|
111
|
+
var endX = rangeScaled.scaledEnd * width;
|
|
112
|
+
this._canvasCtxt.fillStyle = this._getColorForRepresentation(rangeScaled.info.infos.representation);
|
|
113
|
+
this._canvasCtxt.fillRect(Math.ceil(startX), 0, Math.ceil(endX - startX), height);
|
|
114
|
+
};
|
|
115
|
+
SegmentBufferGraph.prototype._getColorForRepresentation = function (representation) {
|
|
116
|
+
var color = this._colorMap.get(representation);
|
|
117
|
+
if (color !== undefined) {
|
|
118
|
+
return color;
|
|
119
|
+
}
|
|
120
|
+
var newColor = COLORS[this._currNbColors % COLORS.length];
|
|
121
|
+
this._currNbColors++;
|
|
122
|
+
this._colorMap.set(representation, newColor);
|
|
123
|
+
return newColor;
|
|
124
|
+
};
|
|
125
|
+
return SegmentBufferGraph;
|
|
126
|
+
}());
|
|
127
|
+
export default SegmentBufferGraph;
|
|
128
|
+
/**
|
|
129
|
+
* Represent the current position in the canvas.
|
|
130
|
+
* @param {number|undefined} position - The current position
|
|
131
|
+
* @param {number} minimumPosition - minimum possible position represented in
|
|
132
|
+
* the canvas.
|
|
133
|
+
* @param {number} maximumPosition - maximum possible position represented in
|
|
134
|
+
* the canvas.
|
|
135
|
+
* @param {Object} canvasCtx - The canvas' 2D context
|
|
136
|
+
*/
|
|
137
|
+
function paintCurrentPosition(position, minimumPosition, maximumPosition, canvasCtx, width, height) {
|
|
138
|
+
if (typeof position === "number" &&
|
|
139
|
+
position >= minimumPosition &&
|
|
140
|
+
position < maximumPosition) {
|
|
141
|
+
var lengthCanvas = maximumPosition - minimumPosition;
|
|
142
|
+
canvasCtx.fillStyle = "#FF0000";
|
|
143
|
+
canvasCtx.fillRect(Math.ceil((position - minimumPosition) /
|
|
144
|
+
lengthCanvas * width) - 1, 5, 5, height);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Scale given bufferedData in terms of percentage between the minimum and
|
|
149
|
+
* maximum position. Filter out ranges which are not part of it.
|
|
150
|
+
* @param {Array.<Object>} bufferedData
|
|
151
|
+
* @param {number} minimumPosition
|
|
152
|
+
* @param {number} maximumPosition
|
|
153
|
+
* @returns {Array.<Object>}
|
|
154
|
+
*/
|
|
155
|
+
function scaleSegments(bufferedData, minimumPosition, maximumPosition) {
|
|
156
|
+
var scaledSegments = [];
|
|
157
|
+
var wholeDuration = maximumPosition - minimumPosition;
|
|
158
|
+
for (var i = 0; i < bufferedData.length; i++) {
|
|
159
|
+
var info = bufferedData[i];
|
|
160
|
+
var start = info.bufferedStart === undefined ?
|
|
161
|
+
info.start :
|
|
162
|
+
info.bufferedStart;
|
|
163
|
+
var end = info.bufferedEnd === undefined ?
|
|
164
|
+
info.end :
|
|
165
|
+
info.bufferedEnd;
|
|
166
|
+
if (end > minimumPosition && start < maximumPosition) {
|
|
167
|
+
var startPoint = Math.max(start - minimumPosition, 0);
|
|
168
|
+
var endPoint = Math.min(end - minimumPosition, maximumPosition);
|
|
169
|
+
var scaledStart = startPoint / wholeDuration;
|
|
170
|
+
var scaledEnd = endPoint / wholeDuration;
|
|
171
|
+
scaledSegments.push({ scaledStart: scaledStart, scaledEnd: scaledEnd, info: info });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return scaledSegments;
|
|
175
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export default class BufferSizeGraph {
|
|
2
|
+
private _history;
|
|
3
|
+
/** Canvas that will contain the buffer size graph itself. */
|
|
4
|
+
private readonly _canvasElt;
|
|
5
|
+
private readonly _canvasCtxt;
|
|
6
|
+
constructor(canvasElt: HTMLCanvasElement);
|
|
7
|
+
pushBufferSize(bufferSize: number): void;
|
|
8
|
+
clear(): void;
|
|
9
|
+
reRender(width: number, height: number): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maximum history of the buffer size that will be displayed, in milliseconds.
|
|
3
|
+
* For example, a value of `3000` indicates that we will just show at most the
|
|
4
|
+
* buffer size evolution during the last 3 seconds.
|
|
5
|
+
*/
|
|
6
|
+
var TIME_SAMPLES_MS = 30000;
|
|
7
|
+
/**
|
|
8
|
+
* At minimum, that value will be taken in the chart as a maximum buffer size,
|
|
9
|
+
* in seconds.
|
|
10
|
+
* If samples go higher than this size, the chart will adapt automatically to
|
|
11
|
+
* a higher scale.
|
|
12
|
+
* However if values go below that value, the chart won't scale down more than
|
|
13
|
+
* this.
|
|
14
|
+
*/
|
|
15
|
+
var MINIMUM_MAX_BUFFER_SIZE = 20;
|
|
16
|
+
var BufferSizeGraph = /** @class */ (function () {
|
|
17
|
+
function BufferSizeGraph(canvasElt) {
|
|
18
|
+
this._canvasElt = canvasElt;
|
|
19
|
+
this._canvasCtxt = this._canvasElt.getContext("2d");
|
|
20
|
+
this._history = [];
|
|
21
|
+
}
|
|
22
|
+
BufferSizeGraph.prototype.pushBufferSize = function (bufferSize) {
|
|
23
|
+
var now = performance.now();
|
|
24
|
+
this._history.push({ timestamp: now, bufferSize: bufferSize });
|
|
25
|
+
if (this._history.length > 0) {
|
|
26
|
+
var minimumTime = now - TIME_SAMPLES_MS;
|
|
27
|
+
var i = void 0;
|
|
28
|
+
for (i = this._history.length - 1; i >= 1; i--) {
|
|
29
|
+
if (this._history[i].timestamp <= minimumTime) {
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
this._history = this._history.slice(i);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
this._history = [];
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
BufferSizeGraph.prototype.clear = function () {
|
|
40
|
+
if (this._canvasCtxt !== null) {
|
|
41
|
+
this._canvasCtxt.clearRect(0, 0, this._canvasElt.width, this._canvasElt.height);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
BufferSizeGraph.prototype.reRender = function (width, height) {
|
|
45
|
+
this._canvasElt.style.width = "".concat(width, "px");
|
|
46
|
+
this._canvasElt.style.height = "".concat(height, "px");
|
|
47
|
+
this._canvasElt.width = width;
|
|
48
|
+
this._canvasElt.height = height;
|
|
49
|
+
this.clear();
|
|
50
|
+
var history = this._history;
|
|
51
|
+
var canvasCtx = this._canvasCtxt;
|
|
52
|
+
if (history.length === 0) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
var currentMaxSize = getNewMaxBufferSize();
|
|
56
|
+
var minDate = history[0].timestamp;
|
|
57
|
+
var gridHeight = height / currentMaxSize;
|
|
58
|
+
var gridWidth = width / TIME_SAMPLES_MS;
|
|
59
|
+
drawData();
|
|
60
|
+
/**
|
|
61
|
+
* Get more appropriate maximum buffer size to put on top of the graph
|
|
62
|
+
* according to current history.
|
|
63
|
+
*/
|
|
64
|
+
function getNewMaxBufferSize() {
|
|
65
|
+
var maxPoint = Math.max.apply(Math, history.map(function (d) { return d.bufferSize; }));
|
|
66
|
+
return Math.max(maxPoint + 5, MINIMUM_MAX_BUFFER_SIZE);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Draw all data contained in `history` in the canvas given.
|
|
70
|
+
*/
|
|
71
|
+
function drawData() {
|
|
72
|
+
if (canvasCtx === null) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
canvasCtx.beginPath();
|
|
76
|
+
canvasCtx.fillStyle = "rgb(200, 100, 200)";
|
|
77
|
+
for (var i = 1; i < history.length; i++) {
|
|
78
|
+
var diff = dateToX(history[i].timestamp) -
|
|
79
|
+
dateToX(history[i - 1].timestamp);
|
|
80
|
+
var y = height - bufferValueToHeight(history[i].bufferSize);
|
|
81
|
+
canvasCtx.fillRect(dateToX(history[i - 1].timestamp), y, diff, height);
|
|
82
|
+
}
|
|
83
|
+
canvasCtx.stroke();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Convert a value of a given data point, to a u coordinate in the canvas.
|
|
87
|
+
* @param {number} bufferVal - Value to convert
|
|
88
|
+
* @returns {number} - y coordinate
|
|
89
|
+
*/
|
|
90
|
+
function bufferValueToHeight(bufferVal) {
|
|
91
|
+
return height - (currentMaxSize - bufferVal) * gridHeight;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Convert a date of a given data point, to a x coordinate in the canvas.
|
|
95
|
+
* @param {number} date - Date to convert, in milliseconds
|
|
96
|
+
* @returns {number} - x coordinate
|
|
97
|
+
*/
|
|
98
|
+
function dateToX(date) {
|
|
99
|
+
return (date - minDate) * gridWidth;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return BufferSizeGraph;
|
|
103
|
+
}());
|
|
104
|
+
export default BufferSizeGraph;
|