rx-player 3.33.0-dev.2023111400 → 3.33.0-dev.2023120600

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 (95) hide show
  1. package/CHANGELOG.md +8 -2
  2. package/FILES.md +1 -1
  3. package/VERSION +1 -1
  4. package/dist/_esm5.processed/core/api/debug/buffer_graph.js +2 -6
  5. package/dist/_esm5.processed/core/api/debug/modules/general_info.js +20 -10
  6. package/dist/_esm5.processed/core/api/option_utils.d.ts +2 -0
  7. package/dist/_esm5.processed/core/api/option_utils.js +2 -3
  8. package/dist/_esm5.processed/core/api/public_api.d.ts +9 -0
  9. package/dist/_esm5.processed/core/api/public_api.js +28 -5
  10. package/dist/_esm5.processed/core/init/directfile_content_initializer.js +24 -7
  11. package/dist/_esm5.processed/core/init/media_source_content_initializer.js +3 -5
  12. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.d.ts +13 -12
  13. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.js +16 -17
  14. package/dist/_esm5.processed/core/init/utils/get_initial_time.d.ts +17 -3
  15. package/dist/_esm5.processed/core/init/utils/get_initial_time.js +9 -7
  16. package/dist/_esm5.processed/core/stream/representation/utils/get_buffer_status.js +3 -3
  17. package/dist/_esm5.processed/core/stream/representation/utils/get_needed_segments.js +1 -1
  18. package/dist/_esm5.processed/manifest/representation_index/static.d.ts +1 -1
  19. package/dist/_esm5.processed/manifest/representation_index/static.js +2 -2
  20. package/dist/_esm5.processed/manifest/representation_index/types.d.ts +4 -4
  21. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.d.ts +6 -1
  22. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.js +4 -3
  23. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/get_segments_from_timeline.d.ts +5 -2
  24. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/get_segments_from_timeline.js +15 -4
  25. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/index.d.ts +5 -5
  26. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.d.ts +1 -1
  27. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.js +2 -2
  28. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.d.ts +12 -11
  29. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.js +43 -34
  30. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/index.d.ts +2 -1
  31. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.d.ts +99 -6
  32. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.js +247 -51
  33. package/dist/_esm5.processed/parsers/manifest/dash/common/manifest_bounds_calculator.d.ts +40 -17
  34. package/dist/_esm5.processed/parsers/manifest/dash/common/manifest_bounds_calculator.js +38 -18
  35. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_adaptation_sets.js +13 -11
  36. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_mpd.js +27 -14
  37. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_periods.d.ts +1 -1
  38. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_periods.js +16 -17
  39. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representation_index.d.ts +19 -8
  40. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representation_index.js +21 -8
  41. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +7 -3
  42. package/dist/_esm5.processed/parsers/manifest/local/representation_index.d.ts +1 -1
  43. package/dist/_esm5.processed/parsers/manifest/local/representation_index.js +3 -3
  44. package/dist/_esm5.processed/parsers/manifest/metaplaylist/representation_index.d.ts +1 -1
  45. package/dist/_esm5.processed/parsers/manifest/metaplaylist/representation_index.js +2 -2
  46. package/dist/_esm5.processed/parsers/manifest/smooth/representation_index.d.ts +5 -5
  47. package/dist/_esm5.processed/parsers/manifest/smooth/representation_index.js +25 -9
  48. package/dist/_esm5.processed/parsers/manifest/utils/index_helpers.js +1 -1
  49. package/dist/_esm5.processed/parsers/texttracks/ttml/html/apply_line_height.js +2 -1
  50. package/dist/_esm5.processed/public_types.d.ts +14 -2
  51. package/dist/rx-player.js +601 -368
  52. package/dist/rx-player.min.js +1 -1
  53. package/package.json +3 -4
  54. package/scripts/canal-release.patch +320 -0
  55. package/scripts/make-releases +26 -0
  56. package/scripts/update-version +2 -0
  57. package/sonar-project.properties +1 -1
  58. package/src/core/api/debug/buffer_graph.ts +2 -5
  59. package/src/core/api/debug/modules/general_info.ts +15 -6
  60. package/src/core/api/option_utils.ts +3 -3
  61. package/src/core/api/public_api.ts +30 -5
  62. package/src/core/init/directfile_content_initializer.ts +23 -7
  63. package/src/core/init/media_source_content_initializer.ts +6 -6
  64. package/src/core/init/utils/content_time_boundaries_observer.ts +23 -22
  65. package/src/core/init/utils/get_initial_time.ts +25 -12
  66. package/src/core/stream/representation/utils/get_buffer_status.ts +3 -3
  67. package/src/core/stream/representation/utils/get_needed_segments.ts +2 -2
  68. package/src/manifest/representation_index/static.ts +2 -2
  69. package/src/manifest/representation_index/types.ts +4 -4
  70. package/src/parsers/manifest/dash/common/__tests__/manifest_bounds_calculator.test.ts +182 -36
  71. package/src/parsers/manifest/dash/common/indexes/base.ts +12 -4
  72. package/src/parsers/manifest/dash/common/indexes/get_segments_from_timeline.ts +19 -5
  73. package/src/parsers/manifest/dash/common/indexes/index.ts +16 -4
  74. package/src/parsers/manifest/dash/common/indexes/list.ts +2 -2
  75. package/src/parsers/manifest/dash/common/indexes/template.ts +53 -43
  76. package/src/parsers/manifest/dash/common/indexes/timeline/index.ts +4 -1
  77. package/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +366 -60
  78. package/src/parsers/manifest/dash/common/manifest_bounds_calculator.ts +63 -25
  79. package/src/parsers/manifest/dash/common/parse_adaptation_sets.ts +10 -5
  80. package/src/parsers/manifest/dash/common/parse_mpd.ts +28 -15
  81. package/src/parsers/manifest/dash/common/parse_periods.ts +14 -20
  82. package/src/parsers/manifest/dash/common/parse_representation_index.ts +51 -31
  83. package/src/parsers/manifest/dash/common/parse_representations.ts +9 -3
  84. package/src/parsers/manifest/local/representation_index.ts +3 -3
  85. package/src/parsers/manifest/metaplaylist/representation_index.ts +2 -2
  86. package/src/parsers/manifest/smooth/representation_index.ts +23 -9
  87. package/src/parsers/manifest/utils/__tests__/get_first_time_from_adaptations.test.ts +1 -1
  88. package/src/parsers/manifest/utils/__tests__/get_last_time_from_adaptation.test.ts +1 -1
  89. package/src/parsers/manifest/utils/index_helpers.ts +1 -1
  90. package/src/parsers/texttracks/ttml/html/apply_line_height.ts +3 -1
  91. package/src/public_types.ts +15 -2
  92. package/dist/_esm5.processed/parsers/manifest/utils/is_segment_still_available.d.ts +0 -29
  93. package/dist/_esm5.processed/parsers/manifest/utils/is_segment_still_available.js +0 -51
  94. package/src/parsers/manifest/utils/is_segment_still_available.ts +0 -58
  95. package/src/typings/object-assign.d.ts +0 -48
package/CHANGELOG.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # Changelog
2
2
 
3
- ## v3.33.0-canal.2023111400 (2023-11-14)
3
+ ## v3.33.0-dev.2023120600 (2023-12-06)
4
4
 
5
5
  ### Features
6
6
 
7
- - Add the possibility to set a new `keySystems` option on the `reload` API [#1308]
7
+ - Add `getLivePosition` RxPlayer method [#1300]
8
+ - Add `startAt.fromLivePosition` `loadVideo` option [#1300]
9
+ - Add the possibility to set a new `keySystems` option on the `reload` API [#1308]
8
10
 
9
11
  ### Bug Fixes
10
12
 
@@ -15,6 +17,10 @@
15
17
  ### Other improvements
16
18
 
17
19
  - DASH: rely on SCTE214 `supplementalCodecs` instead of `codecs` if it's supported to better support backward compatible Dolby Vision contents [#1307]
20
+ - DASH: Provide better support of the `availabilityTimeOffset` attribute [#1300]
21
+ - DEBUG_ELEMENT: Add unsupported and undecipherable bitrates to the debug element [#1321]
22
+ - DEBUG_ELEMENT: update buffer graph maximum size so it becomes more readable for lengthy contents [#1316]
23
+ - DEBUG_ELEMENT: always synchronize inventory of segments before rendering it [#1317]
18
24
 
19
25
 
20
26
  ## v3.32.1 (2023-10-19)
package/FILES.md CHANGED
@@ -20,7 +20,7 @@ At the time of writing, there are two distinct demos:
20
20
 
21
21
  ## `dist/`: Builds
22
22
 
23
- The `demo/` directory stores the player builds of the last version released.
23
+ The `dist/` directory stores the player builds of the last version released.
24
24
 
25
25
  Contains the minified (``rx-player.min.js``) and the non-minified files
26
26
  (``rx-player.js``). Both are automatically generated with scripts at every new
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.33.0-dev.2023111400
1
+ 3.33.0-dev.2023120600
@@ -1,4 +1,4 @@
1
- var BUFFER_WIDTH_IN_SECONDS = 10000;
1
+ var BUFFER_WIDTH_IN_SECONDS = 30 * 60;
2
2
  var COLORS = [
3
3
  "#2ab7ca",
4
4
  "#fed766",
@@ -65,11 +65,7 @@ var SegmentBufferGraph = /** @class */ (function () {
65
65
  var minimumPosition;
66
66
  var maximumPosition;
67
67
  if (maximumPoint - minimumPoint > BUFFER_WIDTH_IN_SECONDS) {
68
- if (currentTime === undefined) {
69
- minimumPosition = minimumPoint;
70
- maximumPosition = maximumPoint;
71
- }
72
- else if (maximumPoint - currentTime < BUFFER_WIDTH_IN_SECONDS / 2) {
68
+ if (maximumPoint - currentTime < BUFFER_WIDTH_IN_SECONDS / 2) {
73
69
  maximumPosition = maximumPoint;
74
70
  minimumPosition = maximumPoint - BUFFER_WIDTH_IN_SECONDS;
75
71
  }
@@ -17,6 +17,7 @@ export default function constructDebugGeneralInfo(instance, parentElt, cancelSig
17
17
  representationsElt,
18
18
  ]);
19
19
  function updateGeneralInfo() {
20
+ var _a, _b, _c, _d;
20
21
  var videoElement = instance.getVideoElement();
21
22
  if (videoElement === null) {
22
23
  // disposed player. Clean-up everything
@@ -99,12 +100,12 @@ export default function constructDebugGeneralInfo(instance, parentElt, cancelSig
99
100
  valuesLine3.push(["er", "\"".concat(String(error), "\"")]);
100
101
  }
101
102
  generalInfoElt.innerHTML = "";
102
- for (var _i = 0, _a = [valuesLine1, valuesLine2, valuesLine3]; _i < _a.length; _i++) {
103
- var valueSet = _a[_i];
103
+ for (var _i = 0, _e = [valuesLine1, valuesLine2, valuesLine3]; _i < _e.length; _i++) {
104
+ var valueSet = _e[_i];
104
105
  if (valueSet.length > 0) {
105
106
  var lineInfoElt = createElement("div");
106
- for (var _b = 0, valueSet_1 = valueSet; _b < valueSet_1.length; _b++) {
107
- var value = valueSet_1[_b];
107
+ for (var _f = 0, valueSet_1 = valueSet; _f < valueSet_1.length; _f++) {
108
+ var value = valueSet_1[_f];
108
109
  lineInfoElt.appendChild(createMetricTitle(value[0]));
109
110
  lineInfoElt.appendChild(createElement("span", {
110
111
  textContent: value[1] + " ",
@@ -175,19 +176,28 @@ export default function constructDebugGeneralInfo(instance, parentElt, cancelSig
175
176
  ]);
176
177
  adaptationsElt.appendChild(textAdaps);
177
178
  }
178
- var videoBitrates = instance.getAvailableVideoBitrates();
179
- var audioBitrates = instance.getAvailableAudioBitrates();
179
+ var adaptations = instance.getCurrentAdaptations();
180
+ var videoBitratesStr = (_b = (_a = adaptations === null || adaptations === void 0 ? void 0 : adaptations.video) === null || _a === void 0 ? void 0 : _a.representations.map(function (r) {
181
+ return String(r.bitrate) +
182
+ (r.isSupported ? "" : " U!") +
183
+ (r.decipherable !== false ? "" : " E!");
184
+ })) !== null && _b !== void 0 ? _b : [];
185
+ var audioBitratesStr = (_d = (_c = adaptations === null || adaptations === void 0 ? void 0 : adaptations.video) === null || _c === void 0 ? void 0 : _c.representations.map(function (r) {
186
+ return String(r.bitrate) +
187
+ (r.isSupported ? "" : " U!") +
188
+ (r.decipherable !== false ? "" : " E!");
189
+ })) !== null && _d !== void 0 ? _d : [];
180
190
  representationsElt.innerHTML = "";
181
- if (videoBitrates.length > 0) {
191
+ if (videoBitratesStr.length > 0) {
182
192
  representationsElt.appendChild(createMetricTitle("vb"));
183
193
  representationsElt.appendChild(createElement("span", {
184
- textContent: videoBitrates.join(" ") + " ",
194
+ textContent: videoBitratesStr.join(" ") + " ",
185
195
  }));
186
196
  }
187
- if (audioBitrates.length > 0) {
197
+ if (audioBitratesStr.length > 0) {
188
198
  representationsElt.appendChild(createMetricTitle("ab"));
189
199
  representationsElt.appendChild(createElement("span", {
190
- textContent: audioBitrates.join(" ") + " ",
200
+ textContent: audioBitratesStr.join(" ") + " ",
191
201
  }));
192
202
  }
193
203
  }
@@ -24,6 +24,8 @@ export type IParsedStartAtOption = {
24
24
  percentage: number;
25
25
  } | {
26
26
  fromLastPosition: number;
27
+ } | {
28
+ fromLivePosition: number;
27
29
  } | {
28
30
  fromFirstPosition: number;
29
31
  };
@@ -462,9 +462,8 @@ function parseLoadVideoOptions(options) {
462
462
  "an \"html\" textTrackMode. It will be ignored.");
463
463
  }
464
464
  if (!isNullOrUndefined(options.startAt)) {
465
- // TODO Better way to express that in TypeScript?
466
- if (options.startAt.wallClockTime
467
- instanceof Date) {
465
+ if ("wallClockTime" in options.startAt
466
+ && options.startAt.wallClockTime instanceof Date) {
468
467
  var wallClockTime = options.startAt
469
468
  .wallClockTime.getTime() / 1000;
470
469
  startAt = objectAssign({}, options.startAt, { wallClockTime: wallClockTime });
@@ -717,6 +717,15 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
717
717
  * @returns {number}
718
718
  */
719
719
  getMinimumPosition(): number | null;
720
+ /**
721
+ * Returns the current position for live contents.
722
+ *
723
+ * Returns `null` if no content is loaded or if the current loaded content is
724
+ * not considered as a live content.
725
+ * Returns `undefined` if that live position is currently unknown.
726
+ * @returns {number}
727
+ */
728
+ getLivePosition(): number | undefined | null;
720
729
  /**
721
730
  * Get maximum seek-able position.
722
731
  * @returns {number}
@@ -88,7 +88,7 @@ var Player = /** @class */ (function (_super) {
88
88
  // Workaround to support Firefox autoplay on FF 42.
89
89
  // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
90
90
  videoElement.preload = "auto";
91
- _this.version = /* PLAYER_VERSION */ "3.33.0-dev.2023111400";
91
+ _this.version = /* PLAYER_VERSION */ "3.33.0-dev.2023120600";
92
92
  _this.log = log;
93
93
  _this.state = "STOPPED";
94
94
  _this.videoElement = videoElement;
@@ -1882,6 +1882,27 @@ var Player = /** @class */ (function (_super) {
1882
1882
  }
1883
1883
  return null;
1884
1884
  };
1885
+ /**
1886
+ * Returns the current position for live contents.
1887
+ *
1888
+ * Returns `null` if no content is loaded or if the current loaded content is
1889
+ * not considered as a live content.
1890
+ * Returns `undefined` if that live position is currently unknown.
1891
+ * @returns {number}
1892
+ */
1893
+ Player.prototype.getLivePosition = function () {
1894
+ if (this._priv_contentInfos === null) {
1895
+ return null;
1896
+ }
1897
+ var _a = this._priv_contentInfos, isDirectFile = _a.isDirectFile, manifest = _a.manifest;
1898
+ if (isDirectFile) {
1899
+ return undefined;
1900
+ }
1901
+ if ((manifest === null || manifest === void 0 ? void 0 : manifest.isLive) !== true) {
1902
+ return null;
1903
+ }
1904
+ return manifest.getLivePosition();
1905
+ };
1885
1906
  /**
1886
1907
  * Get maximum seek-able position.
1887
1908
  * @returns {number}
@@ -1920,9 +1941,11 @@ var Player = /** @class */ (function (_super) {
1920
1941
  }
1921
1942
  var segmentBufferStatus = this._priv_contentInfos
1922
1943
  .segmentBuffersStore.getStatus(bufferType);
1923
- return segmentBufferStatus.type === "initialized" ?
1924
- segmentBufferStatus.value.getInventory() :
1925
- null;
1944
+ if (segmentBufferStatus.type === "initialized") {
1945
+ segmentBufferStatus.value.synchronizeInventory();
1946
+ return segmentBufferStatus.value.getInventory();
1947
+ }
1948
+ return null;
1926
1949
  };
1927
1950
  /**
1928
1951
  * Reset all state properties relative to a playing content.
@@ -2449,5 +2472,5 @@ var Player = /** @class */ (function (_super) {
2449
2472
  };
2450
2473
  return Player;
2451
2474
  }(EventEmitter));
2452
- Player.version = /* PLAYER_VERSION */ "3.33.0-dev.2023111400";
2475
+ Player.version = /* PLAYER_VERSION */ "3.33.0-dev.2023120600";
2453
2476
  export default Player;
@@ -35,6 +35,7 @@ var __extends = (this && this.__extends) || (function () {
35
35
  import { clearElementSrc } from "../../compat";
36
36
  import log from "../../log";
37
37
  import assert from "../../utils/assert";
38
+ import isNullOrUndefined from "../../utils/is_null_or_undefined";
38
39
  import SharedReference from "../../utils/reference";
39
40
  import TaskCanceller from "../../utils/task_canceller";
40
41
  import { ContentInitializer } from "./types";
@@ -203,10 +204,10 @@ export default DirectFileContentInitializer;
203
204
  * @returns {number}
204
205
  */
205
206
  function getDirectFileInitialTime(mediaElement, startAt) {
206
- if (startAt == null) {
207
+ if (isNullOrUndefined(startAt)) {
207
208
  return 0;
208
209
  }
209
- if (startAt.position != null) {
210
+ if (!isNullOrUndefined(startAt.position)) {
210
211
  return startAt.position;
211
212
  }
212
213
  else if (startAt.wallClockTime != null) {
@@ -216,15 +217,31 @@ function getDirectFileInitialTime(mediaElement, startAt) {
216
217
  return startAt.fromFirstPosition;
217
218
  }
218
219
  var duration = mediaElement.duration;
219
- if (duration == null || !isFinite(duration)) {
220
- log.warn("startAt.fromLastPosition set but no known duration, " +
221
- "beginning at 0.");
222
- return 0;
223
- }
224
220
  if (typeof startAt.fromLastPosition === "number") {
221
+ if (isNullOrUndefined(duration) || !isFinite(duration)) {
222
+ log.warn("startAt.fromLastPosition set but no known duration, " +
223
+ "beginning at 0.");
224
+ return 0;
225
+ }
225
226
  return Math.max(0, duration + startAt.fromLastPosition);
226
227
  }
228
+ else if (typeof startAt.fromLivePosition === "number") {
229
+ var livePosition = mediaElement.seekable.length > 0 ?
230
+ mediaElement.seekable.end(0) :
231
+ duration;
232
+ if (isNullOrUndefined(livePosition)) {
233
+ log.warn("startAt.fromLivePosition set but no known live position, " +
234
+ "beginning at 0.");
235
+ return 0;
236
+ }
237
+ return Math.max(0, livePosition + startAt.fromLivePosition);
238
+ }
227
239
  else if (startAt.percentage != null) {
240
+ if (isNullOrUndefined(duration) || !isFinite(duration)) {
241
+ log.warn("startAt.percentage set but no known duration, " +
242
+ "beginning at 0.");
243
+ return 0;
244
+ }
228
245
  var percentage = startAt.percentage;
229
246
  if (percentage >= 100) {
230
247
  return duration;
@@ -569,9 +569,7 @@ var MediaSourceContentInitializer = /** @class */ (function (_super) {
569
569
  contentTimeBoundariesObserver.addEventListener("periodChange", function (period) {
570
570
  _this.trigger("activePeriodChanged", { period: period });
571
571
  });
572
- contentTimeBoundariesObserver.addEventListener("durationUpdate", function (newDuration) {
573
- mediaSourceDurationUpdater.updateDuration(newDuration.duration, newDuration.isEnd);
574
- });
572
+ contentTimeBoundariesObserver.addEventListener("endingPositionChange", function (x) { return mediaSourceDurationUpdater.updateDuration(x.endingPosition, x.isEnd); });
575
573
  contentTimeBoundariesObserver.addEventListener("endOfStream", function () {
576
574
  if (endOfStreamCanceller === null) {
577
575
  endOfStreamCanceller = new TaskCanceller();
@@ -587,8 +585,8 @@ var MediaSourceContentInitializer = /** @class */ (function (_super) {
587
585
  endOfStreamCanceller = null;
588
586
  }
589
587
  });
590
- var currentDuration = contentTimeBoundariesObserver.getCurrentDuration();
591
- mediaSourceDurationUpdater.updateDuration(currentDuration.duration, currentDuration.isEnd);
588
+ var endInfo = contentTimeBoundariesObserver.getCurrentEndingTime();
589
+ mediaSourceDurationUpdater.updateDuration(endInfo.endingPosition, endInfo.isEnd);
592
590
  return contentTimeBoundariesObserver;
593
591
  };
594
592
  /**
@@ -22,8 +22,8 @@ import { IStreamOrchestratorPlaybackObservation } from "../../stream";
22
22
  /**
23
23
  * Observes what's being played and take care of media events relating to time
24
24
  * boundaries:
25
- * - Emits a `durationUpdate` when the duration of the current content is
26
- * known and every time it changes.
25
+ * - Emits a `endingPositionChange` when the known maximum playable position
26
+ * of the current content is known and every time it changes.
27
27
  * - Emits `endOfStream` API once segments have been pushed until the end and
28
28
  * `resumeStream` if downloads starts back.
29
29
  * - Emits a `periodChange` event when the currently-playing Period seemed to
@@ -56,10 +56,11 @@ export default class ContentTimeBoundariesObserver extends EventEmitter<IContent
56
56
  */
57
57
  constructor(manifest: Manifest, playbackObserver: IReadOnlyPlaybackObserver<IStreamOrchestratorPlaybackObservation>, bufferTypes: IBufferType[]);
58
58
  /**
59
- * Returns an estimate of the current duration of the content.
59
+ * Returns an estimate of the current last position which may be played in
60
+ * the content at the moment.
60
61
  * @returns {Object}
61
62
  */
62
- getCurrentDuration(): IDurationItem;
63
+ getCurrentEndingTime(): IEndingPositionInformation;
63
64
  /**
64
65
  * Method to call any time an Adaptation has been selected.
65
66
  *
@@ -126,20 +127,20 @@ export default class ContentTimeBoundariesObserver extends EventEmitter<IContent
126
127
  private _addActivelyLoadedPeriod;
127
128
  private _removeActivelyLoadedPeriod;
128
129
  private _checkCurrentPeriod;
129
- private _getManifestDuration;
130
+ private _getManifestEndTime;
130
131
  private _lazilyCreateActiveStreamInfo;
131
132
  private _checkEndOfStream;
132
133
  }
133
- export interface IDurationItem {
134
+ export interface IEndingPositionInformation {
134
135
  /**
135
136
  * The new maximum known position (note that this is the ending position
136
137
  * currently known of the current content, it might be superior to the last
137
138
  * position at which segments are available and it might also evolve over
138
139
  * time), in seconds.
139
140
  */
140
- duration: number;
141
+ endingPosition: number;
141
142
  /**
142
- * If `true`, the communicated `duration` is the actual end of the content.
143
+ * If `true`, the communicated `endingPosition` is the actual end of the content.
143
144
  * It may still be updated due to a track change or to add precision, but it
144
145
  * is still a (rough) estimate of the maximum position that content should
145
146
  * have.
@@ -147,7 +148,7 @@ export interface IDurationItem {
147
148
  * If `false`, this is the currently known maximum position associated to
148
149
  * the content, but the content is still evolving (typically, new media
149
150
  * segments are still being generated) and as such it can still have a
150
- * longer duration in the future.
151
+ * longer `endingPosition` in the future.
151
152
  */
152
153
  isEnd: boolean;
153
154
  }
@@ -161,10 +162,10 @@ export interface IContentTimeBoundariesObserverEvent {
161
162
  /** Triggered when a new `Period` is currently playing. */
162
163
  periodChange: Period;
163
164
  /**
164
- * Triggered when the duration of the currently-playing content became known
165
- * or changed.
165
+ * Triggered when the ending position of the currently-playing content became
166
+ * known or changed.
166
167
  */
167
- durationUpdate: IDurationItem;
168
+ endingPositionChange: IEndingPositionInformation;
168
169
  /**
169
170
  * Triggered when the last possible chronological segment for all types of
170
171
  * buffers has either been pushed or is being pushed to the corresponding
@@ -36,8 +36,8 @@ import TaskCanceller from "../../../utils/task_canceller";
36
36
  /**
37
37
  * Observes what's being played and take care of media events relating to time
38
38
  * boundaries:
39
- * - Emits a `durationUpdate` when the duration of the current content is
40
- * known and every time it changes.
39
+ * - Emits a `endingPositionChange` when the known maximum playable position
40
+ * of the current content is known and every time it changes.
41
41
  * - Emits `endOfStream` API once segments have been pushed until the end and
42
42
  * `resumeStream` if downloads starts back.
43
43
  * - Emits a `periodChange` event when the currently-playing Period seemed to
@@ -82,7 +82,7 @@ var ContentTimeBoundariesObserver = /** @class */ (function (_super) {
82
82
  }
83
83
  }, { includeLastObservation: true, clearSignal: cancelSignal });
84
84
  manifest.addEventListener("manifestUpdate", function () {
85
- _this.trigger("durationUpdate", _this._getManifestDuration());
85
+ _this.trigger("endingPositionChange", _this._getManifestEndTime());
86
86
  if (cancelSignal.isCancelled()) {
87
87
  return;
88
88
  }
@@ -91,11 +91,12 @@ var ContentTimeBoundariesObserver = /** @class */ (function (_super) {
91
91
  return _this;
92
92
  }
93
93
  /**
94
- * Returns an estimate of the current duration of the content.
94
+ * Returns an estimate of the current last position which may be played in
95
+ * the content at the moment.
95
96
  * @returns {Object}
96
97
  */
97
- ContentTimeBoundariesObserver.prototype.getCurrentDuration = function () {
98
- return this._getManifestDuration();
98
+ ContentTimeBoundariesObserver.prototype.getCurrentEndingTime = function () {
99
+ return this._getManifestEndTime();
99
100
  };
100
101
  /**
101
102
  * Method to call any time an Adaptation has been selected.
@@ -124,12 +125,12 @@ var ContentTimeBoundariesObserver = /** @class */ (function (_super) {
124
125
  .updateLastVideoAdaptation(adaptation);
125
126
  }
126
127
  var endingPosition = this._maximumPositionCalculator.getEndingPosition();
127
- var newDuration = endingPosition !== undefined ?
128
- { isEnd: true,
129
- duration: endingPosition } :
128
+ var newEndingPosition = endingPosition !== undefined ?
129
+ { isEnd: true, endingPosition: endingPosition } :
130
130
  { isEnd: false,
131
- duration: this._maximumPositionCalculator.getMaximumAvailablePosition() };
132
- this.trigger("durationUpdate", newDuration);
131
+ endingPosition: this._maximumPositionCalculator
132
+ .getMaximumAvailablePosition() };
133
+ this.trigger("endingPositionChange", newEndingPosition);
133
134
  }
134
135
  }
135
136
  }
@@ -263,13 +264,12 @@ var ContentTimeBoundariesObserver = /** @class */ (function (_super) {
263
264
  return state_1.value;
264
265
  }
265
266
  };
266
- ContentTimeBoundariesObserver.prototype._getManifestDuration = function () {
267
+ ContentTimeBoundariesObserver.prototype._getManifestEndTime = function () {
267
268
  var endingPosition = this._maximumPositionCalculator.getEndingPosition();
268
269
  return endingPosition !== undefined ?
269
- { isEnd: true,
270
- duration: endingPosition } :
270
+ { isEnd: true, endingPosition: endingPosition } :
271
271
  { isEnd: false,
272
- duration: this._maximumPositionCalculator.getMaximumAvailablePosition() };
272
+ endingPosition: this._maximumPositionCalculator.getMaximumAvailablePosition() };
273
273
  };
274
274
  ContentTimeBoundariesObserver.prototype._lazilyCreateActiveStreamInfo = function (bufferType) {
275
275
  var streamInfo = this._activeStreams.get(bufferType);
@@ -343,9 +343,8 @@ var MaximumPositionCalculator = /** @class */ (function () {
343
343
  * @returns {number}
344
344
  */
345
345
  MaximumPositionCalculator.prototype.getMaximumAvailablePosition = function () {
346
- var _a;
347
346
  if (this._manifest.isDynamic) {
348
- return (_a = this._manifest.getLivePosition()) !== null && _a !== void 0 ? _a : this._manifest.getMaximumSafePosition();
347
+ return this._manifest.getMaximumSafePosition();
349
348
  }
350
349
  if (this._lastVideoAdaptation === undefined ||
351
350
  this._lastAudioAdaptation === undefined) {
@@ -37,11 +37,25 @@ export interface IInitialTimeOptions {
37
37
  */
38
38
  fromFirstPosition?: number | null | undefined;
39
39
  /**
40
- * If set, we should begin at this position relative to the content's end,
41
- * in seconds.
40
+ * If set, we should begin at this position relative to the content's maximum
41
+ * seekable position, in seconds.
42
+ *
43
+ * It should consequently in most cases be a negative value.
42
44
  */
43
45
  fromLastPosition?: number | null | undefined;
44
- /** If set, we should begin at this position relative to the whole duration of
46
+ /**
47
+ * If set, we should begin at this position relative to the content's live
48
+ * edge if it makes sense, in seconds.
49
+ *
50
+ * It should consequently in most cases be a negative value.
51
+ *
52
+ * If the live edge is unknown or if it does not make sense for the current
53
+ * content, that position is relative to the content's maximum position
54
+ * instead.
55
+ */
56
+ fromLivePosition?: number | null | undefined;
57
+ /**
58
+ * If set, we should begin at this position relative to the whole duration of
45
59
  * the content, in percentage.
46
60
  */
47
61
  percentage?: number | null | undefined;
@@ -30,15 +30,10 @@ import isNullOrUndefined from "../../../utils/is_null_or_undefined";
30
30
  * @returns {Number}
31
31
  */
32
32
  export default function getInitialTime(manifest, lowLatencyMode, startAt) {
33
+ var _a;
33
34
  if (!isNullOrUndefined(startAt)) {
34
35
  var min = manifest.getMinimumSafePosition();
35
- var max = void 0;
36
- if (manifest.isLive) {
37
- max = manifest.getLivePosition();
38
- }
39
- if (max === undefined) {
40
- max = manifest.getMaximumSafePosition();
41
- }
36
+ var max = manifest.getMaximumSafePosition();
42
37
  if (!isNullOrUndefined(startAt.position)) {
43
38
  log.debug("Init: using startAt.minimumPosition");
44
39
  return Math.max(Math.min(startAt.position, max), min);
@@ -63,6 +58,13 @@ export default function getInitialTime(manifest, lowLatencyMode, startAt) {
63
58
  return fromLastPosition >= 0 ? max :
64
59
  Math.max(min, max + fromLastPosition);
65
60
  }
61
+ else if (!isNullOrUndefined(startAt.fromLivePosition)) {
62
+ log.debug("Init: using startAt.fromLivePosition");
63
+ var livePosition = (_a = manifest.getLivePosition()) !== null && _a !== void 0 ? _a : max;
64
+ var fromLivePosition = startAt.fromLivePosition;
65
+ return fromLivePosition >= 0 ? livePosition :
66
+ Math.max(min, livePosition + fromLivePosition);
67
+ }
66
68
  else if (!isNullOrUndefined(startAt.percentage)) {
67
69
  log.debug("Init: using startAt.percentage");
68
70
  var percentage = startAt.percentage;
@@ -69,7 +69,7 @@ export default function getBufferStatus(content, initialWantedTime, playbackObse
69
69
  * needed segments for this Representation until the end of the Period.
70
70
  */
71
71
  var hasFinishedLoading = representation.index.isInitialized() &&
72
- representation.index.isFinished() &&
72
+ !representation.index.isStillAwaitingFutureSegments() &&
73
73
  neededRange.hasReachedPeriodEnd &&
74
74
  prioritizedNeededSegments.length === 0 &&
75
75
  segmentsOnHold.length === 0;
@@ -119,7 +119,7 @@ function getRangeOfNeededSegments(content, initialWantedTime, bufferGoal) {
119
119
  SegmentBuffersStore.isNative(content.adaptation.type) &&
120
120
  initialWantedTime >= lastIndexPosition &&
121
121
  representationIndex.isInitialized() &&
122
- representationIndex.isFinished() &&
122
+ !representationIndex.isStillAwaitingFutureSegments() &&
123
123
  isPeriodTheCurrentAndLastOne(manifest, period, initialWantedTime)) {
124
124
  wantedStartPosition = lastIndexPosition - 1;
125
125
  }
@@ -129,7 +129,7 @@ function getRangeOfNeededSegments(content, initialWantedTime, bufferGoal) {
129
129
  var wantedEndPosition = wantedStartPosition + bufferGoal;
130
130
  var hasReachedPeriodEnd;
131
131
  if (!representation.index.isInitialized() ||
132
- !representation.index.isFinished() ||
132
+ representation.index.isStillAwaitingFutureSegments() ||
133
133
  period.end === undefined) {
134
134
  hasReachedPeriodEnd = false;
135
135
  }
@@ -321,7 +321,7 @@ function doesEndSeemGarbageCollected(currentSeg, nextSeg, minimumEndTime) {
321
321
  }
322
322
  if (minimumEndTime > currentSeg.bufferedEnd &&
323
323
  currentSeg.end - currentSeg.bufferedEnd > MAX_TIME_MISSING_FROM_COMPLETE_SEGMENT) {
324
- log.info("Stream: The end of the wanted segment has been garbage collected", currentSeg.start, currentSeg.bufferedStart);
324
+ log.info("Stream: The end of the wanted segment has been garbage collected", currentSeg.end, currentSeg.bufferedEnd);
325
325
  return true;
326
326
  }
327
327
  return false;
@@ -89,7 +89,7 @@ export default class StaticRepresentationIndex implements IRepresentationIndex {
89
89
  /**
90
90
  * @returns {Boolean}
91
91
  */
92
- isFinished(): true;
92
+ isStillAwaitingFutureSegments(): false;
93
93
  /**
94
94
  * @returns {Boolean}
95
95
  */
@@ -115,8 +115,8 @@ var StaticRepresentationIndex = /** @class */ (function () {
115
115
  /**
116
116
  * @returns {Boolean}
117
117
  */
118
- StaticRepresentationIndex.prototype.isFinished = function () {
119
- return true;
118
+ StaticRepresentationIndex.prototype.isStillAwaitingFutureSegments = function () {
119
+ return false;
120
120
  };
121
121
  /**
122
122
  * @returns {Boolean}
@@ -306,7 +306,7 @@ export interface IRepresentationIndex {
306
306
  getLastAvailablePosition(): number | null | undefined;
307
307
  /**
308
308
  * Returns the ending time, in seconds, of the Representation once it is
309
- * "finished" (@see isFinished).
309
+ * "finished" (@see isStillAwaitingFutureSegments).
310
310
  * Should thus be equivalent to `getLastAvailablePosition` once finished.
311
311
  *
312
312
  * Returns `null` if nothing is in the index
@@ -354,13 +354,13 @@ export interface IRepresentationIndex {
354
354
  */
355
355
  checkDiscontinuity(time: number): number | null;
356
356
  /**
357
- * Returns `true` if the last segments in this index have already been
357
+ * Returns `false` if the last segments in this index have already been
358
358
  * generated so that we can freely go to the next period.
359
- * Returns `false` if the index is still waiting on future segments to be
359
+ * Returns `true` if the index is still waiting on future segments to be
360
360
  * generated.
361
361
  * @returns {boolean}
362
362
  */
363
- isFinished(): boolean;
363
+ isStillAwaitingFutureSegments(): boolean;
364
364
  /**
365
365
  * Returns `true` if this index has all the data it needs to give the list
366
366
  * of available segments.
@@ -16,6 +16,7 @@
16
16
  import { IRepresentationIndex, ISegment } from "../../../../../manifest";
17
17
  import { IEMSG } from "../../../../containers/isobmff";
18
18
  import { IIndexSegment } from "../../../utils/index_helpers";
19
+ import ManifestBoundsCalculator from "../manifest_bounds_calculator";
19
20
  /**
20
21
  * Index property defined for a SegmentBase RepresentationIndex
21
22
  * This object contains every property needed to generate an ISegment for a
@@ -107,6 +108,8 @@ export interface IBaseIndexContextArgument {
107
108
  representationId?: string | undefined;
108
109
  /** Bitrate of the Representation concerned. */
109
110
  representationBitrate?: number | undefined;
111
+ /** Allows to obtain the minimum and maximum positions of a content. */
112
+ manifestBoundsCalculator: ManifestBoundsCalculator;
110
113
  isEMSGWhitelisted: (inbandEvent: IEMSG) => boolean;
111
114
  }
112
115
  export default class BaseRepresentationIndex implements IRepresentationIndex {
@@ -123,6 +126,8 @@ export default class BaseRepresentationIndex implements IRepresentationIndex {
123
126
  private _scaledPeriodStart;
124
127
  /** Absolute end of the period, timescaled and converted to index time. */
125
128
  private _scaledPeriodEnd;
129
+ /** Allows to obtain the minimum and maximum positions of a content. */
130
+ private _manifestBoundsCalculator;
126
131
  private _isEMSGWhitelisted;
127
132
  /**
128
133
  * @param {Object} index
@@ -218,7 +223,7 @@ export default class BaseRepresentationIndex implements IRepresentationIndex {
218
223
  * should become available in the future.
219
224
  * @returns {Boolean}
220
225
  */
221
- isFinished(): true;
226
+ isStillAwaitingFutureSegments(): false;
222
227
  /**
223
228
  * No segment in a `BaseRepresentationIndex` are known initially.
224
229
  * It is only defined generally in an "index segment" that will thus need to