rx-player 3.27.1-dev.2022041500 → 3.27.1-dev.2022051100

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 (27) hide show
  1. package/CHANGELOG.md +11 -5
  2. package/VERSION +1 -1
  3. package/dist/_esm5.processed/core/api/public_api.js +2 -2
  4. package/dist/_esm5.processed/core/decrypt/content_decryptor.js +12 -10
  5. package/dist/_esm5.processed/core/decrypt/utils/key_session_record.js +2 -1
  6. package/dist/_esm5.processed/core/init/throw_on_media_error.js +19 -10
  7. package/dist/_esm5.processed/manifest/representation.js +4 -4
  8. package/dist/_esm5.processed/parsers/manifest/dash/common/flatten_overlapping_periods.js +11 -1
  9. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.d.ts +2 -0
  10. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.js +9 -2
  11. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +10 -3
  12. package/dist/_esm5.processed/parsers/manifest/types.d.ts +7 -2
  13. package/dist/_esm5.processed/parsers/texttracks/ttml/html/generate_css_test_outline.js +14 -4
  14. package/dist/rx-player.js +85 -33
  15. package/dist/rx-player.min.js +1 -1
  16. package/package.json +1 -1
  17. package/sonar-project.properties +1 -1
  18. package/src/core/api/public_api.ts +2 -2
  19. package/src/core/decrypt/content_decryptor.ts +12 -10
  20. package/src/core/decrypt/utils/key_session_record.ts +2 -1
  21. package/src/core/init/throw_on_media_error.ts +25 -15
  22. package/src/manifest/representation.ts +2 -2
  23. package/src/parsers/manifest/dash/common/flatten_overlapping_periods.ts +10 -1
  24. package/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +12 -2
  25. package/src/parsers/manifest/dash/common/parse_representations.ts +9 -3
  26. package/src/parsers/manifest/types.ts +7 -2
  27. package/src/parsers/texttracks/ttml/html/generate_css_test_outline.ts +15 -4
package/CHANGELOG.md CHANGED
@@ -1,16 +1,22 @@
1
1
  # Changelog
2
2
 
3
- ## v3.27.1-dev.2022041500 (2022-04-15)
3
+ ## v3.27.1-dev.2022051100 (2022-05-11)
4
4
 
5
5
  ### Bug fixes
6
6
 
7
- - Use the first compatible codec of the current AdaptationSet when creating a SourceBuffer [#1094]
8
- - DASH: fix wrong segment estimates on some SegmentTimeline-based contents where the last segment has a negative `S@d` attribute set in the MPD [#1098]
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.
9
14
 
10
15
  ### Other improvements
11
16
 
12
- - Update duration of a content based on the last chosen tracks [#1102]
13
- - If seeking after the last potential position, load last segments before ending [#1097]
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]
19
+
14
20
 
15
21
  ## v3.27.0 (2022-03-31)
16
22
 
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.27.1-dev.2022041500
1
+ 3.27.1-dev.2022051100
@@ -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.2022041500";
90
+ _this.version = /* PLAYER_VERSION */ "3.27.1-dev.2022051100";
91
91
  _this.log = log;
92
92
  _this.state = "STOPPED";
93
93
  _this.videoElement = videoElement;
@@ -2301,5 +2301,5 @@ var Player = /** @class */ (function (_super) {
2301
2301
  };
2302
2302
  return Player;
2303
2303
  }(EventEmitter));
2304
- Player.version = /* PLAYER_VERSION */ "3.27.1-dev.2022041500";
2304
+ Player.version = /* PLAYER_VERSION */ "3.27.1-dev.2022051100";
2305
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
  }
@@ -15,6 +15,7 @@
15
15
  */
16
16
  import { fromEvent as observableFromEvent, mergeMap, } from "rxjs";
17
17
  import { MediaError } from "../../errors";
18
+ import isNullOrUndefined from "../../utils/is_null_or_undefined";
18
19
  /**
19
20
  * Returns an observable which throws the right MediaError as soon an "error"
20
21
  * event is received through the media element.
@@ -24,22 +25,30 @@ import { MediaError } from "../../errors";
24
25
  export default function throwOnMediaError(mediaElement) {
25
26
  return observableFromEvent(mediaElement, "error")
26
27
  .pipe(mergeMap(function () {
27
- var errorCode = mediaElement.error == null ? 0 :
28
- mediaElement.error.code;
28
+ var mediaError = mediaElement.error;
29
+ var errorCode;
30
+ var errorMessage;
31
+ if (!isNullOrUndefined(mediaError)) {
32
+ errorCode = mediaError.code;
33
+ errorMessage = mediaError.message;
34
+ }
29
35
  switch (errorCode) {
30
36
  case 1:
31
- throw new MediaError("MEDIA_ERR_ABORTED", "The fetching of the associated resource was aborted " +
32
- "by the user's request.");
37
+ errorMessage = errorMessage !== null && errorMessage !== void 0 ? errorMessage : "The fetching of the associated resource was aborted by the user's request.";
38
+ throw new MediaError("MEDIA_ERR_ABORTED", errorMessage);
33
39
  case 2:
34
- throw new MediaError("MEDIA_ERR_NETWORK", "A network error occurred which prevented the media " +
35
- "from being successfully fetched");
40
+ errorMessage = errorMessage !== null && errorMessage !== void 0 ? errorMessage : "A network error occurred which prevented the media from being " +
41
+ "successfully fetched";
42
+ throw new MediaError("MEDIA_ERR_NETWORK", errorMessage);
36
43
  case 3:
37
- throw new MediaError("MEDIA_ERR_DECODE", "An error occurred while trying to decode the media " +
38
- "resource");
44
+ errorMessage = errorMessage !== null && errorMessage !== void 0 ? errorMessage : "An error occurred while trying to decode the media resource";
45
+ throw new MediaError("MEDIA_ERR_DECODE", errorMessage);
39
46
  case 4:
40
- throw new MediaError("MEDIA_ERR_SRC_NOT_SUPPORTED", "The media resource has been found to be unsuitable.");
47
+ errorMessage = errorMessage !== null && errorMessage !== void 0 ? errorMessage : "The media resource has been found to be unsuitable.";
48
+ throw new MediaError("MEDIA_ERR_SRC_NOT_SUPPORTED", errorMessage);
41
49
  default:
42
- throw new MediaError("MEDIA_ERR_UNKNOWN", "The HTMLMediaElement errored due to an unknown reason.");
50
+ errorMessage = errorMessage !== null && errorMessage !== void 0 ? errorMessage : "The HTMLMediaElement errored due to an unknown reason.";
51
+ throw new MediaError("MEDIA_ERR_UNKNOWN", errorMessage);
43
52
  }
44
53
  }));
45
54
  }
@@ -82,7 +82,7 @@ var Representation = /** @class */ (function () {
82
82
  * @returns {Array.<Object>}
83
83
  */
84
84
  Representation.prototype.getEncryptionData = function (drmSystemId) {
85
- var _a;
85
+ var _a, _b;
86
86
  var allInitData = this.getAllEncryptionData();
87
87
  var filtered = [];
88
88
  for (var i = 0; i < allInitData.length; i++) {
@@ -91,7 +91,7 @@ var Representation = /** @class */ (function () {
91
91
  for (var j = 0; j < initData.values.length; j++) {
92
92
  if (initData.values[j].systemId.toLowerCase() === drmSystemId.toLowerCase()) {
93
93
  if (!createdObjForType) {
94
- var keyIds = (_a = this.contentProtections) === null || _a === void 0 ? void 0 : _a.keyIds.map(function (val) { return val.keyId; });
94
+ var keyIds = (_b = (_a = this.contentProtections) === null || _a === void 0 ? void 0 : _a.keyIds) === null || _b === void 0 ? void 0 : _b.map(function (val) { return val.keyId; });
95
95
  filtered.push({ type: initData.type, keyIds: keyIds, values: [initData.values[j]] });
96
96
  createdObjForType = true;
97
97
  }
@@ -130,12 +130,12 @@ var Representation = /** @class */ (function () {
130
130
  * @returns {Array.<Object>}
131
131
  */
132
132
  Representation.prototype.getAllEncryptionData = function () {
133
- var _a;
133
+ var _a, _b;
134
134
  if (this.contentProtections === undefined ||
135
135
  this.contentProtections.initData.length === 0) {
136
136
  return [];
137
137
  }
138
- var keyIds = (_a = this.contentProtections) === null || _a === void 0 ? void 0 : _a.keyIds.map(function (val) { return val.keyId; });
138
+ var keyIds = (_b = (_a = this.contentProtections) === null || _a === void 0 ? void 0 : _a.keyIds) === null || _b === void 0 ? void 0 : _b.map(function (val) { return val.keyId; });
139
139
  return this.contentProtections.initData.map(function (x) {
140
140
  return { type: x.type, keyIds: keyIds, values: x.values };
141
141
  });
@@ -53,7 +53,17 @@ export default function flattenOverlappingPeriods(parsedPeriods) {
53
53
  log.warn("DASH: Updating overlapping Periods.", lastFlattenedPeriod === null || lastFlattenedPeriod === void 0 ? void 0 : lastFlattenedPeriod.start, parsedPeriod.start);
54
54
  lastFlattenedPeriod.duration = parsedPeriod.start - lastFlattenedPeriod.start;
55
55
  lastFlattenedPeriod.end = parsedPeriod.start;
56
- if (lastFlattenedPeriod.duration <= 0) {
56
+ if (lastFlattenedPeriod.duration > 0) {
57
+ // Note: Calling `break` to quit the while loop should theoritically be
58
+ // unnecessary as the previous operations should ensure we do not re-enter
59
+ // the loop's condition.
60
+ // Yet we dit encounter infinite loops without it because of float-related
61
+ // rounding errors.
62
+ break;
63
+ }
64
+ else {
65
+ // `lastFlattenedPeriod` has now a negative or `0` duration.
66
+ // Remove it, consider the next Period in its place, and re-start the loop.
57
67
  flattenedPeriods.pop();
58
68
  lastFlattenedPeriod = flattenedPeriods[flattenedPeriods.length - 1];
59
69
  }
@@ -166,6 +166,8 @@ export default class TimelineRepresentationIndex implements IRepresentationIndex
166
166
  private _lastUpdate;
167
167
  /** Absolute start of the period, timescaled and converted to index time. */
168
168
  private _scaledPeriodStart;
169
+ /** Actual un-scaled start of the Period as indicated in the MPD. */
170
+ private _periodStart;
169
171
  /** Absolute end of the period, timescaled and converted to index time. */
170
172
  private _scaledPeriodEnd;
171
173
  /** Whether this RepresentationIndex can change over time. */
@@ -73,6 +73,7 @@ var TimelineRepresentationIndex = /** @class */ (function () {
73
73
  mediaURLs: createIndexURLs(urlSources, index.media, representationId, representationBitrate),
74
74
  startNumber: index.startNumber,
75
75
  timeline: (_c = index.timeline) !== null && _c !== void 0 ? _c : null, timescale: timescale };
76
+ this._periodStart = periodStart;
76
77
  this._scaledPeriodStart = toIndexTime(periodStart, this._index);
77
78
  this._scaledPeriodEnd = periodEnd === undefined ? undefined :
78
79
  toIndexTime(periodEnd, this._index);
@@ -201,6 +202,7 @@ var TimelineRepresentationIndex = /** @class */ (function () {
201
202
  this._index = newIndex._index;
202
203
  this._isDynamic = newIndex._isDynamic;
203
204
  this._scaledPeriodStart = newIndex._scaledPeriodStart;
205
+ this._periodStart = newIndex._periodStart;
204
206
  this._scaledPeriodEnd = newIndex._scaledPeriodEnd;
205
207
  this._lastUpdate = newIndex._lastUpdate;
206
208
  this._manifestBoundsCalculator = newIndex._manifestBoundsCalculator;
@@ -224,6 +226,7 @@ var TimelineRepresentationIndex = /** @class */ (function () {
224
226
  }
225
227
  this._isDynamic = newIndex._isDynamic;
226
228
  this._scaledPeriodStart = newIndex._scaledPeriodStart;
229
+ this._periodStart = newIndex._periodStart;
227
230
  this._scaledPeriodEnd = newIndex._scaledPeriodEnd;
228
231
  this._lastUpdate = newIndex._lastUpdate;
229
232
  this._isLastPeriod = newIndex._isLastPeriod;
@@ -279,6 +282,9 @@ var TimelineRepresentationIndex = /** @class */ (function () {
279
282
  if (this._index.timeline === null) {
280
283
  this._index.timeline = this._getTimeline();
281
284
  }
285
+ if (!this._isDynamic) {
286
+ return;
287
+ }
282
288
  var firstPosition = this._manifestBoundsCalculator.estimateMinimumBound();
283
289
  if (firstPosition == null) {
284
290
  return; // we don't know yet
@@ -327,11 +333,12 @@ var TimelineRepresentationIndex = /** @class */ (function () {
327
333
  }
328
334
  var newElements = this._parseTimeline();
329
335
  this._parseTimeline = null; // Free memory
336
+ var actualPeriodStart = this._periodStart * this._index.timescale;
330
337
  var MIN_DASH_S_ELEMENTS_TO_PARSE_UNSAFELY = config.getCurrent().MIN_DASH_S_ELEMENTS_TO_PARSE_UNSAFELY;
331
338
  if (this._unsafelyBaseOnPreviousIndex === null ||
332
339
  newElements.length < MIN_DASH_S_ELEMENTS_TO_PARSE_UNSAFELY) {
333
340
  // Just completely parse the current timeline
334
- return constructTimelineFromElements(newElements, this._scaledPeriodStart);
341
+ return constructTimelineFromElements(newElements, actualPeriodStart);
335
342
  }
336
343
  // Construct previously parsed timeline if not already done
337
344
  var prevTimeline;
@@ -343,7 +350,7 @@ var TimelineRepresentationIndex = /** @class */ (function () {
343
350
  prevTimeline = this._unsafelyBaseOnPreviousIndex._index.timeline;
344
351
  }
345
352
  this._unsafelyBaseOnPreviousIndex = null; // Free memory
346
- return constructTimelineFromPreviousTimeline(newElements, prevTimeline, this._scaledPeriodStart);
353
+ return constructTimelineFromPreviousTimeline(newElements, prevTimeline, actualPeriodStart);
347
354
  };
348
355
  return TimelineRepresentationIndex;
349
356
  }());
@@ -175,7 +175,13 @@ export default function parseRepresentations(representationsIR, adaptation, cont
175
175
  .toLowerCase();
176
176
  }
177
177
  if (cp.attributes.keyId !== undefined && cp.attributes.keyId.length > 0) {
178
- acc.keyIds.push({ keyId: cp.attributes.keyId, systemId: systemId });
178
+ var kidObj = { keyId: cp.attributes.keyId, systemId: systemId };
179
+ if (acc.keyIds === undefined) {
180
+ acc.keyIds = [kidObj];
181
+ }
182
+ else {
183
+ acc.keyIds.push(kidObj);
184
+ }
179
185
  }
180
186
  if (systemId !== undefined) {
181
187
  var cencPssh = cp.children.cencPssh;
@@ -195,9 +201,10 @@ export default function parseRepresentations(representationsIR, adaptation, cont
195
201
  }
196
202
  }
197
203
  return acc;
198
- }, { keyIds: [], initData: [] });
204
+ }, { keyIds: undefined, initData: [] });
199
205
  if (Object.keys(contentProtections.initData).length > 0 ||
200
- contentProtections.keyIds.length > 0) {
206
+ (contentProtections.keyIds !== undefined &&
207
+ contentProtections.keyIds.length > 0)) {
201
208
  parsedRepresentation.contentProtections = contentProtections;
202
209
  }
203
210
  }
@@ -67,8 +67,13 @@ export interface IContentProtectionInitData {
67
67
  */
68
68
  /** Describes every encryption protection parsed for a given media. */
69
69
  export interface IContentProtections {
70
- /** The different encryption key IDs associated with that content. */
71
- keyIds: IContentProtectionKID[];
70
+ /**
71
+ * The different encryption key IDs associated with that content.
72
+ *
73
+ * `undefined` if the key id(s) associated with that content may exist but are
74
+ * not known.
75
+ */
76
+ keyIds: IContentProtectionKID[] | undefined;
72
77
  /** The different encryption initialization data associated with that content. */
73
78
  initData: IContentProtectionInitData[];
74
79
  }
@@ -13,6 +13,7 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
+ import isNonEmptyString from "../../../../utils/is_non_empty_string";
16
17
  /**
17
18
  * Try to replicate the textOutline TTML style property into CSS.
18
19
  *
@@ -24,8 +25,17 @@
24
25
  * @returns {string}
25
26
  */
26
27
  export default function generateCSSTextOutline(color, thickness) {
27
- return "-1px -1px ".concat(thickness, " ").concat(color, ",") +
28
- "1px -1px ".concat(thickness, " ").concat(color, ",") +
29
- "-1px 1px ".concat(thickness, " ").concat(color, ",") +
30
- "1px 1px ".concat(thickness, " ").concat(color);
28
+ var thick = thickness;
29
+ if (isNonEmptyString(thickness) && thickness.trim().endsWith("%")) {
30
+ // As em and % are basically equivalent in CSS
31
+ // (they both are relative to the font-size
32
+ // of the current element)
33
+ // We convert the non supported % into the supported em
34
+ thick = thickness.trim().slice(0, -1);
35
+ thick = (parseInt(thick, 10) / 100).toString() + "em";
36
+ }
37
+ return "-1px -1px ".concat(thick, " ").concat(color, ",") +
38
+ "1px -1px ".concat(thick, " ").concat(color, ",") +
39
+ "-1px 1px ".concat(thick, " ").concat(color, ",") +
40
+ "1px 1px ".concat(thick, " ").concat(color);
31
41
  }