rx-player 3.30.1-dev.2023032800 → 3.31.0-dev.2023052200

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 (96) hide show
  1. package/CHANGELOG.md +14 -2
  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/has_issues_with_high_media_source_duration.d.ts +21 -0
  8. package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.js +26 -0
  9. package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +1 -2
  10. package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.d.ts +18 -1
  11. package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.js +105 -24
  12. package/dist/_esm5.processed/core/adaptive/guess_based_chooser.js +6 -6
  13. package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.d.ts +19 -1
  14. package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.js +1 -1
  15. package/dist/_esm5.processed/core/api/debug/render.js +1 -1
  16. package/dist/_esm5.processed/core/api/public_api.js +2 -2
  17. package/dist/_esm5.processed/core/api/tracks_management/media_element_track_choice_manager.js +10 -1
  18. package/dist/_esm5.processed/core/api/tracks_management/track_choice_manager.js +20 -117
  19. package/dist/_esm5.processed/core/init/media_source_content_initializer.js +28 -3
  20. package/dist/_esm5.processed/core/init/utils/media_source_duration_updater.d.ts +2 -2
  21. package/dist/_esm5.processed/core/init/utils/media_source_duration_updater.js +29 -18
  22. package/dist/_esm5.processed/core/segment_buffers/index.d.ts +2 -2
  23. package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.js +1 -1
  24. package/dist/_esm5.processed/core/stream/period/period_stream.js +1 -1
  25. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.d.ts +4 -2
  26. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.js +2 -2
  27. package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.js +6 -2
  28. package/dist/_esm5.processed/errors/index.d.ts +2 -2
  29. package/dist/_esm5.processed/errors/media_error.d.ts +23 -1
  30. package/dist/_esm5.processed/errors/media_error.js +18 -5
  31. package/dist/_esm5.processed/manifest/adaptation.d.ts +17 -2
  32. package/dist/_esm5.processed/manifest/adaptation.js +67 -1
  33. package/dist/_esm5.processed/manifest/manifest.d.ts +1 -1
  34. package/dist/_esm5.processed/manifest/manifest.js +3 -3
  35. package/dist/_esm5.processed/manifest/period.js +1 -1
  36. package/dist/_esm5.processed/manifest/representation.d.ts +11 -1
  37. package/dist/_esm5.processed/manifest/representation.js +16 -0
  38. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.d.ts +1 -1
  39. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.js +1 -1
  40. package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.js +1 -0
  41. package/dist/_esm5.processed/public_types.d.ts +6 -5
  42. package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.d.ts +4 -6
  43. package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.js +4 -6
  44. package/dist/rx-player.js +3086 -3024
  45. package/dist/rx-player.min.js +1 -1
  46. package/package.json +25 -26
  47. package/sonar-project.properties +1 -1
  48. package/src/compat/browser_detection.ts +7 -1
  49. package/src/compat/has_issues_with_high_media_source_duration.ts +27 -0
  50. package/src/core/adaptive/__tests__/buffer_based_chooser.test.ts +147 -48
  51. package/src/core/adaptive/adaptive_representation_selector.ts +1 -2
  52. package/src/core/adaptive/buffer_based_chooser.ts +143 -25
  53. package/src/core/adaptive/guess_based_chooser.ts +9 -8
  54. package/src/core/adaptive/utils/representation_score_calculator.ts +22 -2
  55. package/src/core/api/debug/render.ts +1 -1
  56. package/src/core/api/public_api.ts +2 -2
  57. package/src/core/api/tracks_management/media_element_track_choice_manager.ts +17 -8
  58. package/src/core/api/tracks_management/track_choice_manager.ts +20 -132
  59. package/src/core/init/media_source_content_initializer.ts +32 -4
  60. package/src/core/init/utils/media_source_duration_updater.ts +31 -19
  61. package/src/core/segment_buffers/index.ts +2 -0
  62. package/src/core/stream/adaptation/utils/create_representation_estimator.ts +2 -1
  63. package/src/core/stream/period/period_stream.ts +2 -1
  64. package/src/core/stream/representation/utils/append_segment_to_buffer.ts +8 -3
  65. package/src/core/stream/representation/utils/push_init_segment.ts +7 -1
  66. package/src/errors/__tests__/media_error.test.ts +6 -6
  67. package/src/errors/index.ts +4 -1
  68. package/src/errors/media_error.ts +67 -1
  69. package/src/manifest/__tests__/period.test.ts +90 -45
  70. package/src/manifest/adaptation.ts +77 -2
  71. package/src/manifest/manifest.ts +5 -3
  72. package/src/manifest/period.ts +2 -1
  73. package/src/manifest/representation.ts +23 -1
  74. package/src/parsers/manifest/dash/js-parser/parse_from_document.ts +1 -1
  75. package/src/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.ts +1 -0
  76. package/src/parsers/texttracks/ttml/parse_ttml.ts +1 -1
  77. package/src/public_types.ts +8 -3
  78. package/src/transports/smooth/isobmff/create_boxes.ts +4 -6
  79. package/src/typings/globals.d.ts +21 -21
  80. package/scripts/doc-generator/construct_table_of_contents.js +0 -76
  81. package/scripts/doc-generator/convert_MD_to_HMTL.js +0 -26
  82. package/scripts/doc-generator/create_documentation.js +0 -331
  83. package/scripts/doc-generator/create_documentation_page.js +0 -209
  84. package/scripts/doc-generator/create_page.js +0 -210
  85. package/scripts/doc-generator/generate_header_html.js +0 -147
  86. package/scripts/doc-generator/generate_page_html.js +0 -115
  87. package/scripts/doc-generator/generate_page_list_html.js +0 -92
  88. package/scripts/doc-generator/generate_sidebar_html.js +0 -85
  89. package/scripts/doc-generator/get_search_data_for_content.js +0 -137
  90. package/scripts/doc-generator/index.js +0 -34
  91. package/scripts/doc-generator/parse_doc_configs.js +0 -327
  92. package/scripts/doc-generator/scripts/lunr.js +0 -10
  93. package/scripts/doc-generator/scripts/script.js +0 -451
  94. package/scripts/doc-generator/styles/code.css +0 -99
  95. package/scripts/doc-generator/styles/style.css +0 -835
  96. package/scripts/doc-generator/utils.js +0 -74
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.30.1-dev.2023032800
1
+ 3.31.0-dev.2023052200
@@ -37,4 +37,6 @@ declare let isWebOs2021: boolean;
37
37
  declare let isWebOs2022: boolean;
38
38
  /** `true` for Panasonic devices. */
39
39
  declare let isPanasonic: boolean;
40
- export { isEdgeChromium, isIE11, isIEOrEdge, isFirefox, isPanasonic, isSafariDesktop, isSafariMobile, isSamsungBrowser, isTizen, isWebOs, isWebOs2021, isWebOs2022, };
40
+ /** `true` for the PlayStation 5 game console. */
41
+ declare let isPlayStation5: boolean;
42
+ export { isEdgeChromium, isIE11, isIEOrEdge, isFirefox, isPanasonic, isPlayStation5, isSafariDesktop, isSafariMobile, isSamsungBrowser, isTizen, isWebOs, isWebOs2021, isWebOs2022, };
@@ -38,6 +38,8 @@ var isWebOs2021 = false;
38
38
  var isWebOs2022 = false;
39
39
  /** `true` for Panasonic devices. */
40
40
  var isPanasonic = false;
41
+ /** `true` for the PlayStation 5 game console. */
42
+ var isPlayStation5 = false;
41
43
  ((function findCurrentBrowser() {
42
44
  var _a, _b;
43
45
  if (isNode) {
@@ -74,7 +76,10 @@ var isPanasonic = false;
74
76
  if (/SamsungBrowser/.test(navigator.userAgent)) {
75
77
  isSamsungBrowser = true;
76
78
  }
77
- if (/Tizen/.test(navigator.userAgent)) {
79
+ if (navigator.userAgent.indexOf("PlayStation 5") !== -1) {
80
+ isPlayStation5 = true;
81
+ }
82
+ else if (/Tizen/.test(navigator.userAgent)) {
78
83
  isTizen = true;
79
84
  // Inspired form: http://webostv.developer.lge.com/discover/specifications/web-engine/
80
85
  // Note: even that page doesn't correspond to what we've actually seen in the
@@ -95,4 +100,4 @@ var isPanasonic = false;
95
100
  isPanasonic = true;
96
101
  }
97
102
  })());
98
- export { isEdgeChromium, isIE11, isIEOrEdge, isFirefox, isPanasonic, isSafariDesktop, isSafariMobile, isSamsungBrowser, isTizen, isWebOs, isWebOs2021, isWebOs2022, };
103
+ export { isEdgeChromium, isIE11, isIEOrEdge, isFirefox, isPanasonic, isPlayStation5, isSafariDesktop, isSafariMobile, isSamsungBrowser, isTizen, isWebOs, isWebOs2021, isWebOs2022, };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Some platforms have issues when the `MediaSource`'s `duration` property
3
+ * is set to a very high value (playback freezes) but not when setting it
4
+ * to `Infinity`, which is what the HTML spec as of now (2023-05-15) recommends
5
+ * for live contents.
6
+ *
7
+ * However setting the `MediaSource`'s `duration` property to `Infinity` seems
8
+ * more risky, considering all platforms we now support, than setting it at a
9
+ * relatively high ~2**32 value which is what we do generally.
10
+ *
11
+ * Moreover, setting it to `Infinity` require us to use another MSE API,
12
+ * `setLiveSeekableRange` to properly allow seeking. We're used to MSE issues so
13
+ * I'm not too confident of using another MSE API for all platforms directly.
14
+ *
15
+ * So this methods just return `true` based on a whitelist of platform for which
16
+ * it has been detected that high `duration` values cause issues but setting it
17
+ * to Infinity AND playing with `setLiveSeekableRange` does not.
18
+ *
19
+ * @returns {boolean}
20
+ */
21
+ export default function hasIssuesWithHighMediaSourceDuration(): boolean;
@@ -0,0 +1,26 @@
1
+ import { isPlayStation5 } from "./browser_detection";
2
+ /**
3
+ * Some platforms have issues when the `MediaSource`'s `duration` property
4
+ * is set to a very high value (playback freezes) but not when setting it
5
+ * to `Infinity`, which is what the HTML spec as of now (2023-05-15) recommends
6
+ * for live contents.
7
+ *
8
+ * However setting the `MediaSource`'s `duration` property to `Infinity` seems
9
+ * more risky, considering all platforms we now support, than setting it at a
10
+ * relatively high ~2**32 value which is what we do generally.
11
+ *
12
+ * Moreover, setting it to `Infinity` require us to use another MSE API,
13
+ * `setLiveSeekableRange` to properly allow seeking. We're used to MSE issues so
14
+ * I'm not too confident of using another MSE API for all platforms directly.
15
+ *
16
+ * So this methods just return `true` based on a whitelist of platform for which
17
+ * it has been detected that high `duration` values cause issues but setting it
18
+ * to Infinity AND playing with `setLiveSeekableRange` does not.
19
+ *
20
+ * @returns {boolean}
21
+ */
22
+ export default function hasIssuesWithHighMediaSourceDuration() {
23
+ // For now only seen on the Webkit present in the PlayStation 5, for which the
24
+ // alternative is known to work.
25
+ return isPlayStation5;
26
+ }
@@ -210,8 +210,7 @@ function getEstimateReference(_a, stopAllEstimates) {
210
210
  var timeRanges = val.buffered;
211
211
  var bufferGap = getLeftSizeOfRange(timeRanges, position.last);
212
212
  var representation = val.content.representation;
213
- var scoreData = scoreCalculator.getEstimate(representation);
214
- var currentScore = scoreData === null || scoreData === void 0 ? void 0 : scoreData[0];
213
+ var currentScore = scoreCalculator.getEstimate(representation);
215
214
  var currentBitrate = representation.bitrate;
216
215
  var observation = { bufferGap: bufferGap, currentBitrate: currentBitrate, currentScore: currentScore, speed: speed };
217
216
  currentBufferBasedEstimate = bufferBasedChooser.getEstimate(observation);
@@ -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?: number | undefined;
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 = arrayFindIndex(bitrates, function (b) { return b === currentBitrate; });
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
115
  if (currentScore !== undefined) {
60
- scaledScore = speed === 0 ? currentScore : (currentScore / speed);
116
+ scaledScore = speed === 0 ? currentScore.score : (currentScore.score / speed);
61
117
  }
62
- if (scaledScore !== undefined && scaledScore > 1) {
63
- var currentBufferLevel_1 = bufferLevels[currentBitrateIndex];
64
- var nextIndex = (function () {
65
- for (var i = currentBitrateIndex + 1; i < bufferLevels.length; i++) {
66
- if (bufferLevels[i] > currentBufferLevel_1) {
67
- return i;
68
- }
69
- }
70
- })();
71
- if (nextIndex !== undefined) {
72
- var nextBufferLevel = bufferLevels[nextIndex];
73
- if (bufferGap >= nextBufferLevel) {
74
- return bitrates[nextIndex];
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 (scaledScore === undefined || scaledScore < 1.15) {
79
- var currentBufferLevel = bufferLevels[currentBitrateIndex];
80
- if (bufferGap < currentBufferLevel) {
81
- for (var i = currentBitrateIndex - 1; i >= 0; i--) {
82
- if (bitrates[i] < currentBitrate) {
83
- return bitrates[i];
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
- return currentBitrate;
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[0], scoreConfidenceLevel = _a[1];
130
+ var score = _a.score, confidenceLevel = _a.confidenceLevel;
131
131
  return isFinite(bufferGap) && bufferGap >= 2.5 &&
132
132
  performance.now() > this._blockGuessesUntil &&
133
- scoreConfidenceLevel === 1 /* ScoreConfidenceLevel.HIGH */ &&
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[0] < 1.01) {
146
+ if (scoreData !== undefined && scoreData.score < 1.01) {
147
147
  return true;
148
148
  }
149
- else if ((scoreData === undefined || scoreData[0] < 1.2) && bufferGap < 0.6) {
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[1] === 1 /* ScoreConfidenceLevel.HIGH */ &&
179
- scoreData[0] > 1.5) {
178
+ scoreData.confidenceLevel === 1 /* ScoreConfidenceLevel.HIGH */ &&
179
+ scoreData.score > 1.5) {
180
180
  return true;
181
181
  }
182
182
  return incomingBestBitrate >= lastGuess.bitrate &&
@@ -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): [number, ScoreConfidenceLevel] | undefined;
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 [estimate, confidenceLevel];
99
+ return { score: estimate, confidenceLevel: confidenceLevel };
100
100
  };
101
101
  /**
102
102
  * Returns last Representation which had reached a score superior to 1.
@@ -21,7 +21,7 @@ export default function renderDebugElement(parentElt, instance, cancelSignal) {
21
21
  debugWrapperElt.style.backgroundColor = "#00000099";
22
22
  debugWrapperElt.style.padding = "7px";
23
23
  debugWrapperElt.style.fontSize = "13px";
24
- debugWrapperElt.style.fontFamily = "mono";
24
+ debugWrapperElt.style.fontFamily = "mono, monospace";
25
25
  debugWrapperElt.style.color = "white";
26
26
  debugWrapperElt.style.display = "inline-block";
27
27
  debugWrapperElt.style.bottom = "0px";
@@ -89,7 +89,7 @@ var Player = /** @class */ (function (_super) {
89
89
  // Workaround to support Firefox autoplay on FF 42.
90
90
  // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
91
91
  videoElement.preload = "auto";
92
- _this.version = /* PLAYER_VERSION */ "3.30.1-dev.2023032800";
92
+ _this.version = /* PLAYER_VERSION */ "3.31.0-dev.2023052200";
93
93
  _this.log = log;
94
94
  _this.state = "STOPPED";
95
95
  _this.videoElement = videoElement;
@@ -2340,5 +2340,5 @@ var Player = /** @class */ (function (_super) {
2340
2340
  };
2341
2341
  return Player;
2342
2342
  }(EventEmitter));
2343
- Player.version = /* PLAYER_VERSION */ "3.30.1-dev.2023032800";
2343
+ Player.version = /* PLAYER_VERSION */ "3.31.0-dev.2023052200";
2344
2344
  export default Player;
@@ -101,7 +101,14 @@ function createTextTracks(textTracks) {
101
101
  "_" +
102
102
  occurences.toString();
103
103
  languagesOccurences[language] = occurences + 1;
104
- var track = { language: textTrack.language, id: id, normalized: normalizeLanguage(textTrack.language),
104
+ // Safari seems to be indicating that the subtitles track is a forced
105
+ // subtitles track by setting the `kind` attribute to `"forced"`.
106
+ // As of now (2023-04-04), this is not standard.
107
+ // @see https://github.com/whatwg/html/issues/4472
108
+ var forced = textTrack.kind === "forced" ?
109
+ true :
110
+ undefined;
111
+ var track = { language: textTrack.language, forced: forced, label: textTrack.label, id: id, normalized: normalizeLanguage(textTrack.language),
105
112
  closedCaption: textTrack.kind === "captions" };
106
113
  newTextTracks.push({ track: track, nativeTrack: textTrack });
107
114
  }
@@ -337,6 +344,8 @@ var MediaElementTrackChoiceManager = /** @class */ (function (_super) {
337
344
  return this._textTracks.map(function (_a) {
338
345
  var track = _a.track, nativeTrack = _a.nativeTrack;
339
346
  return { id: track.id,
347
+ label: track.label,
348
+ forced: track.forced,
340
349
  language: track.language,
341
350
  normalized: track.normalized,
342
351
  closedCaption: track.closedCaption,
@@ -22,6 +22,7 @@ import arrayFind from "../../../utils/array_find";
22
22
  import arrayIncludes from "../../../utils/array_includes";
23
23
  import isNullOrUndefined from "../../../utils/is_null_or_undefined";
24
24
  import normalizeLanguage from "../../../utils/languages";
25
+ import objectAssign from "../../../utils/object_assign";
25
26
  import SortedList from "../../../utils/sorted_list";
26
27
  import takeFirstSet from "../../../utils/take_first_set";
27
28
  /**
@@ -426,18 +427,7 @@ var TrackChoiceManager = /** @class */ (function () {
426
427
  if (isNullOrUndefined(chosenTrack)) {
427
428
  return null;
428
429
  }
429
- var audioTrack = {
430
- language: takeFirstSet(chosenTrack.language, ""),
431
- normalized: takeFirstSet(chosenTrack.normalizedLanguage, ""),
432
- audioDescription: chosenTrack.isAudioDescription === true,
433
- id: chosenTrack.id,
434
- representations: chosenTrack.representations.map(parseAudioRepresentation),
435
- label: chosenTrack.label,
436
- };
437
- if (chosenTrack.isDub === true) {
438
- audioTrack.dub = true;
439
- }
440
- return audioTrack;
430
+ return chosenTrack.toAudioTrack();
441
431
  };
442
432
  /**
443
433
  * Returns an object describing the chosen text track for the given text
@@ -460,17 +450,7 @@ var TrackChoiceManager = /** @class */ (function () {
460
450
  if (isNullOrUndefined(chosenTextAdaptation)) {
461
451
  return null;
462
452
  }
463
- var formatted = {
464
- language: takeFirstSet(chosenTextAdaptation.language, ""),
465
- normalized: takeFirstSet(chosenTextAdaptation.normalizedLanguage, ""),
466
- closedCaption: chosenTextAdaptation.isClosedCaption === true,
467
- id: chosenTextAdaptation.id,
468
- label: chosenTextAdaptation.label,
469
- };
470
- if (chosenTextAdaptation.isForcedSubtitles !== undefined) {
471
- formatted.forced = chosenTextAdaptation.isForcedSubtitles;
472
- }
473
- return formatted;
453
+ return chosenTextAdaptation.toTextTrack();
474
454
  };
475
455
  /**
476
456
  * Returns an object describing the chosen video track for the given video
@@ -494,32 +474,7 @@ var TrackChoiceManager = /** @class */ (function () {
494
474
  return null;
495
475
  }
496
476
  var currAdaptation = chosenVideoAdaptation.adaptation;
497
- var trickModeTracks = currAdaptation.trickModeTracks !== undefined ?
498
- currAdaptation.trickModeTracks.map(function (trickModeAdaptation) {
499
- var representations = trickModeAdaptation.representations
500
- .map(parseVideoRepresentation);
501
- var trickMode = { id: trickModeAdaptation.id, representations: representations, isTrickModeTrack: true };
502
- if (trickModeAdaptation.isSignInterpreted === true) {
503
- trickMode.signInterpreted = true;
504
- }
505
- return trickMode;
506
- }) :
507
- undefined;
508
- var videoTrack = {
509
- id: currAdaptation.id,
510
- representations: currAdaptation.representations.map(parseVideoRepresentation),
511
- label: currAdaptation.label,
512
- };
513
- if (currAdaptation.isSignInterpreted === true) {
514
- videoTrack.signInterpreted = true;
515
- }
516
- if (currAdaptation.isTrickModeTrack === true) {
517
- videoTrack.isTrickModeTrack = true;
518
- }
519
- if (trickModeTracks !== undefined) {
520
- videoTrack.trickModeTracks = trickModeTracks;
521
- }
522
- return videoTrack;
477
+ return currAdaptation.toVideoTrack();
523
478
  };
524
479
  /**
525
480
  * Returns all available audio tracks for a given Period, as an array of
@@ -540,20 +495,9 @@ var TrackChoiceManager = /** @class */ (function () {
540
495
  null;
541
496
  return audioInfos.adaptations
542
497
  .map(function (adaptation) {
543
- var formatted = {
544
- language: takeFirstSet(adaptation.language, ""),
545
- normalized: takeFirstSet(adaptation.normalizedLanguage, ""),
546
- audioDescription: adaptation.isAudioDescription === true,
547
- id: adaptation.id,
548
- active: currentId === null ? false :
549
- currentId === adaptation.id,
550
- representations: adaptation.representations.map(parseAudioRepresentation),
551
- label: adaptation.label,
552
- };
553
- if (adaptation.isDub === true) {
554
- formatted.dub = true;
555
- }
556
- return formatted;
498
+ var active = currentId === null ? false :
499
+ currentId === adaptation.id;
500
+ return objectAssign(adaptation.toAudioTrack(), { active: active });
557
501
  });
558
502
  };
559
503
  /**
@@ -576,19 +520,9 @@ var TrackChoiceManager = /** @class */ (function () {
576
520
  null;
577
521
  return textInfos.adaptations
578
522
  .map(function (adaptation) {
579
- var formatted = {
580
- language: takeFirstSet(adaptation.language, ""),
581
- normalized: takeFirstSet(adaptation.normalizedLanguage, ""),
582
- closedCaption: adaptation.isClosedCaption === true,
583
- id: adaptation.id,
584
- active: currentId === null ? false :
585
- currentId === adaptation.id,
586
- label: adaptation.label,
587
- };
588
- if (adaptation.isForcedSubtitles !== undefined) {
589
- formatted.forced = adaptation.isForcedSubtitles;
590
- }
591
- return formatted;
523
+ var active = currentId === null ? false :
524
+ currentId === adaptation.id;
525
+ return objectAssign(adaptation.toTextTrack(), { active: active });
592
526
  });
593
527
  };
594
528
  /**
@@ -611,34 +545,21 @@ var TrackChoiceManager = /** @class */ (function () {
611
545
  (_a = chosenVideoAdaptation === null || chosenVideoAdaptation === void 0 ? void 0 : chosenVideoAdaptation.adaptation.id) !== null && _a !== void 0 ? _a : undefined;
612
546
  return videoInfos.adaptations
613
547
  .map(function (adaptation) {
614
- var trickModeTracks = adaptation.trickModeTracks !== undefined ?
615
- adaptation.trickModeTracks.map(function (trickModeAdaptation) {
548
+ var active = currentId === null ? false :
549
+ currentId === adaptation.id;
550
+ var track = adaptation.toVideoTrack();
551
+ var trickModeTracks = track.trickModeTracks !== undefined ?
552
+ track.trickModeTracks.map(function (trickModeAdaptation) {
616
553
  var isActive = currentId === null ? false :
617
554
  currentId === trickModeAdaptation.id;
618
- var representations = trickModeAdaptation.representations
619
- .map(parseVideoRepresentation);
620
- var trickMode = { id: trickModeAdaptation.id, representations: representations, isTrickModeTrack: true,
621
- active: isActive };
622
- if (trickModeAdaptation.isSignInterpreted === true) {
623
- trickMode.signInterpreted = true;
624
- }
625
- return trickMode;
555
+ return objectAssign(trickModeAdaptation, { active: isActive });
626
556
  }) :
627
- undefined;
628
- var formatted = {
629
- id: adaptation.id,
630
- active: currentId === null ? false :
631
- currentId === adaptation.id,
632
- representations: adaptation.representations.map(parseVideoRepresentation),
633
- label: adaptation.label,
634
- };
635
- if (adaptation.isSignInterpreted === true) {
636
- formatted.signInterpreted = true;
637
- }
557
+ [];
558
+ var availableTrack = objectAssign(track, { active: active });
638
559
  if (trickModeTracks !== undefined) {
639
- formatted.trickModeTracks = trickModeTracks;
560
+ availableTrack.trickModeTracks = trickModeTracks;
640
561
  }
641
- return formatted;
562
+ return availableTrack;
642
563
  });
643
564
  };
644
565
  /**
@@ -1058,24 +979,6 @@ function getPeriodItem(periods, period) {
1058
979
  }
1059
980
  }
1060
981
  }
1061
- /**
1062
- * Parse video Representation into a IVideoRepresentation.
1063
- * @param {Object} representation
1064
- * @returns {Object}
1065
- */
1066
- function parseVideoRepresentation(_a) {
1067
- var id = _a.id, bitrate = _a.bitrate, frameRate = _a.frameRate, width = _a.width, height = _a.height, codec = _a.codec, hdrInfo = _a.hdrInfo;
1068
- return { id: id, bitrate: bitrate, frameRate: frameRate, width: width, height: height, codec: codec, hdrInfo: hdrInfo };
1069
- }
1070
- /**
1071
- * Parse audio Representation into a ITMAudioRepresentation.
1072
- * @param {Object} representation
1073
- * @returns {Object}
1074
- */
1075
- function parseAudioRepresentation(_a) {
1076
- var id = _a.id, bitrate = _a.bitrate, codec = _a.codec;
1077
- return { id: id, bitrate: bitrate, codec: codec };
1078
- }
1079
982
  function getRightVideoTrack(adaptation, isTrickModeEnabled) {
1080
983
  var _a;
1081
984
  if (isTrickModeEnabled &&