rx-player 3.27.1-dev.2022040500 → 3.27.1-dev.2022060300

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 (103) hide show
  1. package/CHANGELOG.md +12 -2
  2. package/README.md +2 -1
  3. package/VERSION +1 -1
  4. package/dist/_esm5.processed/core/abr/abr_manager.d.ts +7 -3
  5. package/dist/_esm5.processed/core/abr/abr_manager.js +4 -3
  6. package/dist/_esm5.processed/core/abr/representation_estimator.d.ts +13 -8
  7. package/dist/_esm5.processed/core/abr/representation_estimator.js +4 -4
  8. package/dist/_esm5.processed/core/api/public_api.js +13 -14
  9. package/dist/_esm5.processed/core/decrypt/content_decryptor.js +12 -10
  10. package/dist/_esm5.processed/core/decrypt/utils/key_session_record.js +2 -1
  11. package/dist/_esm5.processed/core/init/content_time_boundaries_observer.d.ts +52 -0
  12. package/dist/_esm5.processed/core/init/content_time_boundaries_observer.js +223 -0
  13. package/dist/_esm5.processed/core/init/create_stream_playback_observer.js +17 -6
  14. package/dist/_esm5.processed/core/init/get_initial_time.d.ts +30 -5
  15. package/dist/_esm5.processed/core/init/get_initial_time.js +20 -13
  16. package/dist/_esm5.processed/core/init/load_on_media_source.js +16 -3
  17. package/dist/_esm5.processed/core/init/media_duration_updater.d.ts +56 -0
  18. package/dist/_esm5.processed/core/init/media_duration_updater.js +188 -0
  19. package/dist/_esm5.processed/core/init/throw_on_media_error.js +19 -10
  20. package/dist/_esm5.processed/core/stream/adaptation/adaptation_stream.d.ts +2 -5
  21. package/dist/_esm5.processed/core/stream/adaptation/create_representation_estimator.d.ts +3 -2
  22. package/dist/_esm5.processed/core/stream/adaptation/create_representation_estimator.js +3 -3
  23. package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +2 -22
  24. package/dist/_esm5.processed/core/stream/period/period_stream.d.ts +2 -5
  25. package/dist/_esm5.processed/core/stream/representation/get_buffer_status.d.ts +4 -2
  26. package/dist/_esm5.processed/core/stream/representation/get_buffer_status.js +85 -42
  27. package/dist/_esm5.processed/core/stream/representation/representation_stream.js +3 -3
  28. package/dist/_esm5.processed/manifest/manifest.d.ts +14 -5
  29. package/dist/_esm5.processed/manifest/manifest.js +31 -12
  30. package/dist/_esm5.processed/manifest/period.d.ts +6 -0
  31. package/dist/_esm5.processed/manifest/period.js +9 -0
  32. package/dist/_esm5.processed/manifest/representation.js +4 -4
  33. package/dist/_esm5.processed/manifest/representation_index/types.d.ts +7 -2
  34. package/dist/_esm5.processed/parsers/manifest/dash/common/flatten_overlapping_periods.js +11 -1
  35. package/dist/_esm5.processed/parsers/manifest/dash/common/get_minimum_and_maximum_positions.d.ts +5 -1
  36. package/dist/_esm5.processed/parsers/manifest/dash/common/get_minimum_and_maximum_positions.js +6 -4
  37. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.js +2 -1
  38. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.d.ts +4 -0
  39. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.js +4 -2
  40. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.js +4 -2
  41. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_elements.d.ts +1 -3
  42. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_elements.js +2 -4
  43. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_previous_timeline.d.ts +1 -1
  44. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_previous_timeline.js +6 -6
  45. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/convert_element_to_index_segment.d.ts +1 -3
  46. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/convert_element_to_index_segment.js +2 -4
  47. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.js +8 -5
  48. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_mpd.js +28 -20
  49. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +10 -3
  50. package/dist/_esm5.processed/parsers/manifest/local/parse_local_manifest.js +3 -2
  51. package/dist/_esm5.processed/parsers/manifest/metaplaylist/metaplaylist_parser.js +9 -3
  52. package/dist/_esm5.processed/parsers/manifest/smooth/create_parser.js +26 -17
  53. package/dist/_esm5.processed/parsers/manifest/types.d.ts +52 -19
  54. package/dist/_esm5.processed/parsers/manifest/utils/{get_maximum_position.d.ts → get_maximum_positions.d.ts} +4 -1
  55. package/dist/_esm5.processed/parsers/manifest/utils/{get_maximum_position.js → get_maximum_positions.js} +10 -6
  56. package/dist/_esm5.processed/parsers/texttracks/ttml/html/generate_css_test_outline.js +14 -4
  57. package/dist/rx-player.js +941 -396
  58. package/dist/rx-player.min.js +1 -1
  59. package/package.json +1 -1
  60. package/sonar-project.properties +1 -1
  61. package/src/core/abr/abr_manager.ts +11 -3
  62. package/src/core/abr/representation_estimator.ts +17 -10
  63. package/src/core/api/public_api.ts +13 -15
  64. package/src/core/decrypt/__tests__/__global__/get_license.test.ts +1 -1
  65. package/src/core/decrypt/content_decryptor.ts +12 -10
  66. package/src/core/decrypt/utils/key_session_record.ts +2 -1
  67. package/src/core/init/content_time_boundaries_observer.ts +312 -0
  68. package/src/core/init/create_stream_playback_observer.ts +18 -7
  69. package/src/core/init/get_initial_time.ts +52 -19
  70. package/src/core/init/load_on_media_source.ts +22 -5
  71. package/src/core/init/media_duration_updater.ts +268 -0
  72. package/src/core/init/throw_on_media_error.ts +25 -15
  73. package/src/core/stream/adaptation/adaptation_stream.ts +2 -5
  74. package/src/core/stream/adaptation/create_representation_estimator.ts +6 -3
  75. package/src/core/stream/orchestrator/stream_orchestrator.ts +2 -29
  76. package/src/core/stream/period/period_stream.ts +2 -5
  77. package/src/core/stream/representation/get_buffer_status.ts +102 -41
  78. package/src/core/stream/representation/representation_stream.ts +3 -3
  79. package/src/manifest/__tests__/manifest.test.ts +94 -68
  80. package/src/manifest/manifest.ts +73 -33
  81. package/src/manifest/period.ts +10 -0
  82. package/src/manifest/representation.ts +2 -2
  83. package/src/manifest/representation_index/types.ts +7 -2
  84. package/src/parsers/manifest/dash/common/flatten_overlapping_periods.ts +10 -1
  85. package/src/parsers/manifest/dash/common/get_minimum_and_maximum_positions.ts +10 -5
  86. package/src/parsers/manifest/dash/common/indexes/base.ts +4 -3
  87. package/src/parsers/manifest/dash/common/indexes/list.ts +8 -1
  88. package/src/parsers/manifest/dash/common/indexes/template.ts +8 -3
  89. package/src/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_elements.ts +2 -8
  90. package/src/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_previous_timeline.ts +6 -10
  91. package/src/parsers/manifest/dash/common/indexes/timeline/convert_element_to_index_segment.ts +2 -5
  92. package/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +12 -11
  93. package/src/parsers/manifest/dash/common/parse_mpd.ts +38 -20
  94. package/src/parsers/manifest/dash/common/parse_representations.ts +9 -3
  95. package/src/parsers/manifest/local/parse_local_manifest.ts +3 -2
  96. package/src/parsers/manifest/metaplaylist/metaplaylist_parser.ts +9 -4
  97. package/src/parsers/manifest/smooth/create_parser.ts +36 -18
  98. package/src/parsers/manifest/types.ts +52 -19
  99. package/src/parsers/manifest/utils/{get_maximum_position.ts → get_maximum_positions.ts} +13 -7
  100. package/src/parsers/texttracks/ttml/html/generate_css_test_outline.ts +15 -4
  101. package/dist/_esm5.processed/core/init/duration_updater.d.ts +0 -27
  102. package/dist/_esm5.processed/core/init/duration_updater.js +0 -136
  103. package/src/core/init/duration_updater.ts +0 -206
package/CHANGELOG.md CHANGED
@@ -1,11 +1,21 @@
1
1
  # Changelog
2
2
 
3
- ## v3.27.1-dev.2022040500 (2022-04-05)
3
+ ## v3.27.1-dev.2022051100 (2022-06-03)
4
4
 
5
5
  ### Bug fixes
6
6
 
7
- - When creating SourceBuffers, use the first _supported_ codec of the chosen `Adaptation`, not the lowest-bitrate one [#1094]
7
+ - Use the first **compatible** codec of the current AdaptationSet when creating a SourceBuffer [#1094]
8
+ - DASH/DRM: Fix potential infinite rebuffering when a KID is not anounced in the MPD [#1113]
9
+ - DASH: Avoid infinite loop due to rounding errors while parsing multi-Periods MPDs [#1111, #1110]
10
+ - TTML: Add support for percent based thickness for textOutline in TTML Subtitles
11
+ - If seeking after the last potential position, load last segments before ending [#1097]
12
+ - DASH: Fix possibility of wrong segments being requested when a SegmentTimeline in a given Period (whose Period@end is set) had an S@r set to `-1` at its end [#1098]
13
+ - DASH: Don't include presentationTimeOffset for the default initial time of the first `<S>` element if its S@t is not set.
8
14
 
15
+ ### Other improvements
16
+
17
+ - The duration set on the media element is now only relative to the current chosen tracks (it was previously relative to all potential track). This allows to seek later when switching e.g. to a longer video track [#1102]
18
+ - Errors coming from an HTMLMediaElement now have the browser's error message if it exists [#1112]
9
19
 
10
20
  ## v3.27.0 (2022-03-31)
11
21
 
package/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  <p align="center">
2
- <img src="./doc/static/img/logo.png" />
2
+ <img src="./doc/static/img/logo.png#gh-light-mode-only" alt="RxPlayer's logo"/>
3
+ <img src="./doc/static/img/logo-white.png#gh-dark-mode-only" alt="RxPlayer's logo"/>
3
4
  <br /><br />
4
5
  <a href="https://developers.canal-plus.com/rx-player/doc/api/Overview.html">📖 <b>API documentation</b></a>
5
6
  -
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.27.1-dev.2022040500
1
+ 3.27.1-dev.2022060300
@@ -14,7 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { Observable } from "rxjs";
17
- import { Representation } from "../../manifest";
17
+ import Manifest, { Adaptation, Period, Representation } from "../../manifest";
18
18
  import { ISharedReference } from "../../utils/reference";
19
19
  import { IBufferType } from "../segment_buffers";
20
20
  import { IABREstimate, IABRStreamEvents, IRepresentationEstimatorPlaybackObservation } from "./representation_estimator";
@@ -59,13 +59,17 @@ export default class ABRManager {
59
59
  * Take type and an array of the available representations, spit out an
60
60
  * observable emitting the best representation (given the network/buffer
61
61
  * state).
62
- * @param {string} type
62
+ * @param {Object} context
63
63
  * @param {Array.<Representation>} representations
64
64
  * @param {Observable<Object>} observation$
65
65
  * @param {Observable<Object>} streamEvents$
66
66
  * @returns {Observable}
67
67
  */
68
- get$(type: IBufferType, representations: Representation[], observation$: Observable<IABRManagerPlaybackObservation>, streamEvents$: Observable<IABRStreamEvents>): Observable<IABREstimate>;
68
+ get$(context: {
69
+ manifest: Manifest;
70
+ period: Period;
71
+ adaptation: Adaptation;
72
+ }, representations: Representation[], observation$: Observable<IABRManagerPlaybackObservation>, streamEvents$: Observable<IABRStreamEvents>): Observable<IABREstimate>;
69
73
  /**
70
74
  * @param {string} bufferType
71
75
  * @returns {Object}
@@ -52,21 +52,22 @@ var ABRManager = /** @class */ (function () {
52
52
  * Take type and an array of the available representations, spit out an
53
53
  * observable emitting the best representation (given the network/buffer
54
54
  * state).
55
- * @param {string} type
55
+ * @param {Object} context
56
56
  * @param {Array.<Representation>} representations
57
57
  * @param {Observable<Object>} observation$
58
58
  * @param {Observable<Object>} streamEvents$
59
59
  * @returns {Observable}
60
60
  */
61
- ABRManager.prototype.get$ = function (type, representations, observation$, streamEvents$) {
61
+ ABRManager.prototype.get$ = function (context, representations, observation$, streamEvents$) {
62
62
  var _a, _b, _c;
63
+ var type = context.adaptation.type;
63
64
  var bandwidthEstimator = this._getBandwidthEstimator(type);
64
65
  var manualBitrate$ = takeFirstSet((_a = this._manualBitrates[type]) === null || _a === void 0 ? void 0 : _a.asObservable(), observableOf(-1));
65
66
  var minAutoBitrate$ = takeFirstSet((_b = this._minAutoBitrates[type]) === null || _b === void 0 ? void 0 : _b.asObservable(), observableOf(0));
66
67
  var maxAutoBitrate$ = takeFirstSet((_c = this._maxAutoBitrates[type]) === null || _c === void 0 ? void 0 : _c.asObservable(), observableOf(Infinity));
67
68
  var initialBitrate = takeFirstSet(this._initialBitrates[type], 0);
68
69
  var filters$ = createFilters(this._throttlers.limitWidth[type], this._throttlers.throttleBitrate[type], this._throttlers.throttle[type]);
69
- return RepresentationEstimator({ bandwidthEstimator: bandwidthEstimator, streamEvents$: streamEvents$, observation$: observation$, filters$: filters$, initialBitrate: initialBitrate, manualBitrate$: manualBitrate$, minAutoBitrate$: minAutoBitrate$, maxAutoBitrate$: maxAutoBitrate$, representations: representations, lowLatencyMode: this._lowLatencyMode });
70
+ return RepresentationEstimator({ bandwidthEstimator: bandwidthEstimator, context: context, streamEvents$: streamEvents$, observation$: observation$, filters$: filters$, initialBitrate: initialBitrate, manualBitrate$: manualBitrate$, minAutoBitrate$: minAutoBitrate$, maxAutoBitrate$: maxAutoBitrate$, representations: representations, lowLatencyMode: this._lowLatencyMode });
70
71
  };
71
72
  /**
72
73
  * @param {string} bufferType
@@ -14,7 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { Observable } from "rxjs";
17
- import { Adaptation, ISegment, Representation } from "../../manifest";
17
+ import Manifest, { Adaptation, ISegment, Period, Representation } from "../../manifest";
18
18
  import BandwidthEstimator from "./bandwidth_estimator";
19
19
  import { IPendingRequestStoreBegin, IPendingRequestStoreProgress } from "./pending_requests_store";
20
20
  /**
@@ -100,12 +100,8 @@ export interface IRepresentationEstimatorPlaybackObservation {
100
100
  speed: number;
101
101
  /** `duration` property of the HTMLMediaElement on which the content plays. */
102
102
  duration: number;
103
- /**
104
- * For live contents only, difference between the maximum playable position
105
- * and the current position.
106
- * `undefined` for non-live contents.
107
- */
108
- liveGap: number | undefined;
103
+ /** Theoretical maximum position on the content that can currently be played. */
104
+ maximumPosition: number;
109
105
  }
110
106
  /** Content of the `IABRMetricsEvent` event's payload. */
111
107
  export interface IABRMetricsEventValue {
@@ -304,6 +300,15 @@ export interface IRepresentationEstimatorArguments {
304
300
  maxAutoBitrate$: Observable<number>;
305
301
  /** The list of Representations the `RepresentationEstimator` can choose from. */
306
302
  representations: Representation[];
303
+ /** Context for the list of Representations to choose. */
304
+ context: {
305
+ /** In which Manifest the Representations are. */
306
+ manifest: Manifest;
307
+ /** In which Period the Representations are. */
308
+ period: Period;
309
+ /** In which Adaptation the Representations are. */
310
+ adaptation: Adaptation;
311
+ };
307
312
  }
308
313
  /**
309
314
  * Estimate regularly the current network bandwidth and the best Representation
@@ -317,4 +322,4 @@ export interface IRepresentationEstimatorArguments {
317
322
  * @param {Object} args
318
323
  * @returns {Observable}
319
324
  */
320
- export default function RepresentationEstimator({ bandwidthEstimator, observation$, filters$, initialBitrate, lowLatencyMode, manualBitrate$, minAutoBitrate$, maxAutoBitrate$, representations, streamEvents$, }: IRepresentationEstimatorArguments): Observable<IABREstimate>;
325
+ export default function RepresentationEstimator({ bandwidthEstimator, context, observation$, filters$, initialBitrate, lowLatencyMode, manualBitrate$, minAutoBitrate$, maxAutoBitrate$, representations, streamEvents$, }: IRepresentationEstimatorArguments): Observable<IABREstimate>;
@@ -54,7 +54,7 @@ function getFilteredRepresentations(representations, filters) {
54
54
  * @returns {Observable}
55
55
  */
56
56
  export default function RepresentationEstimator(_a) {
57
- var bandwidthEstimator = _a.bandwidthEstimator, observation$ = _a.observation$, filters$ = _a.filters$, initialBitrate = _a.initialBitrate, lowLatencyMode = _a.lowLatencyMode, manualBitrate$ = _a.manualBitrate$, minAutoBitrate$ = _a.minAutoBitrate$, maxAutoBitrate$ = _a.maxAutoBitrate$, representations = _a.representations, streamEvents$ = _a.streamEvents$;
57
+ var bandwidthEstimator = _a.bandwidthEstimator, context = _a.context, observation$ = _a.observation$, filters$ = _a.filters$, initialBitrate = _a.initialBitrate, lowLatencyMode = _a.lowLatencyMode, manualBitrate$ = _a.manualBitrate$, minAutoBitrate$ = _a.minAutoBitrate$, maxAutoBitrate$ = _a.maxAutoBitrate$, representations = _a.representations, streamEvents$ = _a.streamEvents$;
58
58
  var scoreCalculator = new RepresentationScoreCalculator();
59
59
  var networkAnalyzer = new NetworkAnalyzer(initialBitrate == null ? 0 :
60
60
  initialBitrate, lowLatencyMode);
@@ -145,7 +145,7 @@ export default function RepresentationEstimator(_a) {
145
145
  filters$,
146
146
  bufferBasedEstimation$]).pipe(withLatestFrom(currentRepresentation$), map(function (_a) {
147
147
  var _b = _a[0], observation = _b[0], minAutoBitrate = _b[1], maxAutoBitrate = _b[2], filters = _b[3], bufferBasedBitrate = _b[4], currentRepresentation = _a[1];
148
- var bufferGap = observation.bufferGap, liveGap = observation.liveGap;
148
+ var bufferGap = observation.bufferGap, position = observation.position, maximumPosition = observation.maximumPosition;
149
149
  var filteredReps = getFilteredRepresentations(representations, filters);
150
150
  var requests = requestsStore.getRequests();
151
151
  var _c = networkAnalyzer
@@ -206,8 +206,8 @@ export default function RepresentationEstimator(_a) {
206
206
  var chosenRepFromGuessMode = null;
207
207
  if (lowLatencyMode &&
208
208
  currentRepresentation !== null &&
209
- liveGap !== undefined &&
210
- liveGap < 40) {
209
+ context.manifest.isDynamic &&
210
+ maximumPosition - position < 40) {
211
211
  chosenRepFromGuessMode = guessBasedChooser.getGuess(representations, observation, currentRepresentation, currentBestBitrate, requests);
212
212
  }
213
213
  if (chosenRepFromGuessMode !== null &&
@@ -87,7 +87,7 @@ var Player = /** @class */ (function (_super) {
87
87
  // Workaround to support Firefox autoplay on FF 42.
88
88
  // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
89
89
  videoElement.preload = "auto";
90
- _this.version = /* PLAYER_VERSION */ "3.27.1-dev.2022040500";
90
+ _this.version = /* PLAYER_VERSION */ "3.27.1-dev.2022060300";
91
91
  _this.log = log;
92
92
  _this.state = "STOPPED";
93
93
  _this.videoElement = videoElement;
@@ -1102,13 +1102,7 @@ var Player = /** @class */ (function (_super) {
1102
1102
  if (positionWanted === undefined) {
1103
1103
  throw new Error("invalid time given");
1104
1104
  }
1105
- var seekAt = positionWanted;
1106
- if (manifest !== null && !manifest.isLive) {
1107
- var maximumTime = manifest.getMaximumPosition();
1108
- seekAt = maximumTime !== undefined ? Math.min(positionWanted, maximumTime - 0.001) :
1109
- positionWanted;
1110
- }
1111
- this.videoElement.currentTime = seekAt;
1105
+ this.videoElement.currentTime = positionWanted;
1112
1106
  return positionWanted;
1113
1107
  };
1114
1108
  /**
@@ -1691,7 +1685,7 @@ var Player = /** @class */ (function (_super) {
1691
1685
  }
1692
1686
  var manifest = this._priv_contentInfos.manifest;
1693
1687
  if (manifest !== null) {
1694
- return manifest.getMinimumPosition();
1688
+ return manifest.getMinimumSafePosition();
1695
1689
  }
1696
1690
  return null;
1697
1691
  };
@@ -1711,7 +1705,10 @@ var Player = /** @class */ (function (_super) {
1711
1705
  return this.videoElement.duration;
1712
1706
  }
1713
1707
  if (manifest !== null) {
1714
- return manifest.getMaximumPosition();
1708
+ if (!manifest.isDynamic && this.videoElement !== null) {
1709
+ return this.videoElement.duration;
1710
+ }
1711
+ return manifest.getMaximumSafePosition();
1715
1712
  }
1716
1713
  return null;
1717
1714
  };
@@ -2236,7 +2233,7 @@ var Player = /** @class */ (function (_super) {
2236
2233
  return;
2237
2234
  }
2238
2235
  this._priv_lastContentPlaybackInfos.lastPlaybackPosition = observation.position;
2239
- var maximumPosition = manifest !== null ? manifest.getMaximumPosition() :
2236
+ var maximumPosition = manifest !== null ? manifest.getMaximumSafePosition() :
2240
2237
  undefined;
2241
2238
  var positionData = {
2242
2239
  position: observation.position,
@@ -2248,12 +2245,14 @@ var Player = /** @class */ (function (_super) {
2248
2245
  0,
2249
2246
  };
2250
2247
  if (manifest !== null &&
2251
- maximumPosition !== undefined &&
2252
2248
  manifest.isLive &&
2253
2249
  observation.position > 0) {
2254
2250
  var ast = (_a = manifest.availabilityStartTime) !== null && _a !== void 0 ? _a : 0;
2255
2251
  positionData.wallClockTime = observation.position + ast;
2256
- positionData.liveGap = maximumPosition - observation.position;
2252
+ var livePosition = manifest.getLivePosition();
2253
+ if (livePosition !== undefined) {
2254
+ positionData.liveGap = livePosition - observation.position;
2255
+ }
2257
2256
  }
2258
2257
  else if (isDirectFile && this.videoElement !== null) {
2259
2258
  var startDate = getStartDate(this.videoElement);
@@ -2302,5 +2301,5 @@ var Player = /** @class */ (function (_super) {
2302
2301
  };
2303
2302
  return Player;
2304
2303
  }(EventEmitter));
2305
- Player.version = /* PLAYER_VERSION */ "3.27.1-dev.2022040500";
2304
+ Player.version = /* PLAYER_VERSION */ "3.27.1-dev.2022060300";
2306
2305
  export default Player;
@@ -668,16 +668,18 @@ function updateDecipherability(manifest, whitelistedKeyIds, blacklistedKeyIDs) {
668
668
  return representation.decipherable;
669
669
  }
670
670
  var contentKIDs = representation.contentProtections.keyIds;
671
- for (var i = 0; i < contentKIDs.length; i++) {
672
- var elt = contentKIDs[i];
673
- for (var j = 0; j < blacklistedKeyIDs.length; j++) {
674
- if (areKeyIdsEqual(blacklistedKeyIDs[j], elt.keyId)) {
675
- return false;
671
+ if (contentKIDs !== undefined) {
672
+ for (var i = 0; i < contentKIDs.length; i++) {
673
+ var elt = contentKIDs[i];
674
+ for (var j = 0; j < blacklistedKeyIDs.length; j++) {
675
+ if (areKeyIdsEqual(blacklistedKeyIDs[j], elt.keyId)) {
676
+ return false;
677
+ }
676
678
  }
677
- }
678
- for (var j = 0; j < whitelistedKeyIds.length; j++) {
679
- if (areKeyIdsEqual(whitelistedKeyIds[j], elt.keyId)) {
680
- return true;
679
+ for (var j = 0; j < whitelistedKeyIds.length; j++) {
680
+ if (areKeyIdsEqual(whitelistedKeyIds[j], elt.keyId)) {
681
+ return true;
682
+ }
681
683
  }
682
684
  }
683
685
  }
@@ -862,7 +864,7 @@ function addKeyIdsFromPeriod(set, period) {
862
864
  for (var _b = 0, _c = adaptation.representations; _b < _c.length; _b++) {
863
865
  var representation = _c[_b];
864
866
  if (representation.contentProtections !== undefined &&
865
- representation.contentProtections.keyIds.length >= -1) {
867
+ representation.contentProtections.keyIds !== undefined) {
866
868
  for (var _d = 0, _e = representation.contentProtections.keyIds; _d < _e.length; _d++) {
867
869
  var kidInf = _e[_d];
868
870
  set.add(kidInf.keyId);
@@ -129,7 +129,7 @@ var KeySessionRecord = /** @class */ (function () {
129
129
  */
130
130
  KeySessionRecord.prototype.isCompatibleWith = function (initializationData) {
131
131
  var keyIds = initializationData.keyIds;
132
- if (keyIds !== undefined) {
132
+ if (keyIds !== undefined && keyIds.length > 0) {
133
133
  if (this._keyIds !== null && areAllKeyIdsContainedIn(keyIds, this._keyIds)) {
134
134
  return true;
135
135
  }
@@ -141,6 +141,7 @@ var KeySessionRecord = /** @class */ (function () {
141
141
  };
142
142
  KeySessionRecord.prototype._checkInitializationDataCompatibility = function (initializationData) {
143
143
  if (initializationData.keyIds !== undefined &&
144
+ initializationData.keyIds.length > 0 &&
144
145
  this._initializationData.keyIds !== undefined) {
145
146
  return areAllKeyIdsContainedIn(initializationData.keyIds, this._initializationData.keyIds);
146
147
  }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Copyright 2015 CANAL+ Group
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { Observable } from "rxjs";
17
+ import Manifest from "../../manifest";
18
+ import { IReadOnlyPlaybackObserver } from "../api";
19
+ import { IStreamOrchestratorEvent } from "../stream";
20
+ import { IWarningEvent } from "./types";
21
+ /**
22
+ * Observes the position and Adaptations being played and deduce various events
23
+ * related to the available time boundaries:
24
+ * - Emit when the theoretical duration of the content becomes known or when it
25
+ * changes.
26
+ * - Emit warnings when the duration goes out of what is currently
27
+ * theoretically playable.
28
+ *
29
+ * @param {Object} manifest
30
+ * @param {Observable} streams
31
+ * @param {Object} playbackObserver
32
+ * @returns {Observable}
33
+ */
34
+ export default function ContentTimeBoundariesObserver(manifest: Manifest, streams: Observable<IStreamOrchestratorEvent>, playbackObserver: IReadOnlyPlaybackObserver<IContentTimeObserverPlaybackObservation>): Observable<IContentDurationUpdateEvent | IWarningEvent>;
35
+ /**
36
+ * Emitted when the duration of the full content (== the last playable position)
37
+ * has changed.
38
+ */
39
+ export interface IContentDurationUpdateEvent {
40
+ type: "contentDurationUpdate";
41
+ /** The new theoretical duration, `undefined` if unknown, */
42
+ value: number | undefined;
43
+ }
44
+ export interface IContentTimeObserverPlaybackObservation {
45
+ /** The position we are in the video in seconds at the time of the observation. */
46
+ position: number;
47
+ /**
48
+ * Offset, in seconds to add to `position` to obtain the starting position at
49
+ * which we actually want to download segments for.
50
+ */
51
+ wantedTimeOffset: number;
52
+ }
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Copyright 2015 CANAL+ Group
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { distinctUntilChanged, ignoreElements, map, merge as observableMerge, skipWhile, startWith, tap, } from "rxjs";
17
+ import { MediaError } from "../../errors";
18
+ import { fromEvent } from "../../utils/event_emitter";
19
+ import filterMap from "../../utils/filter_map";
20
+ import createSharedReference from "../../utils/reference";
21
+ import EVENTS from "./events_generators";
22
+ // NOTE As of now (RxJS 7.4.0), RxJS defines `ignoreElements` default
23
+ // first type parameter as `any` instead of the perfectly fine `unknown`,
24
+ // leading to linter issues, as it forbids the usage of `any`.
25
+ // This is why we're disabling the eslint rule.
26
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
27
+ /**
28
+ * Observes the position and Adaptations being played and deduce various events
29
+ * related to the available time boundaries:
30
+ * - Emit when the theoretical duration of the content becomes known or when it
31
+ * changes.
32
+ * - Emit warnings when the duration goes out of what is currently
33
+ * theoretically playable.
34
+ *
35
+ * @param {Object} manifest
36
+ * @param {Observable} streams
37
+ * @param {Object} playbackObserver
38
+ * @returns {Observable}
39
+ */
40
+ export default function ContentTimeBoundariesObserver(manifest, streams, playbackObserver) {
41
+ /**
42
+ * Allows to calculate the minimum and maximum playable position on the
43
+ * whole content.
44
+ */
45
+ var maximumPositionCalculator = new MaximumPositionCalculator(manifest);
46
+ // trigger warnings when the wanted time is before or after the manifest's
47
+ // segments
48
+ var outOfManifest$ = playbackObserver.observe(true).pipe(filterMap(function (_a) {
49
+ var position = _a.position, wantedTimeOffset = _a.wantedTimeOffset;
50
+ var offsetedPosition = wantedTimeOffset + position;
51
+ if (offsetedPosition < manifest.getMinimumSafePosition()) {
52
+ var warning = new MediaError("MEDIA_TIME_BEFORE_MANIFEST", "The current position is behind the " +
53
+ "earliest time announced in the Manifest.");
54
+ return EVENTS.warning(warning);
55
+ }
56
+ else if (offsetedPosition > maximumPositionCalculator.getCurrentMaximumPosition()) {
57
+ var warning = new MediaError("MEDIA_TIME_AFTER_MANIFEST", "The current position is after the latest " +
58
+ "time announced in the Manifest.");
59
+ return EVENTS.warning(warning);
60
+ }
61
+ return null;
62
+ }, null));
63
+ /**
64
+ * Contains the content duration according to the last audio and video
65
+ * Adaptation chosen for the last Period.
66
+ * `undefined` if unknown yet.
67
+ */
68
+ var contentDuration = createSharedReference(undefined);
69
+ var updateDurationOnManifestUpdate$ = fromEvent(manifest, "manifestUpdate").pipe(startWith(null), tap(function () {
70
+ if (!manifest.isDynamic) {
71
+ var maxPos = maximumPositionCalculator.getCurrentMaximumPosition();
72
+ contentDuration.setValue(maxPos);
73
+ }
74
+ else {
75
+ // TODO handle finished dynamic contents?
76
+ contentDuration.setValue(undefined);
77
+ }
78
+ }), ignoreElements());
79
+ var updateDurationAndTimeBoundsOnTrackChange$ = streams.pipe(tap(function (message) {
80
+ if (message.type === "adaptationChange") {
81
+ var lastPeriod = manifest.periods[manifest.periods.length - 1];
82
+ if (message.value.period.id === (lastPeriod === null || lastPeriod === void 0 ? void 0 : lastPeriod.id)) {
83
+ if (message.value.type === "audio") {
84
+ maximumPositionCalculator
85
+ .updateLastAudioAdaptation(message.value.adaptation);
86
+ if (!manifest.isDynamic) {
87
+ contentDuration.setValue(maximumPositionCalculator.getCurrentMaximumPosition());
88
+ }
89
+ }
90
+ else if (message.value.type === "video") {
91
+ maximumPositionCalculator
92
+ .updateLastVideoAdaptation(message.value.adaptation);
93
+ if (!manifest.isDynamic) {
94
+ contentDuration.setValue(maximumPositionCalculator.getCurrentMaximumPosition());
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }), ignoreElements());
100
+ return observableMerge(updateDurationOnManifestUpdate$, updateDurationAndTimeBoundsOnTrackChange$, outOfManifest$, contentDuration.asObservable().pipe(skipWhile(function (val) { return val === undefined; }), distinctUntilChanged(), map(function (value) { return ({ type: "contentDurationUpdate", value: value }); })));
101
+ }
102
+ /**
103
+ * Calculate the last position from the last chosen audio and video Adaptations
104
+ * for the last Period (or a default one, if no Adaptations has been chosen).
105
+ * @class MaximumPositionCalculator
106
+ */
107
+ var MaximumPositionCalculator = /** @class */ (function () {
108
+ /**
109
+ * @param {Object} manifest
110
+ */
111
+ function MaximumPositionCalculator(manifest) {
112
+ this._manifest = manifest;
113
+ this._lastAudioAdaptation = undefined;
114
+ this._lastVideoAdaptation = undefined;
115
+ }
116
+ /**
117
+ * Update the last known audio Adaptation for the last Period.
118
+ * If no Adaptation has been set, it should be set to `null`.
119
+ *
120
+ * Allows to calculate the maximum position more precizely in
121
+ * `getCurrentMaximumPosition`.
122
+ * @param {Object|null} adaptation
123
+ */
124
+ MaximumPositionCalculator.prototype.updateLastAudioAdaptation = function (adaptation) {
125
+ this._lastAudioAdaptation = adaptation;
126
+ };
127
+ /**
128
+ * Update the last known video Adaptation for the last Period.
129
+ * If no Adaptation has been set, it should be set to `null`.
130
+ *
131
+ * Allows to calculate the maximum position more precizely in
132
+ * `getCurrentMaximumPosition`.
133
+ * @param {Object|null} adaptation
134
+ */
135
+ MaximumPositionCalculator.prototype.updateLastVideoAdaptation = function (adaptation) {
136
+ this._lastVideoAdaptation = adaptation;
137
+ };
138
+ /**
139
+ * Returns an estimate of the maximum position reachable under the current
140
+ * circumstances.
141
+ * @returns {number}
142
+ */
143
+ MaximumPositionCalculator.prototype.getCurrentMaximumPosition = function () {
144
+ var _a;
145
+ if (this._manifest.isDynamic) {
146
+ return (_a = this._manifest.getLivePosition()) !== null && _a !== void 0 ? _a : this._manifest.getMaximumSafePosition();
147
+ }
148
+ if (this._lastVideoAdaptation === undefined ||
149
+ this._lastAudioAdaptation === undefined) {
150
+ return this._manifest.getMaximumSafePosition();
151
+ }
152
+ else if (this._lastAudioAdaptation === null) {
153
+ if (this._lastVideoAdaptation === null) {
154
+ return this._manifest.getMaximumSafePosition();
155
+ }
156
+ else {
157
+ var lastVideoPosition = getLastPositionFromAdaptation(this._lastVideoAdaptation);
158
+ if (typeof lastVideoPosition !== "number") {
159
+ return this._manifest.getMaximumSafePosition();
160
+ }
161
+ return lastVideoPosition;
162
+ }
163
+ }
164
+ else if (this._lastVideoAdaptation === null) {
165
+ var lastAudioPosition = getLastPositionFromAdaptation(this._lastAudioAdaptation);
166
+ if (typeof lastAudioPosition !== "number") {
167
+ return this._manifest.getMaximumSafePosition();
168
+ }
169
+ return lastAudioPosition;
170
+ }
171
+ else {
172
+ var lastAudioPosition = getLastPositionFromAdaptation(this._lastAudioAdaptation);
173
+ var lastVideoPosition = getLastPositionFromAdaptation(this._lastVideoAdaptation);
174
+ if (typeof lastAudioPosition !== "number" ||
175
+ typeof lastVideoPosition !== "number") {
176
+ return this._manifest.getMaximumSafePosition();
177
+ }
178
+ else {
179
+ return Math.min(lastAudioPosition, lastVideoPosition);
180
+ }
181
+ }
182
+ };
183
+ return MaximumPositionCalculator;
184
+ }());
185
+ /**
186
+ * Returns "last time of reference" from the adaptation given.
187
+ * `undefined` if a time could not be found.
188
+ * Null if the Adaptation has no segments (it could be that it didn't started or
189
+ * that it already finished for example).
190
+ *
191
+ * We consider the earliest last time from every representations in the given
192
+ * adaptation.
193
+ * @param {Object} adaptation
194
+ * @returns {Number|undefined|null}
195
+ */
196
+ function getLastPositionFromAdaptation(adaptation) {
197
+ var representations = adaptation.representations;
198
+ var min = null;
199
+ /**
200
+ * Some Manifest parsers use the exact same `IRepresentationIndex` reference
201
+ * for each Representation of a given Adaptation, because in the actual source
202
+ * Manifest file, indexing data is often defined at Adaptation-level.
203
+ * This variable allows to optimize the logic here when this is the case.
204
+ */
205
+ var lastIndex;
206
+ for (var i = 0; i < representations.length; i++) {
207
+ if (representations[i].index !== lastIndex) {
208
+ lastIndex = representations[i].index;
209
+ var lastPosition = representations[i].index.getLastPosition();
210
+ if (lastPosition === undefined) { // we cannot tell
211
+ return undefined;
212
+ }
213
+ if (lastPosition !== null) {
214
+ min = min == null ? lastPosition :
215
+ Math.min(min, lastPosition);
216
+ }
217
+ }
218
+ }
219
+ if (min === null) { // It means that all positions were null === no segments (yet?)
220
+ return null;
221
+ }
222
+ return min;
223
+ }
@@ -25,10 +25,23 @@ export default function createStreamPlaybackObserver(manifest, playbackObserver,
25
25
  return playbackObserver.deriveReadOnlyObserver(function mapObservable(observation$) {
26
26
  return observableCombineLatest([observation$, speed.asObservable()]).pipe(map(function (_a) {
27
27
  var observation = _a[0], lastSpeed = _a[1];
28
+ var wantedTimeOffset = 0;
29
+ if (!initialSeekPerformed.getValue()) {
30
+ wantedTimeOffset = startTime - observation.position;
31
+ }
32
+ else if (!manifest.isDynamic || manifest.isLastPeriodKnown) {
33
+ var lastPeriod = manifest.periods[manifest.periods.length - 1];
34
+ if (lastPeriod !== undefined &&
35
+ lastPeriod.end !== undefined &&
36
+ observation.position > lastPeriod.end) {
37
+ wantedTimeOffset = lastPeriod.end -
38
+ observation.position -
39
+ 1;
40
+ }
41
+ }
28
42
  return {
29
- liveGap: manifest.isLive ?
30
- manifest.getMaximumPosition() - observation.position :
31
- undefined,
43
+ // TODO more exact according to the current Adaptation chosen?
44
+ maximumPosition: manifest.getMaximumSafePosition(),
32
45
  position: observation.position,
33
46
  duration: observation.duration,
34
47
  isPaused: initialPlayPerformed.getValue() ? observation.paused :
@@ -41,9 +54,7 @@ export default function createStreamPlaybackObserver(manifest, playbackObserver,
41
54
  // initial position, the currentTime will most probably be 0 where the
42
55
  // effective starting position will be _startTime_.
43
56
  // Thus we initially set a wantedTimeOffset equal to startTime.
44
- wantedTimeOffset: initialSeekPerformed.getValue() ?
45
- 0 :
46
- startTime - observation.position,
57
+ wantedTimeOffset: wantedTimeOffset,
47
58
  };
48
59
  }));
49
60
  });