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.
Files changed (169) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/CONTRIBUTING.md +48 -168
  3. package/FILES.md +40 -92
  4. package/VERSION +1 -1
  5. package/dist/_esm5.processed/compat/browser_detection.d.ts +3 -1
  6. package/dist/_esm5.processed/compat/browser_detection.js +7 -2
  7. package/dist/_esm5.processed/compat/eme/load_session.js +1 -1
  8. package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.d.ts +21 -0
  9. package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.js +26 -0
  10. package/dist/_esm5.processed/config.d.ts +2 -0
  11. package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +5 -4
  12. package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.d.ts +18 -1
  13. package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.js +106 -25
  14. package/dist/_esm5.processed/core/adaptive/guess_based_chooser.js +6 -6
  15. package/dist/_esm5.processed/core/adaptive/network_analyzer.js +8 -5
  16. package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.d.ts +19 -1
  17. package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.js +1 -1
  18. package/dist/_esm5.processed/core/api/debug/render.js +1 -1
  19. package/dist/_esm5.processed/core/api/playback_observer.js +1 -0
  20. package/dist/_esm5.processed/core/api/public_api.d.ts +54 -1
  21. package/dist/_esm5.processed/core/api/public_api.js +232 -35
  22. package/dist/_esm5.processed/core/api/track_management/media_element_tracks_store.js +10 -1
  23. package/dist/_esm5.processed/core/api/track_management/track_dispatcher.d.ts +13 -1
  24. package/dist/_esm5.processed/core/api/track_management/track_dispatcher.js +30 -15
  25. package/dist/_esm5.processed/core/api/track_management/tracks_store.d.ts +3 -1
  26. package/dist/_esm5.processed/core/api/track_management/tracks_store.js +67 -152
  27. package/dist/_esm5.processed/core/api/utils.d.ts +10 -0
  28. package/dist/_esm5.processed/core/api/utils.js +20 -0
  29. package/dist/_esm5.processed/core/decrypt/session_events_listener.js +7 -1
  30. package/dist/_esm5.processed/core/decrypt/utils/clean_old_loaded_sessions.js +2 -0
  31. package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +5 -1
  32. package/dist/_esm5.processed/core/init/directfile_content_initializer.js +1 -1
  33. package/dist/_esm5.processed/core/init/media_source_content_initializer.js +47 -10
  34. package/dist/_esm5.processed/core/init/types.d.ts +9 -1
  35. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.d.ts +28 -1
  36. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.js +22 -9
  37. package/dist/_esm5.processed/core/init/utils/media_source_duration_updater.d.ts +58 -0
  38. package/dist/_esm5.processed/core/init/utils/{media_duration_updater.js → media_source_duration_updater.js} +84 -87
  39. package/dist/_esm5.processed/core/init/utils/rebuffering_controller.d.ts +36 -2
  40. package/dist/_esm5.processed/core/init/utils/rebuffering_controller.js +82 -2
  41. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.d.ts +18 -7
  42. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +31 -40
  43. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.d.ts +8 -0
  44. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +12 -0
  45. package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.d.ts +8 -0
  46. package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.js +12 -0
  47. package/dist/_esm5.processed/core/segment_buffers/implementations/types.d.ts +11 -4
  48. package/dist/_esm5.processed/core/segment_buffers/index.d.ts +2 -2
  49. package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.d.ts +47 -0
  50. package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.js +70 -0
  51. package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +15 -8
  52. package/dist/_esm5.processed/core/stream/period/period_stream.js +1 -1
  53. package/dist/_esm5.processed/core/stream/representation/representation_stream.js +22 -13
  54. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.d.ts +4 -2
  55. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.js +2 -2
  56. package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.d.ts +3 -2
  57. package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.js +8 -8
  58. package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.d.ts +2 -2
  59. package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.js +2 -3
  60. package/dist/_esm5.processed/default_config.d.ts +25 -0
  61. package/dist/_esm5.processed/default_config.js +27 -2
  62. package/dist/_esm5.processed/errors/index.d.ts +2 -2
  63. package/dist/_esm5.processed/errors/media_error.d.ts +23 -1
  64. package/dist/_esm5.processed/errors/media_error.js +18 -5
  65. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.d.ts +1 -1
  66. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.js +8 -7
  67. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +17 -9
  68. package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/index.js +0 -2
  69. package/dist/_esm5.processed/manifest/adaptation.d.ts +21 -2
  70. package/dist/_esm5.processed/manifest/adaptation.js +76 -1
  71. package/dist/_esm5.processed/manifest/manifest.js +1 -1
  72. package/dist/_esm5.processed/manifest/period.js +2 -2
  73. package/dist/_esm5.processed/manifest/representation.d.ts +33 -2
  74. package/dist/_esm5.processed/manifest/representation.js +21 -0
  75. package/dist/_esm5.processed/manifest/utils.js +1 -3
  76. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.d.ts +1 -1
  77. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.js +1 -1
  78. package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.js +1 -0
  79. package/dist/_esm5.processed/public_types.d.ts +13 -3
  80. package/dist/_esm5.processed/tools/TextTrackRenderer/text_track_renderer.js +1 -1
  81. package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.d.ts +4 -6
  82. package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.js +4 -6
  83. package/dist/_esm5.processed/utils/is_null_or_undefined.d.ts +1 -1
  84. package/dist/_esm5.processed/utils/is_null_or_undefined.js +1 -1
  85. package/dist/mpd-parser.wasm +0 -0
  86. package/dist/rx-player.js +4709 -4218
  87. package/dist/rx-player.min.js +1 -1
  88. package/package.json +42 -36
  89. package/scripts/build/generate_build.js +1 -1
  90. package/scripts/fast_demo_build.js +4 -3
  91. package/scripts/generate_full_demo.js +1 -1
  92. package/sonar-project.properties +1 -1
  93. package/src/compat/browser_detection.ts +7 -1
  94. package/src/compat/eme/load_session.ts +1 -1
  95. package/src/compat/has_issues_with_high_media_source_duration.ts +27 -0
  96. package/src/core/adaptive/__tests__/buffer_based_chooser.test.ts +147 -48
  97. package/src/core/adaptive/adaptive_representation_selector.ts +7 -4
  98. package/src/core/adaptive/buffer_based_chooser.ts +144 -26
  99. package/src/core/adaptive/guess_based_chooser.ts +9 -8
  100. package/src/core/adaptive/network_analyzer.ts +9 -4
  101. package/src/core/adaptive/utils/representation_score_calculator.ts +22 -2
  102. package/src/core/api/debug/render.ts +1 -1
  103. package/src/core/api/playback_observer.ts +1 -0
  104. package/src/core/api/public_api.ts +277 -44
  105. package/src/core/api/track_management/media_element_tracks_store.ts +17 -8
  106. package/src/core/api/track_management/track_dispatcher.ts +37 -14
  107. package/src/core/api/track_management/tracks_store.ts +77 -167
  108. package/src/core/api/utils.ts +26 -0
  109. package/src/core/decrypt/session_events_listener.ts +6 -1
  110. package/src/core/decrypt/utils/clean_old_loaded_sessions.ts +2 -1
  111. package/src/core/decrypt/utils/loaded_sessions_store.ts +8 -1
  112. package/src/core/init/directfile_content_initializer.ts +1 -0
  113. package/src/core/init/media_source_content_initializer.ts +52 -9
  114. package/src/core/init/types.ts +9 -1
  115. package/src/core/init/utils/content_time_boundaries_observer.ts +46 -10
  116. package/src/core/init/utils/{media_duration_updater.ts → media_source_duration_updater.ts} +100 -112
  117. package/src/core/init/utils/rebuffering_controller.ts +114 -3
  118. package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +56 -55
  119. package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +16 -0
  120. package/src/core/segment_buffers/implementations/text/native/native_text_segment_buffer.ts +16 -0
  121. package/src/core/segment_buffers/implementations/types.ts +16 -4
  122. package/src/core/segment_buffers/index.ts +2 -0
  123. package/src/core/stream/adaptation/utils/create_representation_estimator.ts +114 -0
  124. package/src/core/stream/orchestrator/stream_orchestrator.ts +16 -8
  125. package/src/core/stream/period/period_stream.ts +2 -1
  126. package/src/core/stream/representation/representation_stream.ts +34 -22
  127. package/src/core/stream/representation/utils/append_segment_to_buffer.ts +8 -3
  128. package/src/core/stream/representation/utils/push_init_segment.ts +11 -6
  129. package/src/core/stream/representation/utils/push_media_segment.ts +3 -3
  130. package/src/default_config.ts +29 -2
  131. package/src/errors/__tests__/media_error.test.ts +6 -6
  132. package/src/errors/index.ts +4 -1
  133. package/src/errors/media_error.ts +67 -1
  134. package/src/experimental/tools/VideoThumbnailLoader/load_and_push_segment.ts +10 -7
  135. package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +17 -6
  136. package/src/experimental/tools/mediaCapabilitiesProber/index.ts +0 -4
  137. package/src/manifest/__tests__/manifest.test.ts +7 -7
  138. package/src/manifest/__tests__/period.test.ts +90 -45
  139. package/src/manifest/adaptation.ts +89 -1
  140. package/src/manifest/manifest.ts +1 -1
  141. package/src/manifest/period.ts +4 -2
  142. package/src/manifest/representation.ts +67 -1
  143. package/src/manifest/utils.ts +1 -3
  144. package/src/parsers/manifest/dash/js-parser/parse_from_document.ts +1 -1
  145. package/src/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.ts +1 -0
  146. package/src/parsers/texttracks/ttml/parse_ttml.ts +1 -1
  147. package/src/public_types.ts +16 -1
  148. package/src/tools/TextTrackRenderer/text_track_renderer.ts +1 -1
  149. package/src/transports/smooth/isobmff/create_boxes.ts +4 -6
  150. package/src/typings/globals.d.ts +20 -20
  151. package/src/utils/is_null_or_undefined.ts +1 -1
  152. package/dist/_esm5.processed/core/init/utils/media_duration_updater.d.ts +0 -56
  153. package/scripts/doc-generator/construct_table_of_contents.js +0 -76
  154. package/scripts/doc-generator/convert_MD_to_HMTL.js +0 -26
  155. package/scripts/doc-generator/create_documentation.js +0 -331
  156. package/scripts/doc-generator/create_documentation_page.js +0 -209
  157. package/scripts/doc-generator/create_page.js +0 -210
  158. package/scripts/doc-generator/generate_header_html.js +0 -147
  159. package/scripts/doc-generator/generate_page_html.js +0 -115
  160. package/scripts/doc-generator/generate_page_list_html.js +0 -92
  161. package/scripts/doc-generator/generate_sidebar_html.js +0 -85
  162. package/scripts/doc-generator/get_search_data_for_content.js +0 -137
  163. package/scripts/doc-generator/index.js +0 -34
  164. package/scripts/doc-generator/parse_doc_configs.js +0 -327
  165. package/scripts/doc-generator/scripts/lunr.js +0 -10
  166. package/scripts/doc-generator/scripts/script.js +0 -451
  167. package/scripts/doc-generator/styles/code.css +0 -99
  168. package/scripts/doc-generator/styles/style.css +0 -835
  169. 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
- const currentBitrateIndex = arrayFindIndex(bitrates, b => b === currentBitrate);
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 != null) {
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
- if (scaledScore != null && scaledScore > 1) {
74
- const currentBufferLevel = bufferLevels[currentBitrateIndex];
75
- const nextIndex = (() => {
76
- for (let i = currentBitrateIndex + 1; i < bufferLevels.length; i++) {
77
- if (bufferLevels[i] > currentBufferLevel) {
78
- return i;
79
- }
80
- }
81
- })();
82
- if (nextIndex != null) {
83
- const nextBufferLevel = bufferLevels[nextIndex];
84
- if (bufferGap >= nextBufferLevel) {
85
- return bitrates[nextIndex];
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
- if (scaledScore == null || scaledScore < 1.15) {
91
- const currentBufferLevel = bufferLevels[currentBitrateIndex];
92
- if (bufferGap < currentBufferLevel) {
93
- for (let i = currentBitrateIndex - 1; i >= 0; i--) {
94
- if (bitrates[i] < currentBitrate) {
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
- return currentBitrate;
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? : number | undefined;
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
- [score, scoreConfidenceLevel] : [number, ScoreConfidenceLevel]
182
+ { score, confidenceLevel } : IRepresentationMaintainabilityScore
182
183
  ) : boolean {
183
184
  return isFinite(bufferGap) && bufferGap >= 2.5 &&
184
185
  performance.now() > this._blockGuessesUntil &&
185
- scoreConfidenceLevel === ScoreConfidenceLevel.HIGH &&
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 : [number, ScoreConfidenceLevel] | undefined,
201
+ scoreData : IRepresentationMaintainabilityScore | undefined,
201
202
  bufferGap : number,
202
203
  requests : IRequestInfo[]
203
204
  ) : boolean {
204
- if (scoreData !== undefined && scoreData[0] < 1.01) {
205
+ if (scoreData !== undefined && scoreData.score < 1.01) {
205
206
  return true;
206
- } else if ((scoreData === undefined || scoreData[0] < 1.2) && bufferGap < 0.6) {
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 : [number, ScoreConfidenceLevel] | undefined
237
+ scoreData : IRepresentationMaintainabilityScore | undefined
237
238
  ) : boolean {
238
239
  if (scoreData !== undefined &&
239
- scoreData[1] === ScoreConfidenceLevel.HIGH &&
240
- scoreData[0] > 1.5)
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 > 2000) {
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 === currentRepresentation.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
- ) : [number, ScoreConfidenceLevel] | undefined {
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 [estimate, confidenceLevel];
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";
@@ -167,6 +167,7 @@ export default class PlaybackObserver {
167
167
  */
168
168
  public setCurrentTime(time: number) : void {
169
169
  this._internalSeeksIncoming.push(time);
170
+ log.info("API: Seeking internally", time);
170
171
  this._mediaElement.currentTime = time;
171
172
  }
172
173