rx-player 4.0.0-beta.1 → 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/CHANGELOG.md +40 -0
- package/CONTRIBUTING.md +48 -168
- package/FILES.md +40 -92
- package/VERSION +1 -1
- package/dist/_esm5.processed/compat/browser_detection.d.ts +3 -1
- package/dist/_esm5.processed/compat/browser_detection.js +7 -2
- package/dist/_esm5.processed/compat/eme/load_session.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 +2 -0
- package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +5 -4
- 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/render.js +1 -1
- package/dist/_esm5.processed/core/api/playback_observer.js +1 -0
- package/dist/_esm5.processed/core/api/public_api.d.ts +54 -1
- package/dist/_esm5.processed/core/api/public_api.js +232 -35
- 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 +20 -0
- package/dist/_esm5.processed/core/decrypt/session_events_listener.js +7 -1
- 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/init/directfile_content_initializer.js +1 -1
- package/dist/_esm5.processed/core/init/media_source_content_initializer.js +47 -10
- 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 +22 -9
- 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} +84 -87
- package/dist/_esm5.processed/core/init/utils/rebuffering_controller.d.ts +36 -2
- package/dist/_esm5.processed/core/init/utils/rebuffering_controller.js +82 -2
- 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 +31 -40
- 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 +12 -0
- 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/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 +15 -8
- package/dist/_esm5.processed/core/stream/period/period_stream.js +1 -1
- package/dist/_esm5.processed/core/stream/representation/representation_stream.js +22 -13
- 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 +2 -2
- 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/default_config.d.ts +25 -0
- package/dist/_esm5.processed/default_config.js +27 -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/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/video_thumbnail_loader.js +17 -9
- package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/index.js +0 -2
- package/dist/_esm5.processed/manifest/adaptation.d.ts +21 -2
- package/dist/_esm5.processed/manifest/adaptation.js +76 -1
- package/dist/_esm5.processed/manifest/manifest.js +1 -1
- 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 +21 -0
- package/dist/_esm5.processed/manifest/utils.js +1 -3
- 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/smooth/isobmff/create_boxes.d.ts +4 -6
- package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.js +4 -6
- 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/mpd-parser.wasm +0 -0
- package/dist/rx-player.js +4709 -4218
- package/dist/rx-player.min.js +1 -1
- package/package.json +42 -36
- package/scripts/build/generate_build.js +1 -1
- package/scripts/fast_demo_build.js +4 -3
- package/scripts/generate_full_demo.js +1 -1
- package/sonar-project.properties +1 -1
- package/src/compat/browser_detection.ts +7 -1
- package/src/compat/eme/load_session.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 +7 -4
- 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/render.ts +1 -1
- package/src/core/api/playback_observer.ts +1 -0
- package/src/core/api/public_api.ts +277 -44
- 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 +26 -0
- package/src/core/decrypt/session_events_listener.ts +6 -1
- 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/init/directfile_content_initializer.ts +1 -0
- package/src/core/init/media_source_content_initializer.ts +52 -9
- package/src/core/init/types.ts +9 -1
- package/src/core/init/utils/content_time_boundaries_observer.ts +46 -10
- package/src/core/init/utils/{media_duration_updater.ts → media_source_duration_updater.ts} +100 -112
- package/src/core/init/utils/rebuffering_controller.ts +114 -3
- package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +56 -55
- package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +16 -0
- 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/stream/adaptation/utils/create_representation_estimator.ts +114 -0
- package/src/core/stream/orchestrator/stream_orchestrator.ts +16 -8
- package/src/core/stream/period/period_stream.ts +2 -1
- package/src/core/stream/representation/representation_stream.ts +34 -22
- package/src/core/stream/representation/utils/append_segment_to_buffer.ts +8 -3
- 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/default_config.ts +29 -2
- 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/tools/VideoThumbnailLoader/load_and_push_segment.ts +10 -7
- package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +17 -6
- package/src/experimental/tools/mediaCapabilitiesProber/index.ts +0 -4
- package/src/manifest/__tests__/manifest.test.ts +7 -7
- package/src/manifest/__tests__/period.test.ts +90 -45
- package/src/manifest/adaptation.ts +89 -1
- package/src/manifest/manifest.ts +1 -1
- package/src/manifest/period.ts +4 -2
- package/src/manifest/representation.ts +67 -1
- package/src/manifest/utils.ts +1 -3
- 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/smooth/isobmff/create_boxes.ts +4 -6
- package/src/typings/globals.d.ts +20 -20
- package/src/utils/is_null_or_undefined.ts +1 -1
- package/dist/_esm5.processed/core/init/utils/media_duration_updater.d.ts +0 -56
- 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
|
@@ -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
|
}
|
|
@@ -162,6 +162,13 @@ function estimateStarvationModeBitrate(
|
|
|
162
162
|
|
|
163
163
|
const concernedRequest = concernedRequests[0];
|
|
164
164
|
const now = performance.now();
|
|
165
|
+
|
|
166
|
+
let minimumRequestTime = concernedRequest.content.segment.duration * 1.5;
|
|
167
|
+
minimumRequestTime = Math.min(minimumRequestTime, 3000);
|
|
168
|
+
minimumRequestTime = Math.max(minimumRequestTime, 12000);
|
|
169
|
+
if (now - concernedRequest.requestTimestamp < minimumRequestTime) {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
165
172
|
const lastProgressEvent = concernedRequest.progress.length > 0 ?
|
|
166
173
|
concernedRequest.progress[concernedRequest.progress.length - 1] :
|
|
167
174
|
undefined;
|
|
@@ -178,7 +185,7 @@ function estimateStarvationModeBitrate(
|
|
|
178
185
|
// Calculate estimated time spent rebuffering if we continue doing that request.
|
|
179
186
|
const expectedRebufferingTime = remainingTime -
|
|
180
187
|
(realBufferGap / speed);
|
|
181
|
-
if (expectedRebufferingTime >
|
|
188
|
+
if (expectedRebufferingTime > 2500) {
|
|
182
189
|
return bandwidthEstimate;
|
|
183
190
|
}
|
|
184
191
|
}
|
|
@@ -402,10 +409,8 @@ export default class NetworkAnalyzer {
|
|
|
402
409
|
) : boolean {
|
|
403
410
|
if (currentRepresentation === null) {
|
|
404
411
|
return true;
|
|
405
|
-
} else if (bitrate
|
|
412
|
+
} else if (bitrate >= currentRepresentation.bitrate) {
|
|
406
413
|
return false;
|
|
407
|
-
} else if (bitrate > currentRepresentation.bitrate) {
|
|
408
|
-
return !this._inStarvationMode;
|
|
409
414
|
}
|
|
410
415
|
return shouldDirectlySwitchToLowBitrate(playbackInfo,
|
|
411
416
|
currentRequests,
|
|
@@ -18,6 +18,26 @@ import log from "../../../log";
|
|
|
18
18
|
import { Representation } from "../../../manifest";
|
|
19
19
|
import EWMA from "./ewma";
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Object representing a maintainability score as calculated by the
|
|
23
|
+
* `RepresentationScoreCalculator`.
|
|
24
|
+
*/
|
|
25
|
+
export interface IRepresentationMaintainabilityScore {
|
|
26
|
+
/**
|
|
27
|
+
* Weighted mean of dividing the loaded segment's duration by the time to make
|
|
28
|
+
* their request.
|
|
29
|
+
*/
|
|
30
|
+
score : number;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The confidence we have on the calculated `score` in reflecting a useful
|
|
34
|
+
* maintainability hint for the concerned Representation.
|
|
35
|
+
*
|
|
36
|
+
* Basically, the more segments have been loaded, the higher the confidence.
|
|
37
|
+
*/
|
|
38
|
+
confidenceLevel: ScoreConfidenceLevel;
|
|
39
|
+
}
|
|
40
|
+
|
|
21
41
|
/**
|
|
22
42
|
* Calculate the "maintainability score" of a given Representation:
|
|
23
43
|
* - A score higher than 1 means that the Representation can theorically
|
|
@@ -107,7 +127,7 @@ export default class RepresentationScoreCalculator {
|
|
|
107
127
|
*/
|
|
108
128
|
public getEstimate(
|
|
109
129
|
representation : Representation
|
|
110
|
-
) :
|
|
130
|
+
) : IRepresentationMaintainabilityScore | undefined {
|
|
111
131
|
if (this._currentRepresentationData === null ||
|
|
112
132
|
this._currentRepresentationData.representation.id !== representation.id)
|
|
113
133
|
{
|
|
@@ -119,7 +139,7 @@ export default class RepresentationScoreCalculator {
|
|
|
119
139
|
loadedDuration >= 10 ? ScoreConfidenceLevel.HIGH :
|
|
120
140
|
ScoreConfidenceLevel.LOW;
|
|
121
141
|
|
|
122
|
-
return
|
|
142
|
+
return { score: estimate, confidenceLevel };
|
|
123
143
|
}
|
|
124
144
|
|
|
125
145
|
/**
|
|
@@ -29,7 +29,7 @@ export default function renderDebugElement(
|
|
|
29
29
|
debugWrapperElt.style.backgroundColor = "#00000099";
|
|
30
30
|
debugWrapperElt.style.padding = "7px";
|
|
31
31
|
debugWrapperElt.style.fontSize = "13px";
|
|
32
|
-
debugWrapperElt.style.fontFamily = "mono";
|
|
32
|
+
debugWrapperElt.style.fontFamily = "mono, monospace";
|
|
33
33
|
debugWrapperElt.style.color = "white";
|
|
34
34
|
debugWrapperElt.style.display = "inline-block";
|
|
35
35
|
debugWrapperElt.style.bottom = "0px";
|