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
@@ -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 &&
@@ -126,6 +126,12 @@ function estimateStarvationModeBitrate(pendingRequests, playbackInfo, currentRep
126
126
  }
127
127
  var concernedRequest = concernedRequests[0];
128
128
  var now = performance.now();
129
+ var minimumRequestTime = concernedRequest.content.segment.duration * 1.5;
130
+ minimumRequestTime = Math.min(minimumRequestTime, 3000);
131
+ minimumRequestTime = Math.max(minimumRequestTime, 12000);
132
+ if (now - concernedRequest.requestTimestamp < minimumRequestTime) {
133
+ return undefined;
134
+ }
129
135
  var lastProgressEvent = concernedRequest.progress.length > 0 ?
130
136
  concernedRequest.progress[concernedRequest.progress.length - 1] :
131
137
  undefined;
@@ -138,7 +144,7 @@ function estimateStarvationModeBitrate(pendingRequests, playbackInfo, currentRep
138
144
  // Calculate estimated time spent rebuffering if we continue doing that request.
139
145
  var expectedRebufferingTime = remainingTime -
140
146
  (realBufferGap / speed);
141
- if (expectedRebufferingTime > 2000) {
147
+ if (expectedRebufferingTime > 2500) {
142
148
  return bandwidthEstimate;
143
149
  }
144
150
  }
@@ -320,12 +326,9 @@ var NetworkAnalyzer = /** @class */ (function () {
320
326
  if (currentRepresentation === null) {
321
327
  return true;
322
328
  }
323
- else if (bitrate === currentRepresentation.bitrate) {
329
+ else if (bitrate >= currentRepresentation.bitrate) {
324
330
  return false;
325
331
  }
326
- else if (bitrate > currentRepresentation.bitrate) {
327
- return !this._inStarvationMode;
328
- }
329
332
  return shouldDirectlySwitchToLowBitrate(playbackInfo, currentRequests, this._lowLatencyMode);
330
333
  };
331
334
  return NetworkAnalyzer;
@@ -14,6 +14,24 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { Representation } from "../../../manifest";
17
+ /**
18
+ * Object representing a maintainability score as calculated by the
19
+ * `RepresentationScoreCalculator`.
20
+ */
21
+ export interface IRepresentationMaintainabilityScore {
22
+ /**
23
+ * Weighted mean of dividing the loaded segment's duration by the time to make
24
+ * their request.
25
+ */
26
+ score: number;
27
+ /**
28
+ * The confidence we have on the calculated `score` in reflecting a useful
29
+ * maintainability hint for the concerned Representation.
30
+ *
31
+ * Basically, the more segments have been loaded, the higher the confidence.
32
+ */
33
+ confidenceLevel: ScoreConfidenceLevel;
34
+ }
17
35
  /**
18
36
  * Calculate the "maintainability score" of a given Representation:
19
37
  * - A score higher than 1 means that the Representation can theorically
@@ -62,7 +80,7 @@ export default class RepresentationScoreCalculator {
62
80
  * @param {Representation} representation
63
81
  * @returns {number|undefined}
64
82
  */
65
- getEstimate(representation: Representation): [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";
@@ -114,6 +114,7 @@ var PlaybackObserver = /** @class */ (function () {
114
114
  */
115
115
  PlaybackObserver.prototype.setCurrentTime = function (time) {
116
116
  this._internalSeeksIncoming.push(time);
117
+ log.info("API: Seeking internally", time);
117
118
  this._mediaElement.currentTime = time;
118
119
  };
119
120
  /**
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import { IErrorCode, IErrorType } from "../../errors";
17
17
  import Manifest, { Adaptation, Representation } from "../../manifest";
18
- import { IAudioRepresentation, IAudioTrack, IAudioTrackSetting, IAvailableAudioTrack, IAvailableTextTrack, IAvailableVideoTrack, IBrokenRepresentationsLockContext, IConstructorOptions, IKeySystemConfigurationOutput, ILoadVideoOptions, ILockedAudioRepresentationsSettings, ILockedVideoRepresentationsSettings, ITrackUpdateEventPayload, IPeriod, IPeriodChangeEvent, IPlayerError, IPlayerState, IPositionUpdate, IStreamEvent, ITextTrack, IVideoRepresentation, ITextTrackSetting, IVideoTrack, IVideoTrackSetting } from "../../public_types";
18
+ import { IAudioRepresentation, IAudioTrack, IAudioTrackSetting, IAvailableAudioTrack, IAvailableTextTrack, IAvailableVideoTrack, IBrokenRepresentationsLockContext, IConstructorOptions, IKeySystemConfigurationOutput, ILoadVideoOptions, ILockedAudioRepresentationsSettings, ILockedVideoRepresentationsSettings, ITrackUpdateEventPayload, IRepresentationListUpdateContext, IPeriod, IPeriodChangeEvent, IPlayerError, IPlayerState, IPositionUpdate, IStreamEvent, ITextTrack, IVideoRepresentation, ITextTrackSetting, IVideoTrack, IVideoTrackSetting } from "../../public_types";
19
19
  import EventEmitter, { IListener } from "../../utils/event_emitter";
20
20
  import Logger from "../../utils/logger";
21
21
  import { IBufferedChunk, IBufferType } from "../segment_buffers";
@@ -95,6 +95,10 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
95
95
  * It should refer to the last content being played.
96
96
  */
97
97
  private _priv_reloadingMetadata;
98
+ /**
99
+ * Store last value of autoPlay, from the last load or reload.
100
+ */
101
+ private _priv_lastAutoPlay;
98
102
  /** All possible Error types emitted by the RxPlayer. */
99
103
  static get ErrorTypes(): Record<IErrorType, IErrorType>;
100
104
  /** All possible Error codes emitted by the RxPlayer. */
@@ -178,6 +182,26 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
178
182
  * @returns {string} - The current Player's state
179
183
  */
180
184
  getPlayerState(): string;
185
+ /**
186
+ * Returns true if a content is loaded.
187
+ * @returns {Boolean} - `true` if a content is loaded, `false` otherwise.
188
+ */
189
+ isContentLoaded(): boolean;
190
+ /**
191
+ * Returns true if the player is buffering.
192
+ * @returns {Boolean} - `true` if the player is buffering, `false` otherwise.
193
+ */
194
+ isBuffering(): boolean;
195
+ /**
196
+ * Returns the play/pause status of the player :
197
+ * - when `LOADING` or `RELOADING`, returns the scheduled play/pause condition
198
+ * for when loading is over,
199
+ * - in other states, returns the `<video>` element .paused value,
200
+ * - if the player is disposed, returns `true`.
201
+ * @returns {Boolean} - `true` if the player is paused or will be after loading,
202
+ * `false` otherwise.
203
+ */
204
+ isPaused(): boolean;
181
205
  /**
182
206
  * Returns true if both:
183
207
  * - a content is loaded
@@ -250,6 +274,12 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
250
274
  * @returns {Number}
251
275
  */
252
276
  getPosition(): number;
277
+ /**
278
+ * Returns the last stored content position, in seconds.
279
+ *
280
+ * @returns {number|undefined}
281
+ */
282
+ getLastStoredContentPosition(): number | undefined;
253
283
  /**
254
284
  * Returns the current playback rate at which the video plays.
255
285
  * @returns {Number}
@@ -630,6 +660,26 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
630
660
  */
631
661
  private _priv_initializeMediaElementTracksStore;
632
662
  private _priv_callTracksStoreGetterSetter;
663
+ /**
664
+ * Method to call when some event lead to a high for possibility that the
665
+ * available tracks for the given type have changed.
666
+ * Send the corresponding `available*Tracks` change event with the last
667
+ * available tracks.
668
+ *
669
+ * @param {string} trackType
670
+ * @param {Object|undefined} [oPeriodRef] - optional period object used by the
671
+ * `tracksStore` API, allows to optimize the method by bypassing this step.
672
+ */
673
+ private _priv_onAvailableTracksMayHaveChanged;
674
+ /**
675
+ * Method to call when a fatal error lead to the stopping of the current
676
+ * content.
677
+ *
678
+ * @param {*} err - The error encountered.
679
+ * @param {Object} contentInfos - The `IPublicApiContentInfos` object linked
680
+ * to the content for which the error was received.
681
+ */
682
+ private _priv_onFatalError;
633
683
  }
634
684
  /** Every events sent by the RxPlayer's public API. */
635
685
  interface IPublicAPIEvent {
@@ -647,9 +697,12 @@ interface IPublicAPIEvent {
647
697
  availableAudioTracksChange: IAvailableAudioTrack[];
648
698
  availableTextTracksChange: IAvailableTextTrack[];
649
699
  availableVideoTracksChange: IAvailableVideoTrack[];
700
+ play: null;
701
+ pause: null;
650
702
  newAvailablePeriods: IPeriod[];
651
703
  brokenRepresentationsLock: IBrokenRepresentationsLockContext;
652
704
  trackUpdate: ITrackUpdateEventPayload;
705
+ representationListUpdate: IRepresentationListUpdateContext;
653
706
  seeking: null;
654
707
  seeked: null;
655
708
  streamEvent: IStreamEvent;
@@ -50,6 +50,8 @@ import config from "../../config";
50
50
  import { ErrorCodes, ErrorTypes, formatError, MediaError, } from "../../errors";
51
51
  import features from "../../features";
52
52
  import log from "../../log";
53
+ import arrayFind from "../../utils/array_find";
54
+ import arrayIncludes from "../../utils/array_includes";
53
55
  import assert from "../../utils/assert";
54
56
  import assertUnreachable from "../../utils/assert_unreachable";
55
57
  import EventEmitter from "../../utils/event_emitter";
@@ -64,7 +66,7 @@ import MediaSourceContentInitializer from "../init/media_source_content_initiali
64
66
  import { checkReloadOptions, parseConstructorOptions, parseLoadVideoOptions, } from "./option_utils";
65
67
  import PlaybackObserver from "./playback_observer";
66
68
  import TracksStore from "./track_management/tracks_store";
67
- import { constructPlayerStateReference, emitSeekEvents, isLoadedState, } from "./utils";
69
+ import { constructPlayerStateReference, emitPlayPauseEvents, emitSeekEvents, isLoadedState, } from "./utils";
68
70
  /* eslint-disable @typescript-eslint/naming-convention */
69
71
  var generateContentId = idGenerator();
70
72
  var getPictureOnPictureStateRef = events.getPictureOnPictureStateRef, getVideoVisibilityRef = events.getVideoVisibilityRef, getElementResolutionRef = events.getElementResolutionRef, getScreenResolutionRef = events.getScreenResolutionRef;
@@ -86,7 +88,7 @@ var Player = /** @class */ (function (_super) {
86
88
  // Workaround to support Firefox autoplay on FF 42.
87
89
  // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
88
90
  videoElement.preload = "auto";
89
- _this.version = /* PLAYER_VERSION */ "4.0.0-beta.1";
91
+ _this.version = /* PLAYER_VERSION */ "4.0.0-beta.2";
90
92
  _this.log = log;
91
93
  _this.state = "STOPPED";
92
94
  _this.videoElement = videoElement;
@@ -114,6 +116,7 @@ var Player = /** @class */ (function (_super) {
114
116
  _this._priv_contentEventsMemory = {};
115
117
  _this._priv_setPlayerState("STOPPED" /* PLAYER_STATES.STOPPED */);
116
118
  _this._priv_reloadingMetadata = {};
119
+ _this._priv_lastAutoPlay = false;
117
120
  return _this;
118
121
  }
119
122
  Object.defineProperty(Player, "ErrorTypes", {
@@ -211,6 +214,7 @@ var Player = /** @class */ (function (_super) {
211
214
  log.info("API: Calling loadvideo", options.url, options.transport);
212
215
  this._priv_reloadingMetadata = { options: options };
213
216
  this._priv_initializeContentPlayback(options);
217
+ this._priv_lastAutoPlay = options.autoPlay;
214
218
  };
215
219
  /**
216
220
  * Reload the last loaded content.
@@ -386,23 +390,7 @@ var Player = /** @class */ (function (_super) {
386
390
  };
387
391
  // Bind events
388
392
  initializer.addEventListener("error", function (error) {
389
- var formattedError = formatError(error, {
390
- defaultCode: "NONE",
391
- defaultReason: "An unknown error stopped content playback.",
392
- });
393
- formattedError.fatal = true;
394
- contentInfos.currentContentCanceller.cancel();
395
- _this._priv_cleanUpCurrentContentState();
396
- _this._priv_currentError = formattedError;
397
- log.error("API: The player stopped because of an error", error instanceof Error ? error : "");
398
- _this._priv_setPlayerState("STOPPED" /* PLAYER_STATES.STOPPED */);
399
- // TODO This condition is here because the eventual callback called when the
400
- // player state is updated can launch a new content, thus the error will not
401
- // be here anymore, in which case triggering the "error" event is unwanted.
402
- // This is very ugly though, and we should probable have a better solution
403
- if (_this._priv_currentError === formattedError) {
404
- _this.trigger("error", formattedError);
405
- }
393
+ _this._priv_onFatalError(error, contentInfos);
406
394
  });
407
395
  initializer.addEventListener("warning", function (error) {
408
396
  var formattedError = formatError(error, {
@@ -412,11 +400,12 @@ var Player = /** @class */ (function (_super) {
412
400
  log.warn("API: Sending warning:", formattedError);
413
401
  _this.trigger("warning", formattedError);
414
402
  });
415
- initializer.addEventListener("reloadingMediaSource", function () {
403
+ initializer.addEventListener("reloadingMediaSource", function (payload) {
416
404
  contentInfos.segmentBuffersStore = null;
417
405
  if (contentInfos.tracksStore !== null) {
418
406
  contentInfos.tracksStore.resetPeriodObjects();
419
407
  }
408
+ _this._priv_lastAutoPlay = payload.autoPlay;
420
409
  });
421
410
  initializer.addEventListener("inbandEvents", function (inbandEvents) {
422
411
  return _this.trigger("inbandEvents", inbandEvents);
@@ -500,6 +489,48 @@ var Player = /** @class */ (function (_super) {
500
489
  break;
501
490
  }
502
491
  };
492
+ /**
493
+ * `TaskCanceller` allowing to stop emitting `"play"` and `"pause"`
494
+ * events.
495
+ * `null` when such events are not emitted currently.
496
+ */
497
+ var playPauseEventsCanceller = null;
498
+ /**
499
+ * Callback emitting `"play"` and `"pause`" events once the content is
500
+ * loaded, starting from the state indicated in argument.
501
+ * @param {boolean} willAutoPlay - If `false`, we're currently paused.
502
+ */
503
+ var triggerPlayPauseEventsWhenReady = function (willAutoPlay) {
504
+ if (playPauseEventsCanceller !== null) {
505
+ playPauseEventsCanceller.cancel(); // cancel previous logic
506
+ playPauseEventsCanceller = null;
507
+ }
508
+ playerStateRef.onUpdate(function (val, stopListeningToStateUpdates) {
509
+ if (!isLoadedState(val)) {
510
+ return; // content not loaded yet: no event
511
+ }
512
+ stopListeningToStateUpdates();
513
+ if (playPauseEventsCanceller !== null) {
514
+ playPauseEventsCanceller.cancel();
515
+ }
516
+ playPauseEventsCanceller = new TaskCanceller();
517
+ playPauseEventsCanceller.linkToSignal(currentContentCanceller.signal);
518
+ if (willAutoPlay !== !videoElement.paused) {
519
+ // paused status is not at the expected value on load: emit event
520
+ if (videoElement.paused) {
521
+ _this.trigger("pause", null);
522
+ }
523
+ else {
524
+ _this.trigger("play", null);
525
+ }
526
+ }
527
+ emitPlayPauseEvents(videoElement, function () { return _this.trigger("play", null); }, function () { return _this.trigger("pause", null); }, currentContentCanceller.signal);
528
+ }, { emitCurrentValue: false, clearSignal: currentContentCanceller.signal });
529
+ };
530
+ triggerPlayPauseEventsWhenReady(autoPlay);
531
+ initializer.addEventListener("reloadingMediaSource", function (payload) {
532
+ triggerPlayPauseEventsWhenReady(payload.autoPlay);
533
+ });
503
534
  /**
504
535
  * `TaskCanceller` allowing to stop emitting `"seeking"` and `"seeked"`
505
536
  * events.
@@ -569,6 +600,40 @@ var Player = /** @class */ (function (_super) {
569
600
  Player.prototype.getPlayerState = function () {
570
601
  return this.state;
571
602
  };
603
+ /**
604
+ * Returns true if a content is loaded.
605
+ * @returns {Boolean} - `true` if a content is loaded, `false` otherwise.
606
+ */
607
+ Player.prototype.isContentLoaded = function () {
608
+ return !arrayIncludes(["LOADING", "RELOADING", "STOPPED"], this.state);
609
+ };
610
+ /**
611
+ * Returns true if the player is buffering.
612
+ * @returns {Boolean} - `true` if the player is buffering, `false` otherwise.
613
+ */
614
+ Player.prototype.isBuffering = function () {
615
+ return arrayIncludes(["BUFFERING", "SEEKING", "LOADING", "RELOADING"], this.state);
616
+ };
617
+ /**
618
+ * Returns the play/pause status of the player :
619
+ * - when `LOADING` or `RELOADING`, returns the scheduled play/pause condition
620
+ * for when loading is over,
621
+ * - in other states, returns the `<video>` element .paused value,
622
+ * - if the player is disposed, returns `true`.
623
+ * @returns {Boolean} - `true` if the player is paused or will be after loading,
624
+ * `false` otherwise.
625
+ */
626
+ Player.prototype.isPaused = function () {
627
+ if (this.videoElement) {
628
+ if (arrayIncludes(["LOADING", "RELOADING"], this.state)) {
629
+ return !this._priv_lastAutoPlay;
630
+ }
631
+ else {
632
+ return this.videoElement.paused;
633
+ }
634
+ }
635
+ return true;
636
+ };
572
637
  /**
573
638
  * Returns true if both:
574
639
  * - a content is loaded
@@ -709,6 +774,14 @@ var Player = /** @class */ (function (_super) {
709
774
  }
710
775
  return this.videoElement.currentTime;
711
776
  };
777
+ /**
778
+ * Returns the last stored content position, in seconds.
779
+ *
780
+ * @returns {number|undefined}
781
+ */
782
+ Player.prototype.getLastStoredContentPosition = function () {
783
+ return this._priv_reloadingMetadata.reloadPosition;
784
+ };
712
785
  /**
713
786
  * Returns the current playback rate at which the video plays.
714
787
  * @returns {Number}
@@ -909,6 +982,7 @@ var Player = /** @class */ (function (_super) {
909
982
  if (positionWanted === undefined) {
910
983
  throw new Error("invalid time given");
911
984
  }
985
+ log.info("API: API Seek to", positionWanted);
912
986
  this.videoElement.currentTime = positionWanted;
913
987
  return positionWanted;
914
988
  };
@@ -1555,20 +1629,32 @@ var Player = /** @class */ (function (_super) {
1555
1629
  return; // Event for another content
1556
1630
  }
1557
1631
  contentInfos.manifest = manifest;
1558
- var cancelSignal = contentInfos.currentContentCanceller.signal;
1559
1632
  this._priv_reloadingMetadata.manifest = manifest;
1560
- contentInfos.tracksStore = new TracksStore({
1633
+ var tracksStore = new TracksStore({
1561
1634
  preferTrickModeTracks: this._priv_preferTrickModeTracks,
1562
1635
  defaultAudioTrackSwitchingMode: contentInfos.defaultAudioTrackSwitchingMode,
1563
1636
  });
1564
- contentInfos.tracksStore.addEventListener("newAvailablePeriods", function (p) {
1637
+ contentInfos.tracksStore = tracksStore;
1638
+ tracksStore.addEventListener("newAvailablePeriods", function (p) {
1565
1639
  _this.trigger("newAvailablePeriods", p);
1566
1640
  });
1567
- contentInfos.tracksStore.addEventListener("brokenRepresentationsLock", function (e) {
1641
+ tracksStore.addEventListener("brokenRepresentationsLock", function (e) {
1568
1642
  _this.trigger("brokenRepresentationsLock", e);
1569
1643
  });
1570
- contentInfos.tracksStore.addEventListener("trackUpdate", function (e) {
1644
+ tracksStore.addEventListener("trackUpdate", function (e) {
1645
+ var _a, _b;
1571
1646
  _this.trigger("trackUpdate", e);
1647
+ var currentPeriod = (_b = (_a = _this._priv_contentInfos) === null || _a === void 0 ? void 0 : _a.currentPeriod) !== null && _b !== void 0 ? _b : undefined;
1648
+ if (e.reason === "no-playable-representation" &&
1649
+ e.period.id === (currentPeriod === null || currentPeriod === void 0 ? void 0 : currentPeriod.id)) {
1650
+ _this._priv_onAvailableTracksMayHaveChanged(e.trackType);
1651
+ }
1652
+ });
1653
+ contentInfos.tracksStore.addEventListener("warning", function (err) {
1654
+ _this.trigger("warning", err);
1655
+ });
1656
+ contentInfos.tracksStore.addEventListener("error", function (err) {
1657
+ _this._priv_onFatalError(err, contentInfos);
1572
1658
  });
1573
1659
  contentInfos.tracksStore.updatePeriodList(manifest);
1574
1660
  manifest.addEventListener("manifestUpdate", function (updates) {
@@ -1578,8 +1664,8 @@ var Player = /** @class */ (function (_super) {
1578
1664
  contentInfos.tracksStore.updatePeriodList(manifest);
1579
1665
  }
1580
1666
  var currentPeriod = (_b = (_a = _this._priv_contentInfos) === null || _a === void 0 ? void 0 : _a.currentPeriod) !== null && _b !== void 0 ? _b : undefined;
1581
- var tracksStore = (_c = _this._priv_contentInfos) === null || _c === void 0 ? void 0 : _c.tracksStore;
1582
- if (currentPeriod === undefined || isNullOrUndefined(tracksStore)) {
1667
+ var currTracksStore = (_c = _this._priv_contentInfos) === null || _c === void 0 ? void 0 : _c.tracksStore;
1668
+ if (currentPeriod === undefined || isNullOrUndefined(currTracksStore)) {
1583
1669
  return;
1584
1670
  }
1585
1671
  for (var _i = 0, _d = updates.updatedPeriods; _i < _d.length; _i++) {
@@ -1588,21 +1674,64 @@ var Player = /** @class */ (function (_super) {
1588
1674
  if (update.result.addedAdaptations.length > 0 ||
1589
1675
  update.result.removedAdaptations.length > 0) {
1590
1676
  // We might have new (or less) tracks, send events just to be sure
1591
- var periodRef = tracksStore.getPeriodObjectFromPeriod(currentPeriod);
1677
+ var periodRef = currTracksStore.getPeriodObjectFromPeriod(currentPeriod);
1592
1678
  if (periodRef === undefined) {
1593
1679
  return;
1594
1680
  }
1595
- var audioTracks = tracksStore.getAvailableAudioTracks(periodRef);
1596
- _this._priv_triggerEventIfNotStopped("availableAudioTracksChange", audioTracks !== null && audioTracks !== void 0 ? audioTracks : [], cancelSignal);
1597
- var textTracks = tracksStore.getAvailableTextTracks(periodRef);
1598
- _this._priv_triggerEventIfNotStopped("availableTextTracksChange", textTracks !== null && textTracks !== void 0 ? textTracks : [], cancelSignal);
1599
- var videoTracks = tracksStore.getAvailableVideoTracks(periodRef);
1600
- _this._priv_triggerEventIfNotStopped("availableVideoTracksChange", videoTracks !== null && videoTracks !== void 0 ? videoTracks : [], cancelSignal);
1681
+ _this._priv_onAvailableTracksMayHaveChanged("audio");
1682
+ _this._priv_onAvailableTracksMayHaveChanged("text");
1683
+ _this._priv_onAvailableTracksMayHaveChanged("video");
1601
1684
  }
1602
1685
  }
1603
1686
  return;
1604
1687
  }
1605
1688
  }, contentInfos.currentContentCanceller.signal);
1689
+ manifest.addEventListener("decipherabilityUpdate", function (elts) {
1690
+ /**
1691
+ * Array of tuples only including once the Period/Track combination, and
1692
+ * only when it concerns the currently-selected track.
1693
+ */
1694
+ var periodsAndTrackTypes = elts.reduce(function (acc, elt) {
1695
+ var _a, _b, _c;
1696
+ var isFound = arrayFind(acc, function (x) { return x[0].id === elt.period.id &&
1697
+ x[1] === elt.adaptation.type; }) === undefined;
1698
+ if (!isFound) {
1699
+ // Only consider the currently-selected tracks.
1700
+ // NOTE: Maybe there's room for optimizations? Unclear.
1701
+ var tStore = contentInfos.tracksStore;
1702
+ if (tStore === null) {
1703
+ return acc;
1704
+ }
1705
+ var isCurrent = false;
1706
+ var periodRef = tStore.getPeriodObjectFromPeriod(elt.period);
1707
+ if (periodRef === undefined) {
1708
+ return acc;
1709
+ }
1710
+ switch (elt.adaptation.type) {
1711
+ case "audio":
1712
+ isCurrent = ((_a = tStore
1713
+ .getChosenAudioTrack(periodRef)) === null || _a === void 0 ? void 0 : _a.id) === elt.adaptation.id;
1714
+ break;
1715
+ case "video":
1716
+ isCurrent = ((_b = tStore
1717
+ .getChosenVideoTrack(periodRef)) === null || _b === void 0 ? void 0 : _b.id) === elt.adaptation.id;
1718
+ break;
1719
+ case "text":
1720
+ isCurrent = ((_c = tStore
1721
+ .getChosenTextTrack(periodRef)) === null || _c === void 0 ? void 0 : _c.id) === elt.adaptation.id;
1722
+ break;
1723
+ }
1724
+ if (isCurrent) {
1725
+ acc.push([elt.period, elt.adaptation.type]);
1726
+ }
1727
+ }
1728
+ return acc;
1729
+ }, []);
1730
+ for (var _i = 0, periodsAndTrackTypes_1 = periodsAndTrackTypes; _i < periodsAndTrackTypes_1.length; _i++) {
1731
+ var _a = periodsAndTrackTypes_1[_i], period = _a[0], trackType = _a[1];
1732
+ _this._priv_triggerEventIfNotStopped("representationListUpdate", { period: period, trackType: trackType, reason: "decipherability-update" }, contentInfos.currentContentCanceller.signal);
1733
+ }
1734
+ }, contentInfos.currentContentCanceller.signal);
1606
1735
  };
1607
1736
  /**
1608
1737
  * Triggered each times the current Period Changed.
@@ -1962,7 +2091,75 @@ var Player = /** @class */ (function (_super) {
1962
2091
  }
1963
2092
  return cb(tracksStore, periodRef);
1964
2093
  };
2094
+ /**
2095
+ * Method to call when some event lead to a high for possibility that the
2096
+ * available tracks for the given type have changed.
2097
+ * Send the corresponding `available*Tracks` change event with the last
2098
+ * available tracks.
2099
+ *
2100
+ * @param {string} trackType
2101
+ * @param {Object|undefined} [oPeriodRef] - optional period object used by the
2102
+ * `tracksStore` API, allows to optimize the method by bypassing this step.
2103
+ */
2104
+ Player.prototype._priv_onAvailableTracksMayHaveChanged = function (trackType, oPeriodRef) {
2105
+ var contentInfos = this._priv_contentInfos;
2106
+ if (contentInfos === null) {
2107
+ return;
2108
+ }
2109
+ var currentPeriod = contentInfos.currentPeriod, tracksStore = contentInfos.tracksStore, currentContentCanceller = contentInfos.currentContentCanceller;
2110
+ var cancelSignal = currentContentCanceller.signal;
2111
+ if (isNullOrUndefined(currentPeriod) || tracksStore === null) {
2112
+ return;
2113
+ }
2114
+ var periodRef = oPeriodRef !== null && oPeriodRef !== void 0 ? oPeriodRef : tracksStore.getPeriodObjectFromPeriod(currentPeriod);
2115
+ if (periodRef === undefined) {
2116
+ return;
2117
+ }
2118
+ switch (trackType) {
2119
+ case "video":
2120
+ var videoTracks = tracksStore.getAvailableVideoTracks(periodRef);
2121
+ this._priv_triggerEventIfNotStopped("availableVideoTracksChange", videoTracks !== null && videoTracks !== void 0 ? videoTracks : [], cancelSignal);
2122
+ break;
2123
+ case "audio":
2124
+ var audioTracks = tracksStore.getAvailableAudioTracks(periodRef);
2125
+ this._priv_triggerEventIfNotStopped("availableAudioTracksChange", audioTracks !== null && audioTracks !== void 0 ? audioTracks : [], cancelSignal);
2126
+ break;
2127
+ case "text":
2128
+ var textTracks = tracksStore.getAvailableTextTracks(periodRef);
2129
+ this._priv_triggerEventIfNotStopped("availableTextTracksChange", textTracks !== null && textTracks !== void 0 ? textTracks : [], cancelSignal);
2130
+ break;
2131
+ default:
2132
+ assertUnreachable(trackType);
2133
+ }
2134
+ };
2135
+ /**
2136
+ * Method to call when a fatal error lead to the stopping of the current
2137
+ * content.
2138
+ *
2139
+ * @param {*} err - The error encountered.
2140
+ * @param {Object} contentInfos - The `IPublicApiContentInfos` object linked
2141
+ * to the content for which the error was received.
2142
+ */
2143
+ Player.prototype._priv_onFatalError = function (err, contentInfos) {
2144
+ var formattedError = formatError(err, {
2145
+ defaultCode: "NONE",
2146
+ defaultReason: "An unknown error stopped content playback.",
2147
+ });
2148
+ formattedError.fatal = true;
2149
+ contentInfos.currentContentCanceller.cancel();
2150
+ this._priv_cleanUpCurrentContentState();
2151
+ this._priv_currentError = formattedError;
2152
+ log.error("API: The player stopped because of an error", formattedError);
2153
+ this._priv_setPlayerState("STOPPED" /* PLAYER_STATES.STOPPED */);
2154
+ // TODO This condition is here because the eventual callback called when the
2155
+ // player state is updated can launch a new content, thus the error will not
2156
+ // be here anymore, in which case triggering the "error" event is unwanted.
2157
+ // This is very ugly though, and we should probable have a better solution
2158
+ if (this._priv_currentError === formattedError) {
2159
+ this.trigger("error", formattedError);
2160
+ }
2161
+ };
1965
2162
  return Player;
1966
2163
  }(EventEmitter));
1967
- Player.version = /* PLAYER_VERSION */ "4.0.0-beta.1";
2164
+ Player.version = /* PLAYER_VERSION */ "4.0.0-beta.2";
1968
2165
  export default Player;
@@ -102,7 +102,14 @@ function createTextTracks(textTracks) {
102
102
  "_" +
103
103
  occurences.toString();
104
104
  languagesOccurences[language] = occurences + 1;
105
- var track = { language: textTrack.language, id: id, normalized: normalizeLanguage(textTrack.language),
105
+ // Safari seems to be indicating that the subtitles track is a forced
106
+ // subtitles track by setting the `kind` attribute to `"forced"`.
107
+ // As of now (2023-04-04), this is not standard.
108
+ // @see https://github.com/whatwg/html/issues/4472
109
+ var forced = textTrack.kind === "forced" ?
110
+ true :
111
+ undefined;
112
+ var track = { language: textTrack.language, forced: forced, label: textTrack.label, id: id, normalized: normalizeLanguage(textTrack.language),
106
113
  closedCaption: textTrack.kind === "captions" };
107
114
  newTextTracks.push({ track: track, nativeTrack: textTrack });
108
115
  }
@@ -293,6 +300,8 @@ var MediaElementTracksStore = /** @class */ (function (_super) {
293
300
  return this._textTracks.map(function (_a) {
294
301
  var track = _a.track, nativeTrack = _a.nativeTrack;
295
302
  return { id: track.id,
303
+ label: track.label,
304
+ forced: track.forced,
296
305
  language: track.language,
297
306
  normalized: track.normalized,
298
307
  closedCaption: track.closedCaption,