rx-player 4.0.0-dev.2023110700 → 4.0.0-dev.2023111400

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 (102) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/VERSION +1 -1
  3. package/dist/_esm5.processed/core/api/option_utils.d.ts +2 -0
  4. package/dist/_esm5.processed/core/api/option_utils.js +6 -0
  5. package/dist/_esm5.processed/core/api/public_api.d.ts +2 -1
  6. package/dist/_esm5.processed/core/api/public_api.js +14 -4
  7. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/text_track_cues_store.js +54 -6
  8. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/utils.d.ts +2 -1
  9. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/utils.js +19 -2
  10. package/dist/_esm5.processed/manifest/representation.js +18 -5
  11. package/dist/_esm5.processed/parsers/manifest/dash/common/convert_supplemental_codecs.d.ts +17 -0
  12. package/dist/_esm5.processed/parsers/manifest/dash/common/convert_supplemental_codecs.js +26 -0
  13. package/dist/_esm5.processed/parsers/manifest/dash/common/flatten_overlapping_periods.js +5 -0
  14. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +29 -17
  15. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/node_parsers/AdaptationSet.js +3 -0
  16. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/node_parsers/Representation.js +3 -0
  17. package/dist/_esm5.processed/parsers/manifest/dash/node_parser_types.d.ts +2 -0
  18. package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/generators/AdaptationSet.js +4 -0
  19. package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/generators/Representation.js +4 -0
  20. package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/types.d.ts +2 -1
  21. package/dist/_esm5.processed/parsers/manifest/types.d.ts +1 -0
  22. package/dist/commonjs/compat/patch_webkit_source_buffer.js +2 -2
  23. package/dist/commonjs/core/api/option_utils.d.ts +2 -0
  24. package/dist/commonjs/core/api/option_utils.js +6 -0
  25. package/dist/commonjs/core/api/public_api.d.ts +2 -1
  26. package/dist/commonjs/core/api/public_api.js +14 -4
  27. package/dist/commonjs/core/segment_buffers/implementations/text/html/text_track_cues_store.js +54 -6
  28. package/dist/commonjs/core/segment_buffers/implementations/text/html/utils.d.ts +2 -1
  29. package/dist/commonjs/core/segment_buffers/implementations/text/html/utils.js +19 -2
  30. package/dist/commonjs/core/stream/adaptation/adaptation_stream.js +2 -2
  31. package/dist/commonjs/core/stream/orchestrator/stream_orchestrator.js +3 -3
  32. package/dist/commonjs/core/stream/period/period_stream.js +2 -2
  33. package/dist/commonjs/manifest/representation.js +18 -5
  34. package/dist/commonjs/parsers/manifest/dash/common/convert_supplemental_codecs.d.ts +17 -0
  35. package/dist/commonjs/parsers/manifest/dash/common/convert_supplemental_codecs.js +30 -0
  36. package/dist/commonjs/parsers/manifest/dash/common/flatten_overlapping_periods.js +5 -0
  37. package/dist/commonjs/parsers/manifest/dash/common/parse_representations.js +29 -17
  38. package/dist/commonjs/parsers/manifest/dash/js-parser/node_parsers/AdaptationSet.js +3 -0
  39. package/dist/commonjs/parsers/manifest/dash/js-parser/node_parsers/Representation.js +3 -0
  40. package/dist/commonjs/parsers/manifest/dash/node_parser_types.d.ts +2 -0
  41. package/dist/commonjs/parsers/manifest/dash/wasm-parser/ts/generators/AdaptationSet.js +4 -0
  42. package/dist/commonjs/parsers/manifest/dash/wasm-parser/ts/generators/Representation.js +4 -0
  43. package/dist/commonjs/parsers/manifest/dash/wasm-parser/ts/types.d.ts +2 -1
  44. package/dist/commonjs/parsers/manifest/types.d.ts +1 -0
  45. package/dist/commonjs/utils/queue_microtask.d.ts +2 -0
  46. package/dist/commonjs/utils/queue_microtask.js +7 -0
  47. package/dist/es2017/compat/patch_webkit_source_buffer.js +2 -2
  48. package/dist/es2017/core/api/option_utils.d.ts +2 -0
  49. package/dist/es2017/core/api/option_utils.js +6 -0
  50. package/dist/es2017/core/api/public_api.d.ts +2 -1
  51. package/dist/es2017/core/api/public_api.js +13 -3
  52. package/dist/es2017/core/segment_buffers/implementations/text/html/text_track_cues_store.js +54 -6
  53. package/dist/es2017/core/segment_buffers/implementations/text/html/utils.d.ts +2 -1
  54. package/dist/es2017/core/segment_buffers/implementations/text/html/utils.js +18 -2
  55. package/dist/es2017/core/stream/adaptation/adaptation_stream.js +2 -2
  56. package/dist/es2017/core/stream/orchestrator/stream_orchestrator.js +3 -3
  57. package/dist/es2017/core/stream/period/period_stream.js +2 -2
  58. package/dist/es2017/manifest/representation.js +18 -5
  59. package/dist/es2017/parsers/manifest/dash/common/convert_supplemental_codecs.d.ts +17 -0
  60. package/dist/es2017/parsers/manifest/dash/common/convert_supplemental_codecs.js +26 -0
  61. package/dist/es2017/parsers/manifest/dash/common/flatten_overlapping_periods.js +5 -0
  62. package/dist/es2017/parsers/manifest/dash/common/parse_representations.js +29 -17
  63. package/dist/es2017/parsers/manifest/dash/js-parser/node_parsers/AdaptationSet.js +3 -0
  64. package/dist/es2017/parsers/manifest/dash/js-parser/node_parsers/Representation.js +3 -0
  65. package/dist/es2017/parsers/manifest/dash/node_parser_types.d.ts +2 -0
  66. package/dist/es2017/parsers/manifest/dash/wasm-parser/ts/generators/AdaptationSet.js +4 -0
  67. package/dist/es2017/parsers/manifest/dash/wasm-parser/ts/generators/Representation.js +4 -0
  68. package/dist/es2017/parsers/manifest/dash/wasm-parser/ts/types.d.ts +2 -1
  69. package/dist/es2017/parsers/manifest/types.d.ts +1 -0
  70. package/dist/es2017/utils/queue_microtask.d.ts +2 -0
  71. package/dist/es2017/utils/queue_microtask.js +5 -0
  72. package/dist/mpd-parser.wasm +0 -0
  73. package/dist/rx-player.js +179 -118
  74. package/dist/rx-player.min.js +1 -1
  75. package/package.json +1 -4
  76. package/sonar-project.properties +1 -1
  77. package/src/compat/patch_webkit_source_buffer.ts +2 -2
  78. package/src/core/api/option_utils.ts +8 -0
  79. package/src/core/api/public_api.ts +15 -3
  80. package/src/core/segment_buffers/implementations/text/html/__tests__/utils.test.ts +15 -0
  81. package/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts +57 -6
  82. package/src/core/segment_buffers/implementations/text/html/utils.ts +19 -2
  83. package/src/core/stream/adaptation/adaptation_stream.ts +2 -2
  84. package/src/core/stream/orchestrator/stream_orchestrator.ts +3 -3
  85. package/src/core/stream/period/period_stream.ts +2 -2
  86. package/src/manifest/representation.ts +19 -6
  87. package/src/parsers/manifest/dash/common/__tests__/convert_supplemental_codecs.test.ts +37 -0
  88. package/src/parsers/manifest/dash/common/__tests__/flatten_overlapping_period.test.ts +20 -0
  89. package/src/parsers/manifest/dash/common/convert_supplemental_codecs.ts +32 -0
  90. package/src/parsers/manifest/dash/common/flatten_overlapping_periods.ts +5 -0
  91. package/src/parsers/manifest/dash/common/parse_representations.ts +30 -17
  92. package/src/parsers/manifest/dash/js-parser/node_parsers/AdaptationSet.ts +4 -0
  93. package/src/parsers/manifest/dash/js-parser/node_parsers/Representation.ts +4 -0
  94. package/src/parsers/manifest/dash/node_parser_types.ts +2 -0
  95. package/src/parsers/manifest/dash/wasm-parser/rs/events.rs +2 -0
  96. package/src/parsers/manifest/dash/wasm-parser/rs/processor/attributes.rs +2 -0
  97. package/src/parsers/manifest/dash/wasm-parser/ts/generators/AdaptationSet.ts +4 -0
  98. package/src/parsers/manifest/dash/wasm-parser/ts/generators/Representation.ts +4 -0
  99. package/src/parsers/manifest/dash/wasm-parser/ts/types.ts +2 -0
  100. package/src/parsers/manifest/types.ts +2 -0
  101. package/src/utils/queue_microtask.ts +7 -0
  102. package/src/typings/next-tick.d.ts +0 -23
package/CHANGELOG.md CHANGED
@@ -1,15 +1,23 @@
1
1
  # Changelog
2
2
 
3
- ## v4.0.0-dev.2023110700 (2023-11-07)
3
+ ## v4.0.0-dev.2023111400 (2023-11-14)
4
+
5
+ ### Features
6
+
7
+ - Add the possibility to set a new `keySystems` option on the `reload` API [#1308]
4
8
 
5
9
  ### Bug fixes
6
10
 
11
+ - Fix subtitles "blinking" in some specific conditions, especially with some DASH low-latency contents [#1314]
12
+ - DASH: Fix Period overlap resolution logic for when the first Period is removed [#1311]
7
13
  - Fix import of the `LOCAL_MANIFEST` experimental feature
8
14
  - Smooth: Rely on a defined `segmentLoader` when playing smooth streaming contents.
9
15
 
10
16
  ### Other improvements
11
17
 
12
18
  - Provide both commonJS and ES6-style exports to improve compatibilities with applications
19
+ - DASH: rely on SCTE214 `supplementalCodecs` instead of `codecs` if it's supported to better support backward compatible Dolby Vision contents [#1307]
20
+ - Remove remaining RxPlayer dependency removing possibility of some application-side bundling errors [#1312]
13
21
 
14
22
 
15
23
  ## v4.0.0-beta.3 (2023-10-19)
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.0.0-dev.2023110700
1
+ 4.0.0-dev.2023111400
@@ -125,6 +125,8 @@ declare function checkReloadOptions(options?: {
125
125
  position?: number;
126
126
  relative?: number;
127
127
  };
128
+ keySystems?: IKeySystemOption[];
129
+ autoPlay?: boolean;
128
130
  }): void;
129
131
  /**
130
132
  * Parse options given to loadVideo and set default options as found
@@ -255,6 +255,12 @@ function checkReloadOptions(options) {
255
255
  ((_d = options === null || options === void 0 ? void 0 : options.reloadAt) === null || _d === void 0 ? void 0 : _d.relative) !== undefined) {
256
256
  throw new Error("API: reload - Invalid 'reloadAt.relative' option format.");
257
257
  }
258
+ if (!Array.isArray(options === null || options === void 0 ? void 0 : options.keySystems) && (options === null || options === void 0 ? void 0 : options.keySystems) !== undefined) {
259
+ throw new Error("API: reload - Invalid 'keySystems' option format.");
260
+ }
261
+ if ((options === null || options === void 0 ? void 0 : options.autoPlay) !== undefined && typeof options.autoPlay !== "boolean") {
262
+ throw new Error("API: reload - Invalid 'autoPlay' option format.");
263
+ }
258
264
  }
259
265
  /**
260
266
  * Parse options given to loadVideo and set default options as found
@@ -16,7 +16,7 @@
16
16
  import { IErrorCode, IErrorType } from "../../errors";
17
17
  import { IFeature } from "../../features";
18
18
  import Manifest from "../../manifest";
19
- import { IAdaptation, IAudioTrack, IAudioTrackPreference, IAvailableAudioTrack, IAvailableTextTrack, IAvailableVideoTrack, IBifThumbnail, IBitrateEstimate, IConstructorOptions, IDecipherabilityUpdateContent, IKeySystemConfigurationOutput, ILoadVideoOptions, IPeriod, IPlayerError, IPlayerState, IPositionUpdate, IRepresentation, IStreamEvent, ITextTrack, ITextTrackPreference, IVideoTrack, IVideoTrackPreference } from "../../public_types";
19
+ import { IAdaptation, IAudioTrack, IAudioTrackPreference, IAvailableAudioTrack, IAvailableTextTrack, IAvailableVideoTrack, IBifThumbnail, IBitrateEstimate, IConstructorOptions, IDecipherabilityUpdateContent, IKeySystemConfigurationOutput, IKeySystemOption, ILoadVideoOptions, IPeriod, IPlayerError, IPlayerState, IPositionUpdate, IRepresentation, IStreamEvent, ITextTrack, ITextTrackPreference, IVideoTrack, IVideoTrackPreference } from "../../public_types";
20
20
  import EventEmitter, { IListener } from "../../utils/event_emitter";
21
21
  import Logger from "../../utils/logger";
22
22
  import { IBufferedChunk, IBufferType } from "../segment_buffers";
@@ -169,6 +169,7 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
169
169
  position?: number;
170
170
  relative?: number;
171
171
  };
172
+ keySystems?: IKeySystemOption[];
172
173
  autoPlay?: boolean;
173
174
  }): void;
174
175
  createDebugElement(element: HTMLElement): {
@@ -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.32.2-canal.2023110700";
91
+ _this.version = /* PLAYER_VERSION */ "3.33.0-canal.2023111400";
92
92
  _this.log = log;
93
93
  _this.state = "STOPPED";
94
94
  _this.videoElement = videoElement;
@@ -283,8 +283,8 @@ var Player = /** @class */ (function (_super) {
283
283
  * @param {Object} reloadOpts
284
284
  */
285
285
  Player.prototype.reload = function (reloadOpts) {
286
- var _a, _b;
287
- var _c = this._priv_reloadingMetadata, options = _c.options, manifest = _c.manifest, reloadPosition = _c.reloadPosition, reloadInPause = _c.reloadInPause;
286
+ var _a, _b, _c;
287
+ var _d = this._priv_reloadingMetadata, options = _d.options, manifest = _d.manifest, reloadPosition = _d.reloadPosition, reloadInPause = _d.reloadInPause;
288
288
  if (options === undefined) {
289
289
  throw new Error("API: Can't reload without having previously loaded a content.");
290
290
  }
@@ -311,6 +311,13 @@ var Player = /** @class */ (function (_super) {
311
311
  else if (reloadInPause !== undefined) {
312
312
  autoPlay = !reloadInPause;
313
313
  }
314
+ var keySystems;
315
+ if ((reloadOpts === null || reloadOpts === void 0 ? void 0 : reloadOpts.keySystems) !== undefined) {
316
+ keySystems = reloadOpts.keySystems;
317
+ }
318
+ else if (((_c = this._priv_reloadingMetadata.options) === null || _c === void 0 ? void 0 : _c.keySystems) !== undefined) {
319
+ keySystems = this._priv_reloadingMetadata.options.keySystems;
320
+ }
314
321
  var newOptions = __assign(__assign({}, options), { initialManifest: manifest });
315
322
  if (startAt !== undefined) {
316
323
  newOptions.startAt = startAt;
@@ -318,6 +325,9 @@ var Player = /** @class */ (function (_super) {
318
325
  if (autoPlay !== undefined) {
319
326
  newOptions.autoPlay = autoPlay;
320
327
  }
328
+ if (keySystems !== undefined) {
329
+ newOptions.keySystems = keySystems;
330
+ }
321
331
  this._priv_initializeContentPlayback(newOptions);
322
332
  };
323
333
  Player.prototype.createDebugElement = function (element) {
@@ -2439,5 +2449,5 @@ var Player = /** @class */ (function (_super) {
2439
2449
  };
2440
2450
  return Player;
2441
2451
  }(EventEmitter));
2442
- Player.version = /* PLAYER_VERSION */ "3.32.2-canal.2023110700";
2452
+ Player.version = /* PLAYER_VERSION */ "3.33.0-canal.2023111400";
2443
2453
  export default Player;
@@ -15,6 +15,22 @@
15
15
  */
16
16
  import assert from "../../../../../utils/assert";
17
17
  import { areNearlyEqual, getCuesAfter, getCuesBefore, removeCuesInfosBetween, } from "./utils";
18
+ /**
19
+ * first or last IHTMLCue in a group can have a slighlty different start
20
+ * or end time than the start or end time of the ICuesGroup due to parsing
21
+ * approximation.
22
+ * DELTA_CUES_GROUP defines the tolerance level when comparing the start/end
23
+ * of a IHTMLCue to the start/end of a ICuesGroup.
24
+ * Having this value too high may lead to have unwanted subtitle displayed
25
+ * Having this value too low may lead to have subtitles not displayed
26
+ */
27
+ var DELTA_CUES_GROUP = 1e-3;
28
+ /**
29
+ * segment_duration / RELATIVE_DELTA_RATIO = relative_delta
30
+ *
31
+ * relative_delta is the tolerance to determine if two segements are the same
32
+ */
33
+ var RELATIVE_DELTA_RATIO = 5;
18
34
  /**
19
35
  * Manage the buffer of the HTMLTextSegmentBuffer.
20
36
  * Allows to add, remove and recuperate cues at given times.
@@ -57,6 +73,18 @@ var TextTrackCuesStore = /** @class */ (function () {
57
73
  ret.push(cues[j].element);
58
74
  }
59
75
  }
76
+ // first or last IHTMLCue in a group can have a slighlty different start
77
+ // or end time than the start or end time of the ICuesGroup due to parsing
78
+ // approximation.
79
+ // Add a tolerance of 1ms to fix this issue
80
+ if (ret.length === 0 && cues.length > 0) {
81
+ for (var j = 0; j < cues.length; j++) {
82
+ if (areNearlyEqual(time, cues[j].start, DELTA_CUES_GROUP)
83
+ || areNearlyEqual(time, cues[j].end, DELTA_CUES_GROUP)) {
84
+ ret.push(cues[j].element);
85
+ }
86
+ }
87
+ }
60
88
  return ret;
61
89
  }
62
90
  }
@@ -143,6 +171,11 @@ var TextTrackCuesStore = /** @class */ (function () {
143
171
  TextTrackCuesStore.prototype.insert = function (cues, start, end) {
144
172
  var cuesBuffer = this._cuesBuffer;
145
173
  var cuesInfosToInsert = { start: start, end: end, cues: cues };
174
+ // it's preferable to have a delta depending on the duration of the segment
175
+ // if the delta is one fifth of the length of the segment:
176
+ // a segment of [0, 2] is the "same" segment as [0, 2.1]
177
+ // but [0, 0.04] is not the "same" segement as [0,04, 0.08]
178
+ var relativeDelta = Math.abs(start - end) / RELATIVE_DELTA_RATIO;
146
179
  /**
147
180
  * Called when we found the index of the next cue relative to the cue we
148
181
  * want to insert (that is a cue starting after its start or at the same
@@ -154,7 +187,7 @@ var TextTrackCuesStore = /** @class */ (function () {
154
187
  function onIndexOfNextCueFound(indexOfNextCue) {
155
188
  var nextCue = cuesBuffer[indexOfNextCue];
156
189
  if (nextCue === undefined || // no cue
157
- areNearlyEqual(cuesInfosToInsert.end, nextCue.end)) // samey end
190
+ areNearlyEqual(cuesInfosToInsert.end, nextCue.end, relativeDelta)) // samey end
158
191
  {
159
192
  // ours: |AAAAA|
160
193
  // the current one: |BBBBB|
@@ -190,8 +223,8 @@ var TextTrackCuesStore = /** @class */ (function () {
190
223
  for (var cueIdx = 0; cueIdx < cuesBuffer.length; cueIdx++) {
191
224
  var cuesInfos = cuesBuffer[cueIdx];
192
225
  if (start < cuesInfos.end) {
193
- if (areNearlyEqual(start, cuesInfos.start)) {
194
- if (areNearlyEqual(end, cuesInfos.end)) {
226
+ if (areNearlyEqual(start, cuesInfos.start, relativeDelta)) {
227
+ if (areNearlyEqual(end, cuesInfos.end, relativeDelta)) {
195
228
  // exact same segment
196
229
  // ours: |AAAAA|
197
230
  // the current one: |BBBBB|
@@ -239,7 +272,7 @@ var TextTrackCuesStore = /** @class */ (function () {
239
272
  cuesBuffer.splice(cueIdx, 0, cuesInfosToInsert);
240
273
  return;
241
274
  }
242
- else if (areNearlyEqual(end, cuesInfos.start)) {
275
+ else if (areNearlyEqual(end, cuesInfos.start, relativeDelta)) {
243
276
  // our cue goes just before the current one:
244
277
  // ours: |AAAAAAA|
245
278
  // the current one: |BBBB|
@@ -251,7 +284,7 @@ var TextTrackCuesStore = /** @class */ (function () {
251
284
  cuesBuffer.splice(cueIdx, 0, cuesInfosToInsert);
252
285
  return;
253
286
  }
254
- else if (areNearlyEqual(end, cuesInfos.end)) {
287
+ else if (areNearlyEqual(end, cuesInfos.end, relativeDelta)) {
255
288
  // ours: |AAAAAAA|
256
289
  // the current one: |BBBB|
257
290
  // Result: |AAAAAAA|
@@ -279,7 +312,7 @@ var TextTrackCuesStore = /** @class */ (function () {
279
312
  return;
280
313
  }
281
314
  // else -> start > cuesInfos.start
282
- if (areNearlyEqual(cuesInfos.end, end)) {
315
+ if (areNearlyEqual(cuesInfos.end, end, relativeDelta)) {
283
316
  // ours: |AAAAAA|
284
317
  // the current one: |BBBBBBBB|
285
318
  // Result: |BBAAAAAA|
@@ -315,6 +348,21 @@ var TextTrackCuesStore = /** @class */ (function () {
315
348
  }
316
349
  }
317
350
  }
351
+ if (cuesBuffer.length) {
352
+ var lastCue = cuesBuffer[cuesBuffer.length - 1];
353
+ if (areNearlyEqual(lastCue.end, start, relativeDelta)) {
354
+ // Match the end of the previous cue to the start of the following one
355
+ // if they are close enough. If there is a small gap between two segments
356
+ // it can lead to having no subtitles for a short time, this is noticeable when
357
+ // two successive segments displays the same text, making it diseappear
358
+ // and reappear quickly, which gives the impression of blinking
359
+ //
360
+ // ours: |AAAAA|
361
+ // the current one: |BBBBB|...
362
+ // Result: |BBBBBBBAAAAA|
363
+ lastCue.end = start;
364
+ }
365
+ }
318
366
  // no cues group has the end after our current start.
319
367
  // These cues should be the last one
320
368
  cuesBuffer.push(cuesInfosToInsert);
@@ -18,9 +18,10 @@ import { ICuesGroup, IHTMLCue } from "./types";
18
18
  * @see MAX_DELTA_BUFFER_TIME
19
19
  * @param {Number} a
20
20
  * @param {Number} b
21
+ * @param {Number} delta
21
22
  * @returns {Boolean}
22
23
  */
23
- export declare function areNearlyEqual(a: number, b: number): boolean;
24
+ export declare function areNearlyEqual(a: number, b: number, delta?: number): boolean;
24
25
  /**
25
26
  * Get all cues which have data before the given time.
26
27
  * @param {Object} cues
@@ -44,6 +44,21 @@
44
44
  * Setting a value too high might lead to two segments targeting different times
45
45
  * to be wrongly believed to target the same time. In worst case scenarios, this
46
46
  * could lead to wanted text tracks being removed.
47
+ *
48
+ * When comparing 2 segments s1 and s2, you may want to take into account the duration
49
+ * of the segments:
50
+ * - if s1 is [0, 2] and s2 is [0, 2.1] s1 and s2 can be considered as nearly equal as
51
+ * there is a relative difference of: (2.1-2) / 2 = 5%;
52
+ * Formula: (end_s1 - end_s2) / duration_s2 = relative_difference
53
+ * - if s1 is [0, 0.04] and s2 is [0.04, 0.08] s1 and s2 may not considered as nearly
54
+ * equal as there is a relative difference of: (0.04-0.08) / 0.04 = 100%
55
+ *
56
+ * To compare relatively to the duration of a segment you can provide and additional
57
+ * parameter "delta" that remplace MAX_DELTA_BUFFER_TIME.
58
+ * If parameter "delta" is higher than MAX_DELTA_BUFFER_TIME, MAX_DELTA_BUFFER_TIME
59
+ * is used instead of delta. This ensure that segments are nearly equal when comparing
60
+ * relatively AND absolutely.
61
+ *
47
62
  * @type Number
48
63
  */
49
64
  var MAX_DELTA_BUFFER_TIME = 0.2;
@@ -51,10 +66,12 @@ var MAX_DELTA_BUFFER_TIME = 0.2;
51
66
  * @see MAX_DELTA_BUFFER_TIME
52
67
  * @param {Number} a
53
68
  * @param {Number} b
69
+ * @param {Number} delta
54
70
  * @returns {Boolean}
55
71
  */
56
- export function areNearlyEqual(a, b) {
57
- return Math.abs(a - b) <= MAX_DELTA_BUFFER_TIME;
72
+ export function areNearlyEqual(a, b, delta) {
73
+ if (delta === void 0) { delta = MAX_DELTA_BUFFER_TIME; }
74
+ return Math.abs(a - b) <= Math.min(delta, MAX_DELTA_BUFFER_TIME);
58
75
  }
59
76
  /**
60
77
  * Get all cues which have data before the given time.
@@ -27,6 +27,7 @@ var Representation = /** @class */ (function () {
27
27
  * @param {Object} args
28
28
  */
29
29
  function Representation(args, opts) {
30
+ var _a;
30
31
  this.id = args.id;
31
32
  this.uniqueId = generateRepresentationUniqueId();
32
33
  this.bitrate = args.bitrate;
@@ -55,12 +56,24 @@ var Representation = /** @class */ (function () {
55
56
  this.cdnMetadata = args.cdnMetadata;
56
57
  this.index = args.index;
57
58
  if (opts.type === "audio" || opts.type === "video") {
58
- var mimeTypeStr = this.getMimeTypeString();
59
- var isSupported = isCodecSupported(mimeTypeStr);
60
- if (!isSupported) {
61
- log.info("Unsupported Representation", mimeTypeStr, this.id, this.bitrate);
59
+ this.isSupported = false;
60
+ // Supplemental codecs are defined as backwards-compatible codecs enhancing
61
+ // the experience of a base layer codec
62
+ if (args.supplementalCodecs !== undefined) {
63
+ var supplementalCodecMimeTypeStr = "".concat((_a = this.mimeType) !== null && _a !== void 0 ? _a : "", ";codecs=\"").concat(args.supplementalCodecs, "\"");
64
+ if (isCodecSupported(supplementalCodecMimeTypeStr)) {
65
+ this.codec = args.supplementalCodecs;
66
+ this.isSupported = true;
67
+ }
68
+ }
69
+ if (!this.isSupported) {
70
+ var mimeTypeStr = this.getMimeTypeString();
71
+ var isSupported = isCodecSupported(mimeTypeStr);
72
+ if (!isSupported) {
73
+ log.info("Unsupported Representation", mimeTypeStr, this.id, this.bitrate);
74
+ }
75
+ this.isSupported = isSupported;
62
76
  }
63
- this.isSupported = isSupported;
64
77
  }
65
78
  else {
66
79
  this.isSupported = true; // TODO for other types
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Converts SCTE 214 supplemental codec string into RFC4281 codec string
3
+ *
4
+ * The returned value is a codec string respecting RFC6381
5
+ *
6
+ * SCTE 214 defines supplemental codecs as a whitespace-separated multiple list of
7
+ * codec strings
8
+ *
9
+ * RFC6381 defines codecs as a comma-separated list of codec strings.
10
+ *
11
+ * This two syntax differs and this parser is used to convert SCTE214
12
+ * to be compliant with what MSE APIs expect
13
+ *
14
+ * @param {string} val - The codec string to parse
15
+ * @returns { Array.<string | undefined | null>}
16
+ */
17
+ export declare function convertSupplementalCodecsToRFC6381(val: string): string;
@@ -0,0 +1,26 @@
1
+ import isNonEmptyString from "../../../../utils/is_non_empty_string";
2
+ var supplementalCodecSeparator = /[, ]+/g;
3
+ /**
4
+ * Converts SCTE 214 supplemental codec string into RFC4281 codec string
5
+ *
6
+ * The returned value is a codec string respecting RFC6381
7
+ *
8
+ * SCTE 214 defines supplemental codecs as a whitespace-separated multiple list of
9
+ * codec strings
10
+ *
11
+ * RFC6381 defines codecs as a comma-separated list of codec strings.
12
+ *
13
+ * This two syntax differs and this parser is used to convert SCTE214
14
+ * to be compliant with what MSE APIs expect
15
+ *
16
+ * @param {string} val - The codec string to parse
17
+ * @returns { Array.<string | undefined | null>}
18
+ */
19
+ export function convertSupplementalCodecsToRFC6381(val) {
20
+ if (isNonEmptyString(val)) {
21
+ return val
22
+ .trim()
23
+ .replace(supplementalCodecSeparator, ", ");
24
+ }
25
+ return "";
26
+ }
@@ -65,6 +65,11 @@ export default function flattenOverlappingPeriods(parsedPeriods) {
65
65
  // `lastFlattenedPeriod` has now a negative or `0` duration.
66
66
  // Remove it, consider the next Period in its place, and re-start the loop.
67
67
  flattenedPeriods.pop();
68
+ if (flattenedPeriods.length === 0) {
69
+ // There's no remaining Period to compare to `parsedPeriod`
70
+ break;
71
+ }
72
+ // Take the previous Period as reference and compare it now to `parsedPeriod`
68
73
  lastFlattenedPeriod = flattenedPeriods[flattenedPeriods.length - 1];
69
74
  }
70
75
  }
@@ -25,6 +25,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
25
25
  import log from "../../../../log";
26
26
  import arrayFind from "../../../../utils/array_find";
27
27
  import objectAssign from "../../../../utils/object_assign";
28
+ import { convertSupplementalCodecsToRFC6381 } from "./convert_supplemental_codecs";
28
29
  import { getWEBMHDRInformation } from "./get_hdr_information";
29
30
  import parseRepresentationIndex from "./parse_representation_index";
30
31
  import resolveBaseURLs from "./resolve_base_urls";
@@ -90,19 +91,19 @@ export default function parseRepresentations(representationsIR, adaptation, cont
90
91
  var parsedRepresentations = [];
91
92
  var _loop_1 = function (representation) {
92
93
  // Compute Representation ID
93
- var representationID = representation.attributes.id != null ?
94
+ var representationID = representation.attributes.id !== undefined ?
94
95
  representation.attributes.id :
95
96
  (String(representation.attributes.bitrate) +
96
- (representation.attributes.height != null ?
97
+ (representation.attributes.height !== undefined ?
97
98
  ("-".concat(representation.attributes.height)) :
98
99
  "") +
99
- (representation.attributes.width != null ?
100
+ (representation.attributes.width !== undefined ?
100
101
  ("-".concat(representation.attributes.width)) :
101
102
  "") +
102
- (representation.attributes.mimeType != null ?
103
+ (representation.attributes.mimeType !== undefined ?
103
104
  ("-".concat(representation.attributes.mimeType)) :
104
105
  "") +
105
- (representation.attributes.codecs != null ?
106
+ (representation.attributes.codecs !== undefined ?
106
107
  ("-".concat(representation.attributes.codecs)) :
107
108
  ""));
108
109
  // Avoid duplicate IDs
@@ -120,7 +121,7 @@ export default function parseRepresentations(representationsIR, adaptation, cont
120
121
  var representationIndex = parseRepresentationIndex(representation, reprIndexCtxt);
121
122
  // Find bitrate
122
123
  var representationBitrate = void 0;
123
- if (representation.attributes.bitrate == null) {
124
+ if (representation.attributes.bitrate === undefined) {
124
125
  log.warn("DASH: No usable bitrate found in the Representation.");
125
126
  representationBitrate = 0;
126
127
  }
@@ -147,45 +148,56 @@ export default function parseRepresentations(representationsIR, adaptation, cont
147
148
  }
148
149
  // Add optional attributes
149
150
  var codecs = void 0;
150
- if (representation.attributes.codecs != null) {
151
+ if (representation.attributes.codecs !== undefined) {
151
152
  codecs = representation.attributes.codecs;
152
153
  }
153
- else if (adaptation.attributes.codecs != null) {
154
+ else if (adaptation.attributes.codecs !== undefined) {
154
155
  codecs = adaptation.attributes.codecs;
155
156
  }
156
- if (codecs != null) {
157
+ if (codecs !== undefined) {
157
158
  codecs = codecs === "mp4a.40.02" ? "mp4a.40.2" : codecs;
158
159
  parsedRepresentation.codecs = codecs;
159
160
  }
160
- if (representation.attributes.frameRate != null) {
161
+ var supplementalCodecs = void 0;
162
+ if (representation.attributes.supplementalCodecs !== undefined) {
163
+ supplementalCodecs = representation.attributes.supplementalCodecs;
164
+ }
165
+ else if (adaptation.attributes.supplementalCodecs !== undefined) {
166
+ supplementalCodecs = adaptation.attributes.supplementalCodecs;
167
+ }
168
+ if (supplementalCodecs !== undefined) {
169
+ parsedRepresentation.supplementalCodecs =
170
+ convertSupplementalCodecsToRFC6381(supplementalCodecs);
171
+ }
172
+ if (representation.attributes.frameRate !== undefined) {
161
173
  parsedRepresentation.frameRate =
162
174
  representation.attributes.frameRate;
163
175
  }
164
- else if (adaptation.attributes.frameRate != null) {
176
+ else if (adaptation.attributes.frameRate !== undefined) {
165
177
  parsedRepresentation.frameRate =
166
178
  adaptation.attributes.frameRate;
167
179
  }
168
- if (representation.attributes.height != null) {
180
+ if (representation.attributes.height !== undefined) {
169
181
  parsedRepresentation.height =
170
182
  representation.attributes.height;
171
183
  }
172
- else if (adaptation.attributes.height != null) {
184
+ else if (adaptation.attributes.height !== undefined) {
173
185
  parsedRepresentation.height =
174
186
  adaptation.attributes.height;
175
187
  }
176
- if (representation.attributes.mimeType != null) {
188
+ if (representation.attributes.mimeType !== undefined) {
177
189
  parsedRepresentation.mimeType =
178
190
  representation.attributes.mimeType;
179
191
  }
180
- else if (adaptation.attributes.mimeType != null) {
192
+ else if (adaptation.attributes.mimeType !== undefined) {
181
193
  parsedRepresentation.mimeType =
182
194
  adaptation.attributes.mimeType;
183
195
  }
184
- if (representation.attributes.width != null) {
196
+ if (representation.attributes.width !== undefined) {
185
197
  parsedRepresentation.width =
186
198
  representation.attributes.width;
187
199
  }
188
- else if (adaptation.attributes.width != null) {
200
+ else if (adaptation.attributes.width !== undefined) {
189
201
  parsedRepresentation.width =
190
202
  adaptation.attributes.width;
191
203
  }
@@ -238,6 +238,9 @@ function parseAdaptationSetAttributes(root) {
238
238
  case "codecs":
239
239
  parsedAdaptation.codecs = attribute.value;
240
240
  break;
241
+ case "scte214:supplementalCodecs":
242
+ parsedAdaptation.supplementalCodecs = attribute.value;
243
+ break;
241
244
  case "codingDependency":
242
245
  parseValue(attribute.value, { asKey: "codingDependency",
243
246
  parser: parseBoolean,
@@ -147,6 +147,9 @@ function parseRepresentationAttributes(representationElement) {
147
147
  parser: parseMPDInteger,
148
148
  dashName: "qualityRanking" });
149
149
  break;
150
+ case "scte214:supplementalCodecs":
151
+ attributes.supplementalCodecs = attr.value;
152
+ break;
150
153
  case "segmentProfiles":
151
154
  attributes.segmentProfiles = attr.value;
152
155
  break;
@@ -217,6 +217,7 @@ export interface IAdaptationSetAttributes {
217
217
  segmentAlignment?: number | boolean;
218
218
  segmentProfiles?: string;
219
219
  subsegmentAlignment?: number | boolean;
220
+ supplementalCodecs?: string;
220
221
  width?: number;
221
222
  availabilityTimeComplete?: boolean;
222
223
  availabilityTimeOffset?: number;
@@ -249,6 +250,7 @@ export interface IRepresentationAttributes {
249
250
  profiles?: string;
250
251
  qualityRanking?: number;
251
252
  segmentProfiles?: string;
253
+ supplementalCodecs?: string;
252
254
  width?: number;
253
255
  availabilityTimeComplete?: boolean;
254
256
  availabilityTimeOffset?: number;
@@ -224,6 +224,10 @@ export function generateAdaptationSetAttrParser(adaptationAttrs, linearMemory) {
224
224
  adaptationAttrs.codecs =
225
225
  parseString(textDecoder, linearMemory.buffer, ptr, len);
226
226
  break;
227
+ case 77 /* AttributeName.SupplementalCodecs */:
228
+ adaptationAttrs.supplementalCodecs =
229
+ parseString(textDecoder, linearMemory.buffer, ptr, len);
230
+ break;
227
231
  case 2 /* AttributeName.Profiles */:
228
232
  adaptationAttrs.profiles =
229
233
  parseString(textDecoder, linearMemory.buffer, ptr, len);
@@ -122,6 +122,10 @@ export function generateRepresentationAttrParser(representationAttrs, linearMemo
122
122
  representationAttrs.codecs =
123
123
  parseString(textDecoder, linearMemory.buffer, ptr, len);
124
124
  break;
125
+ case 77 /* AttributeName.SupplementalCodecs */:
126
+ representationAttrs.supplementalCodecs =
127
+ parseString(textDecoder, linearMemory.buffer, ptr, len);
128
+ break;
125
129
  case 5 /* AttributeName.CodingDependency */:
126
130
  representationAttrs.codingDependency =
127
131
  new DataView(linearMemory.buffer).getUint8(0) === 0;
@@ -140,5 +140,6 @@ export declare const enum AttributeName {
140
140
  QueryBeforeStart = 73,
141
141
  ProxyServerUrl = 74,
142
142
  DefaultServiceLocation = 75,
143
- EndNumber = 76
143
+ EndNumber = 76,
144
+ SupplementalCodecs = 77
144
145
  }
@@ -154,6 +154,7 @@ export interface IParsedRepresentation {
154
154
  hdrInfo?: IHDRInformation | undefined;
155
155
  /** `true` if audio has Dolby Atmos. */
156
156
  isSpatialAudio?: boolean | undefined;
157
+ supplementalCodecs?: string | undefined;
157
158
  }
158
159
  /** Every possible types an Adaptation can have. */
159
160
  export type IParsedAdaptationType = "audio" | "video" | "text" | "image";
@@ -15,8 +15,8 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- var next_tick_1 = require("next-tick");
19
18
  var event_emitter_1 = require("../utils/event_emitter");
19
+ var queue_microtask_1 = require("../utils/queue_microtask");
20
20
  var global_scope_1 = require("./global_scope");
21
21
  var is_node_1 = require("./is_node");
22
22
  // TODO This is the last ugly side-effect here.
@@ -44,7 +44,7 @@ function patchWebkitSourceBuffer() {
44
44
  sourceBufferWebkitProto._emitUpdate =
45
45
  function (eventName, val) {
46
46
  var _this = this;
47
- (0, next_tick_1.default)(function () {
47
+ (0, queue_microtask_1.default)(function () {
48
48
  /* eslint-disable no-invalid-this */
49
49
  _this.trigger(eventName, val);
50
50
  _this.updating = false;
@@ -103,6 +103,8 @@ declare function checkReloadOptions(options?: {
103
103
  position?: number;
104
104
  relative?: number;
105
105
  };
106
+ keySystems?: IKeySystemOption[];
107
+ autoPlay?: boolean;
106
108
  }): void;
107
109
  /**
108
110
  * Parse options given to loadVideo and set default options as found
@@ -147,6 +147,12 @@ function checkReloadOptions(options) {
147
147
  ((_d = options === null || options === void 0 ? void 0 : options.reloadAt) === null || _d === void 0 ? void 0 : _d.relative) !== undefined) {
148
148
  throw new Error("API: reload - Invalid 'reloadAt.relative' option format.");
149
149
  }
150
+ if (!Array.isArray(options === null || options === void 0 ? void 0 : options.keySystems) && (options === null || options === void 0 ? void 0 : options.keySystems) !== undefined) {
151
+ throw new Error("API: reload - Invalid 'keySystems' option format.");
152
+ }
153
+ if ((options === null || options === void 0 ? void 0 : options.autoPlay) !== undefined && typeof options.autoPlay !== "boolean") {
154
+ throw new Error("API: reload - Invalid 'autoPlay' option format.");
155
+ }
150
156
  }
151
157
  exports.checkReloadOptions = checkReloadOptions;
152
158
  /**