rx-player 4.0.0-beta.1 → 4.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/CONTRIBUTING.md +48 -168
  3. package/FILES.md +40 -92
  4. package/VERSION +1 -1
  5. package/dist/_esm5.processed/compat/browser_detection.d.ts +3 -1
  6. package/dist/_esm5.processed/compat/browser_detection.js +7 -2
  7. package/dist/_esm5.processed/compat/eme/load_session.js +1 -1
  8. package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.d.ts +21 -0
  9. package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.js +26 -0
  10. package/dist/_esm5.processed/config.d.ts +2 -0
  11. package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +5 -4
  12. package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.d.ts +18 -1
  13. package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.js +106 -25
  14. package/dist/_esm5.processed/core/adaptive/guess_based_chooser.js +6 -6
  15. package/dist/_esm5.processed/core/adaptive/network_analyzer.js +8 -5
  16. package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.d.ts +19 -1
  17. package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.js +1 -1
  18. package/dist/_esm5.processed/core/api/debug/render.js +1 -1
  19. package/dist/_esm5.processed/core/api/playback_observer.js +1 -0
  20. package/dist/_esm5.processed/core/api/public_api.d.ts +54 -1
  21. package/dist/_esm5.processed/core/api/public_api.js +232 -35
  22. package/dist/_esm5.processed/core/api/track_management/media_element_tracks_store.js +10 -1
  23. package/dist/_esm5.processed/core/api/track_management/track_dispatcher.d.ts +13 -1
  24. package/dist/_esm5.processed/core/api/track_management/track_dispatcher.js +30 -15
  25. package/dist/_esm5.processed/core/api/track_management/tracks_store.d.ts +3 -1
  26. package/dist/_esm5.processed/core/api/track_management/tracks_store.js +67 -152
  27. package/dist/_esm5.processed/core/api/utils.d.ts +10 -0
  28. package/dist/_esm5.processed/core/api/utils.js +20 -0
  29. package/dist/_esm5.processed/core/decrypt/session_events_listener.js +7 -1
  30. package/dist/_esm5.processed/core/decrypt/utils/clean_old_loaded_sessions.js +2 -0
  31. package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +5 -1
  32. package/dist/_esm5.processed/core/init/directfile_content_initializer.js +1 -1
  33. package/dist/_esm5.processed/core/init/media_source_content_initializer.js +47 -10
  34. package/dist/_esm5.processed/core/init/types.d.ts +9 -1
  35. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.d.ts +28 -1
  36. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.js +22 -9
  37. package/dist/_esm5.processed/core/init/utils/media_source_duration_updater.d.ts +58 -0
  38. package/dist/_esm5.processed/core/init/utils/{media_duration_updater.js → media_source_duration_updater.js} +84 -87
  39. package/dist/_esm5.processed/core/init/utils/rebuffering_controller.d.ts +36 -2
  40. package/dist/_esm5.processed/core/init/utils/rebuffering_controller.js +82 -2
  41. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.d.ts +18 -7
  42. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +31 -40
  43. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.d.ts +8 -0
  44. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +12 -0
  45. package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.d.ts +8 -0
  46. package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.js +12 -0
  47. package/dist/_esm5.processed/core/segment_buffers/implementations/types.d.ts +11 -4
  48. package/dist/_esm5.processed/core/segment_buffers/index.d.ts +2 -2
  49. package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.d.ts +47 -0
  50. package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.js +70 -0
  51. package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +15 -8
  52. package/dist/_esm5.processed/core/stream/period/period_stream.js +1 -1
  53. package/dist/_esm5.processed/core/stream/representation/representation_stream.js +22 -13
  54. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.d.ts +4 -2
  55. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.js +2 -2
  56. package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.d.ts +3 -2
  57. package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.js +8 -8
  58. package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.d.ts +2 -2
  59. package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.js +2 -3
  60. package/dist/_esm5.processed/default_config.d.ts +25 -0
  61. package/dist/_esm5.processed/default_config.js +27 -2
  62. package/dist/_esm5.processed/errors/index.d.ts +2 -2
  63. package/dist/_esm5.processed/errors/media_error.d.ts +23 -1
  64. package/dist/_esm5.processed/errors/media_error.js +18 -5
  65. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.d.ts +1 -1
  66. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.js +8 -7
  67. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +17 -9
  68. package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/index.js +0 -2
  69. package/dist/_esm5.processed/manifest/adaptation.d.ts +21 -2
  70. package/dist/_esm5.processed/manifest/adaptation.js +76 -1
  71. package/dist/_esm5.processed/manifest/manifest.js +1 -1
  72. package/dist/_esm5.processed/manifest/period.js +2 -2
  73. package/dist/_esm5.processed/manifest/representation.d.ts +33 -2
  74. package/dist/_esm5.processed/manifest/representation.js +21 -0
  75. package/dist/_esm5.processed/manifest/utils.js +1 -3
  76. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.d.ts +1 -1
  77. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.js +1 -1
  78. package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.js +1 -0
  79. package/dist/_esm5.processed/public_types.d.ts +13 -3
  80. package/dist/_esm5.processed/tools/TextTrackRenderer/text_track_renderer.js +1 -1
  81. package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.d.ts +4 -6
  82. package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.js +4 -6
  83. package/dist/_esm5.processed/utils/is_null_or_undefined.d.ts +1 -1
  84. package/dist/_esm5.processed/utils/is_null_or_undefined.js +1 -1
  85. package/dist/mpd-parser.wasm +0 -0
  86. package/dist/rx-player.js +4709 -4218
  87. package/dist/rx-player.min.js +1 -1
  88. package/package.json +42 -36
  89. package/scripts/build/generate_build.js +1 -1
  90. package/scripts/fast_demo_build.js +4 -3
  91. package/scripts/generate_full_demo.js +1 -1
  92. package/sonar-project.properties +1 -1
  93. package/src/compat/browser_detection.ts +7 -1
  94. package/src/compat/eme/load_session.ts +1 -1
  95. package/src/compat/has_issues_with_high_media_source_duration.ts +27 -0
  96. package/src/core/adaptive/__tests__/buffer_based_chooser.test.ts +147 -48
  97. package/src/core/adaptive/adaptive_representation_selector.ts +7 -4
  98. package/src/core/adaptive/buffer_based_chooser.ts +144 -26
  99. package/src/core/adaptive/guess_based_chooser.ts +9 -8
  100. package/src/core/adaptive/network_analyzer.ts +9 -4
  101. package/src/core/adaptive/utils/representation_score_calculator.ts +22 -2
  102. package/src/core/api/debug/render.ts +1 -1
  103. package/src/core/api/playback_observer.ts +1 -0
  104. package/src/core/api/public_api.ts +277 -44
  105. package/src/core/api/track_management/media_element_tracks_store.ts +17 -8
  106. package/src/core/api/track_management/track_dispatcher.ts +37 -14
  107. package/src/core/api/track_management/tracks_store.ts +77 -167
  108. package/src/core/api/utils.ts +26 -0
  109. package/src/core/decrypt/session_events_listener.ts +6 -1
  110. package/src/core/decrypt/utils/clean_old_loaded_sessions.ts +2 -1
  111. package/src/core/decrypt/utils/loaded_sessions_store.ts +8 -1
  112. package/src/core/init/directfile_content_initializer.ts +1 -0
  113. package/src/core/init/media_source_content_initializer.ts +52 -9
  114. package/src/core/init/types.ts +9 -1
  115. package/src/core/init/utils/content_time_boundaries_observer.ts +46 -10
  116. package/src/core/init/utils/{media_duration_updater.ts → media_source_duration_updater.ts} +100 -112
  117. package/src/core/init/utils/rebuffering_controller.ts +114 -3
  118. package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +56 -55
  119. package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +16 -0
  120. package/src/core/segment_buffers/implementations/text/native/native_text_segment_buffer.ts +16 -0
  121. package/src/core/segment_buffers/implementations/types.ts +16 -4
  122. package/src/core/segment_buffers/index.ts +2 -0
  123. package/src/core/stream/adaptation/utils/create_representation_estimator.ts +114 -0
  124. package/src/core/stream/orchestrator/stream_orchestrator.ts +16 -8
  125. package/src/core/stream/period/period_stream.ts +2 -1
  126. package/src/core/stream/representation/representation_stream.ts +34 -22
  127. package/src/core/stream/representation/utils/append_segment_to_buffer.ts +8 -3
  128. package/src/core/stream/representation/utils/push_init_segment.ts +11 -6
  129. package/src/core/stream/representation/utils/push_media_segment.ts +3 -3
  130. package/src/default_config.ts +29 -2
  131. package/src/errors/__tests__/media_error.test.ts +6 -6
  132. package/src/errors/index.ts +4 -1
  133. package/src/errors/media_error.ts +67 -1
  134. package/src/experimental/tools/VideoThumbnailLoader/load_and_push_segment.ts +10 -7
  135. package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +17 -6
  136. package/src/experimental/tools/mediaCapabilitiesProber/index.ts +0 -4
  137. package/src/manifest/__tests__/manifest.test.ts +7 -7
  138. package/src/manifest/__tests__/period.test.ts +90 -45
  139. package/src/manifest/adaptation.ts +89 -1
  140. package/src/manifest/manifest.ts +1 -1
  141. package/src/manifest/period.ts +4 -2
  142. package/src/manifest/representation.ts +67 -1
  143. package/src/manifest/utils.ts +1 -3
  144. package/src/parsers/manifest/dash/js-parser/parse_from_document.ts +1 -1
  145. package/src/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.ts +1 -0
  146. package/src/parsers/texttracks/ttml/parse_ttml.ts +1 -1
  147. package/src/public_types.ts +16 -1
  148. package/src/tools/TextTrackRenderer/text_track_renderer.ts +1 -1
  149. package/src/transports/smooth/isobmff/create_boxes.ts +4 -6
  150. package/src/typings/globals.d.ts +20 -20
  151. package/src/utils/is_null_or_undefined.ts +1 -1
  152. package/dist/_esm5.processed/core/init/utils/media_duration_updater.d.ts +0 -56
  153. package/scripts/doc-generator/construct_table_of_contents.js +0 -76
  154. package/scripts/doc-generator/convert_MD_to_HMTL.js +0 -26
  155. package/scripts/doc-generator/create_documentation.js +0 -331
  156. package/scripts/doc-generator/create_documentation_page.js +0 -209
  157. package/scripts/doc-generator/create_page.js +0 -210
  158. package/scripts/doc-generator/generate_header_html.js +0 -147
  159. package/scripts/doc-generator/generate_page_html.js +0 -115
  160. package/scripts/doc-generator/generate_page_list_html.js +0 -92
  161. package/scripts/doc-generator/generate_sidebar_html.js +0 -85
  162. package/scripts/doc-generator/get_search_data_for_content.js +0 -137
  163. package/scripts/doc-generator/index.js +0 -34
  164. package/scripts/doc-generator/parse_doc_configs.js +0 -327
  165. package/scripts/doc-generator/scripts/lunr.js +0 -10
  166. package/scripts/doc-generator/scripts/script.js +0 -451
  167. package/scripts/doc-generator/styles/code.css +0 -99
  168. package/scripts/doc-generator/styles/style.css +0 -835
  169. package/scripts/doc-generator/utils.js +0 -74
@@ -55,14 +55,16 @@ var RebufferingController = /** @class */ (function (_super) {
55
55
  * @param {Object} manifest - The Manifest of the currently-played content.
56
56
  * @param {Object} speed - The last speed set by the user
57
57
  */
58
- function RebufferingController(playbackObserver, manifest, speed) {
58
+ function RebufferingController(playbackObserver, manifest, segmentBuffersStore, speed) {
59
59
  var _this = _super.call(this) || this;
60
60
  _this._playbackObserver = playbackObserver;
61
61
  _this._manifest = manifest;
62
+ _this._segmentBuffersStore = segmentBuffersStore;
62
63
  _this._speed = speed;
63
64
  _this._discontinuitiesStore = [];
64
65
  _this._isStarted = false;
65
66
  _this._canceller = new TaskCanceller();
67
+ _this._currentFreezeTimestamp = null;
66
68
  return _this;
67
69
  }
68
70
  RebufferingController.prototype.start = function () {
@@ -117,6 +119,9 @@ var RebufferingController = /** @class */ (function (_super) {
117
119
  lastSeekingPosition = observation.seeking ?
118
120
  Math.max((_a = observation.pendingInternalSeek) !== null && _a !== void 0 ? _a : 0, observation.position) :
119
121
  null;
122
+ if (_this._checkDecipherabilityFreeze(observation)) {
123
+ return;
124
+ }
120
125
  if (freezing !== null) {
121
126
  var now = performance.now();
122
127
  var referenceTimestamp = prevFreezingState === null ?
@@ -175,7 +180,7 @@ var RebufferingController = /** @class */ (function (_super) {
175
180
  return;
176
181
  }
177
182
  else {
178
- log.warn("Init: ignored stall for too long, checking discontinuity", now - ignoredStallTimeStamp);
183
+ log.warn("Init: ignored stall for too long, considering it", now - ignoredStallTimeStamp);
179
184
  }
180
185
  }
181
186
  ignoredStallTimeStamp = null;
@@ -291,6 +296,81 @@ var RebufferingController = /** @class */ (function (_super) {
291
296
  RebufferingController.prototype.destroy = function () {
292
297
  this._canceller.cancel();
293
298
  };
299
+ /**
300
+ * Support of contents with DRM on all the platforms out there is a pain in
301
+ * the *ss considering all the DRM-related bugs there are.
302
+ *
303
+ * We found out a frequent issue which is to be unable to play despite having
304
+ * all the decryption keys to play what is currently buffered.
305
+ * When this happens, re-creating the buffers from scratch, with a reload, is
306
+ * usually sufficient to unlock the situation.
307
+ *
308
+ * Although we prefer providing more targeted fixes or telling to platform
309
+ * developpers to fix their implementation, it's not always possible.
310
+ * We thus resorted to developping an heuristic which detects such situation
311
+ * and reload in that case.
312
+ *
313
+ * @param {Object} observation - The last playback observation produced, it
314
+ * has to be recent (just triggered for example).
315
+ * @returns {boolean} - Returns `true` if it seems to be such kind of
316
+ * decipherability freeze, in which case this method already performed the
317
+ * right handling steps.
318
+ */
319
+ RebufferingController.prototype._checkDecipherabilityFreeze = function (observation) {
320
+ var readyState = observation.readyState, rebuffering = observation.rebuffering, freezing = observation.freezing;
321
+ var bufferGap = observation.bufferGap !== undefined &&
322
+ isFinite(observation.bufferGap) ? observation.bufferGap :
323
+ 0;
324
+ if (this._segmentBuffersStore === null ||
325
+ bufferGap < 6 ||
326
+ (rebuffering === null && freezing === null) ||
327
+ readyState > 1) {
328
+ this._currentFreezeTimestamp = null;
329
+ return false;
330
+ }
331
+ var now = performance.now();
332
+ if (this._currentFreezeTimestamp === null) {
333
+ this._currentFreezeTimestamp = now;
334
+ }
335
+ var rebufferingForTooLong = rebuffering !== null && now - rebuffering.timestamp > 4000;
336
+ var frozenForTooLong = freezing !== null && now - freezing.timestamp > 4000;
337
+ if ((rebufferingForTooLong || frozenForTooLong) &&
338
+ performance.now() - this._currentFreezeTimestamp > 4000) {
339
+ var statusAudio = this._segmentBuffersStore.getStatus("audio");
340
+ var statusVideo = this._segmentBuffersStore.getStatus("video");
341
+ var hasOnlyDecipherableSegments = true;
342
+ var isClear = true;
343
+ for (var _i = 0, _a = [statusAudio, statusVideo]; _i < _a.length; _i++) {
344
+ var status_1 = _a[_i];
345
+ if (status_1.type === "initialized") {
346
+ for (var _b = 0, _c = status_1.value.getInventory(); _b < _c.length; _b++) {
347
+ var segment = _c[_b];
348
+ var representation = segment.infos.representation;
349
+ if (representation.decipherable === false) {
350
+ log.warn("Init: we have undecipherable segments left in the buffer, reloading");
351
+ this._currentFreezeTimestamp = null;
352
+ this.trigger("needsReload", null);
353
+ return true;
354
+ }
355
+ else if (representation.contentProtections !== undefined) {
356
+ isClear = false;
357
+ if (representation.decipherable !== true) {
358
+ hasOnlyDecipherableSegments = false;
359
+ }
360
+ }
361
+ }
362
+ }
363
+ }
364
+ if (!isClear && hasOnlyDecipherableSegments) {
365
+ log.warn("Init: we are frozen despite only having decipherable " +
366
+ "segments left in the buffer, reloading");
367
+ this._currentFreezeTimestamp = null;
368
+ this.trigger("needsReload", null);
369
+ return true;
370
+ }
371
+ }
372
+ return false;
373
+ };
294
374
  return RebufferingController;
295
375
  }(EventEmitter));
296
376
  export default RebufferingController;
@@ -49,16 +49,25 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
49
49
  */
50
50
  private _pendingTask;
51
51
  /**
52
- * Keep track of the of the latest init segment pushed in the linked
53
- * SourceBuffer.
52
+ * Keep track of the unique identifier of the of the latest init segment
53
+ * pushed to the linked SourceBuffer.
54
54
  *
55
- * This allows to be sure the right initialization segment is pushed before
56
- * any chunk is.
55
+ * Such identifiers are first declared through the `declareInitSegment`
56
+ * method and the corresponding initialization segment is then pushed through
57
+ * the `pushChunk` method.
58
+ *
59
+ * Keeping track of this allows to be sure the right initialization segment is
60
+ * pushed before any chunk is.
57
61
  *
58
62
  * `null` if no initialization segment have been pushed to the
59
63
  * `AudioVideoSegmentBuffer` yet.
60
64
  */
61
- private _lastInitSegment;
65
+ private _lastInitSegmentUniqueId;
66
+ /**
67
+ * Link unique identifiers for initialization segments (as communicated by
68
+ * `declareInitSegment`) to the corresponding initialization data.
69
+ */
70
+ private _initSegmentsMap;
62
71
  /**
63
72
  * @constructor
64
73
  * @param {string} bufferType
@@ -66,6 +75,8 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
66
75
  * @param {MediaSource} mediaSource
67
76
  */
68
77
  constructor(bufferType: "audio" | "video", codec: string, mediaSource: MediaSource);
78
+ declareInitSegment(uniqueId: string, initSegmentData: unknown): void;
79
+ freeInitSegment(uniqueId: string): void;
69
80
  /**
70
81
  * Push a chunk of the media segment given to the attached SourceBuffer, in a
71
82
  * FIFO queue.
@@ -162,9 +173,9 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
162
173
  */
163
174
  private _preparePushOperation;
164
175
  /**
165
- * Return `true` if the given `segmentData` is the same segment than the last
176
+ * Return `true` if the given `uniqueId` is the identifier of the last
166
177
  * initialization segment pushed to the `AudioVideoSegmentBuffer`.
167
- * @param {BufferSource} segmentData
178
+ * @param {string} uniqueId
168
179
  * @returns {boolean}
169
180
  */
170
181
  private _isLastInitSegment;
@@ -32,11 +32,8 @@ import { tryToChangeSourceBufferType, } from "../../../../compat";
32
32
  import config from "../../../../config";
33
33
  import log from "../../../../log";
34
34
  import { getLoggableSegmentId } from "../../../../manifest";
35
- import areArraysOfNumbersEqual from "../../../../utils/are_arrays_of_numbers_equal";
36
35
  import assertUnreachable from "../../../../utils/assert_unreachable";
37
- import { toUint8Array } from "../../../../utils/byte_parsing";
38
36
  import createCancellablePromise from "../../../../utils/create_cancellable_promise";
39
- import hashBuffer from "../../../../utils/hash_buffer";
40
37
  import noop from "../../../../utils/noop";
41
38
  import objectAssign from "../../../../utils/object_assign";
42
39
  import TaskCanceller, { CancellationError, } from "../../../../utils/task_canceller";
@@ -68,8 +65,9 @@ var AudioVideoSegmentBuffer = /** @class */ (function (_super) {
68
65
  _this._sourceBuffer = sourceBuffer;
69
66
  _this._queue = [];
70
67
  _this._pendingTask = null;
71
- _this._lastInitSegment = null;
68
+ _this._lastInitSegmentUniqueId = null;
72
69
  _this.codec = codec;
70
+ _this._initSegmentsMap = new Map();
73
71
  var onError = _this._onPendingTaskError.bind(_this);
74
72
  var reCheck = _this._flush.bind(_this);
75
73
  // Some browsers (happened with firefox 66) sometimes "forget" to send us
@@ -89,6 +87,13 @@ var AudioVideoSegmentBuffer = /** @class */ (function (_super) {
89
87
  });
90
88
  return _this;
91
89
  }
90
+ AudioVideoSegmentBuffer.prototype.declareInitSegment = function (uniqueId, initSegmentData) {
91
+ assertDataIsBufferSource(initSegmentData);
92
+ this._initSegmentsMap.set(uniqueId, initSegmentData);
93
+ };
94
+ AudioVideoSegmentBuffer.prototype.freeInitSegment = function (uniqueId) {
95
+ this._initSegmentsMap.delete(uniqueId);
96
+ };
92
97
  /**
93
98
  * Push a chunk of the media segment given to the attached SourceBuffer, in a
94
99
  * FIFO queue.
@@ -117,7 +122,7 @@ var AudioVideoSegmentBuffer = /** @class */ (function (_super) {
117
122
  * @returns {Promise}
118
123
  */
119
124
  AudioVideoSegmentBuffer.prototype.pushChunk = function (infos, cancellationSignal) {
120
- assertPushedDataIsBufferSource(infos);
125
+ assertDataIsBufferSource(infos.data.chunk);
121
126
  log.debug("AVSB: receiving order to push data to the SourceBuffer", this.bufferType, getLoggableSegmentId(infos.inventoryInfos));
122
127
  return this._addToQueue({ type: SegmentBufferOperation.Push,
123
128
  value: infos }, cancellationSignal);
@@ -211,7 +216,7 @@ var AudioVideoSegmentBuffer = /** @class */ (function (_super) {
211
216
  * @param {Event} err
212
217
  */
213
218
  AudioVideoSegmentBuffer.prototype._onPendingTaskError = function (err) {
214
- this._lastInitSegment = null; // initialize init segment as a security
219
+ this._lastInitSegmentUniqueId = null; // initialize init segment as a security
215
220
  if (this._pendingTask !== null) {
216
221
  var error = err instanceof Error ?
217
222
  err :
@@ -304,7 +309,7 @@ var AudioVideoSegmentBuffer = /** @class */ (function (_super) {
304
309
  var error = e instanceof Error ?
305
310
  e :
306
311
  new Error("An unknown error occured when preparing a push operation");
307
- this._lastInitSegment = null; // initialize init segment as a security
312
+ this._lastInitSegmentUniqueId = null; // initialize init segment as a security
308
313
  nextItem.reject(error);
309
314
  return;
310
315
  }
@@ -392,14 +397,16 @@ var AudioVideoSegmentBuffer = /** @class */ (function (_super) {
392
397
  else if (appendWindow[1] !== this._sourceBuffer.appendWindowEnd) {
393
398
  this._sourceBuffer.appendWindowEnd = appendWindow[1];
394
399
  }
395
- if (data.initSegment !== null &&
396
- (hasUpdatedSourceBufferType || !this._isLastInitSegment(data.initSegment))) {
400
+ if (data.initSegmentUniqueId !== null &&
401
+ (hasUpdatedSourceBufferType ||
402
+ !this._isLastInitSegment(data.initSegmentUniqueId))) {
397
403
  // Push initialization segment before the media segment
398
- var segmentData = data.initSegment;
404
+ var segmentData = this._initSegmentsMap.get(data.initSegmentUniqueId);
405
+ if (segmentData === undefined) {
406
+ throw new Error("Invalid initialization segment uniqueId");
407
+ }
399
408
  dataToPush.push(segmentData);
400
- var initU8 = toUint8Array(segmentData);
401
- this._lastInitSegment = { data: initU8,
402
- hash: hashBuffer(initU8) };
409
+ this._lastInitSegmentUniqueId = data.initSegmentUniqueId;
403
410
  }
404
411
  if (data.chunk !== null) {
405
412
  dataToPush.push(data.chunk);
@@ -407,27 +414,16 @@ var AudioVideoSegmentBuffer = /** @class */ (function (_super) {
407
414
  return dataToPush;
408
415
  };
409
416
  /**
410
- * Return `true` if the given `segmentData` is the same segment than the last
417
+ * Return `true` if the given `uniqueId` is the identifier of the last
411
418
  * initialization segment pushed to the `AudioVideoSegmentBuffer`.
412
- * @param {BufferSource} segmentData
419
+ * @param {string} uniqueId
413
420
  * @returns {boolean}
414
421
  */
415
- AudioVideoSegmentBuffer.prototype._isLastInitSegment = function (segmentData) {
416
- if (this._lastInitSegment === null) {
422
+ AudioVideoSegmentBuffer.prototype._isLastInitSegment = function (uniqueId) {
423
+ if (this._lastInitSegmentUniqueId === null) {
417
424
  return false;
418
425
  }
419
- if (this._lastInitSegment.data === segmentData) {
420
- return true;
421
- }
422
- var oldInit = this._lastInitSegment.data;
423
- if (oldInit.byteLength === segmentData.byteLength) {
424
- var newInitU8 = toUint8Array(segmentData);
425
- if (hashBuffer(newInitU8) === this._lastInitSegment.hash &&
426
- areArraysOfNumbersEqual(oldInit, newInitU8)) {
427
- return true;
428
- }
429
- }
430
- return false;
426
+ return this._lastInitSegmentUniqueId === uniqueId;
431
427
  };
432
428
  return AudioVideoSegmentBuffer;
433
429
  }(SegmentBuffer));
@@ -436,21 +432,16 @@ export default AudioVideoSegmentBuffer;
436
432
  * Throw if the given input is not in the expected format.
437
433
  * Allows to enforce runtime type-checking as compile-time type-checking here is
438
434
  * difficult to enforce.
439
- * @param {Object} pushedData
435
+ * @param {Object} data
440
436
  */
441
- function assertPushedDataIsBufferSource(pushedData) {
437
+ function assertDataIsBufferSource(data) {
442
438
  if (0 /* __ENVIRONMENT__.CURRENT_ENV */ === 0 /* __ENVIRONMENT__.PRODUCTION */) {
443
439
  return;
444
440
  }
445
- var _a = pushedData.data, chunk = _a.chunk, initSegment = _a.initSegment;
446
- if (typeof chunk !== "object" ||
447
- typeof initSegment !== "object" ||
448
- (chunk !== null &&
449
- !(chunk instanceof ArrayBuffer) &&
450
- !(chunk.buffer instanceof ArrayBuffer)) ||
451
- (initSegment !== null &&
452
- !(initSegment instanceof ArrayBuffer) &&
453
- !(initSegment.buffer instanceof ArrayBuffer))) {
441
+ if (typeof data !== "object" ||
442
+ (data !== null &&
443
+ !(data instanceof ArrayBuffer) &&
444
+ !(data.buffer instanceof ArrayBuffer))) {
454
445
  throw new Error("Invalid data given to the AudioVideoSegmentBuffer");
455
446
  }
456
447
  }
@@ -47,6 +47,14 @@ export default class HTMLTextSegmentBuffer extends SegmentBuffer {
47
47
  * @param {HTMLElement} textTrackElement
48
48
  */
49
49
  constructor(videoElement: HTMLMediaElement, textTrackElement: HTMLElement);
50
+ /**
51
+ * @param {string} uniqueId
52
+ */
53
+ declareInitSegment(uniqueId: string): void;
54
+ /**
55
+ * @param {string} uniqueId
56
+ */
57
+ freeInitSegment(uniqueId: string): void;
50
58
  /**
51
59
  * Push text segment to the HTMLTextSegmentBuffer.
52
60
  * @param {Object} infos
@@ -93,6 +93,18 @@ var HTMLTextSegmentBuffer = /** @class */ (function (_super) {
93
93
  _this.autoRefreshSubtitles(_this._canceller.signal);
94
94
  return _this;
95
95
  }
96
+ /**
97
+ * @param {string} uniqueId
98
+ */
99
+ HTMLTextSegmentBuffer.prototype.declareInitSegment = function (uniqueId) {
100
+ log.warn("ISB: Declaring initialization segment for image SegmentBuffer", uniqueId);
101
+ };
102
+ /**
103
+ * @param {string} uniqueId
104
+ */
105
+ HTMLTextSegmentBuffer.prototype.freeInitSegment = function (uniqueId) {
106
+ log.warn("ISB: Freeing initialization segment for image SegmentBuffer", uniqueId);
107
+ };
96
108
  /**
97
109
  * Push text segment to the HTMLTextSegmentBuffer.
98
110
  * @param {Object} infos
@@ -31,6 +31,14 @@ export default class NativeTextSegmentBuffer extends SegmentBuffer {
31
31
  * @param {HTMLMediaElement} videoElement
32
32
  */
33
33
  constructor(videoElement: HTMLMediaElement);
34
+ /**
35
+ * @param {string} uniqueId
36
+ */
37
+ declareInitSegment(uniqueId: string): void;
38
+ /**
39
+ * @param {string} uniqueId
40
+ */
41
+ freeInitSegment(uniqueId: string): void;
34
42
  /**
35
43
  * @param {Object} infos
36
44
  * @returns {Promise}
@@ -57,6 +57,18 @@ var NativeTextSegmentBuffer = /** @class */ (function (_super) {
57
57
  _this._trackElement = trackElement;
58
58
  return _this;
59
59
  }
60
+ /**
61
+ * @param {string} uniqueId
62
+ */
63
+ NativeTextSegmentBuffer.prototype.declareInitSegment = function (uniqueId) {
64
+ log.warn("ISB: Declaring initialization segment for image SegmentBuffer", uniqueId);
65
+ };
66
+ /**
67
+ * @param {string} uniqueId
68
+ */
69
+ NativeTextSegmentBuffer.prototype.freeInitSegment = function (uniqueId) {
70
+ log.warn("ISB: Freeing initialization segment for image SegmentBuffer", uniqueId);
71
+ };
60
72
  /**
61
73
  * @param {Object} infos
62
74
  * @returns {Promise}
@@ -68,6 +68,8 @@ export declare abstract class SegmentBuffer {
68
68
  */
69
69
  codec: string | undefined;
70
70
  constructor();
71
+ abstract declareInitSegment(uniqueId: string, initSegmentData: unknown): void;
72
+ abstract freeInitSegment(uniqueId: string): void;
71
73
  /**
72
74
  * Push a chunk of the media segment given to the attached buffer, in a
73
75
  * FIFO queue.
@@ -77,7 +79,8 @@ export declare abstract class SegmentBuffer {
77
79
  * pushed.
78
80
  *
79
81
  * Depending on the type of data appended, the pushed chunk might rely on an
80
- * initialization segment, given through the `data.initSegment` property.
82
+ * initialization segment, which had to be previously declared through the
83
+ * `declareInitSegment` method.
81
84
  *
82
85
  * Such initialization segment will be first pushed to the buffer if the
83
86
  * last pushed segment was associated to another initialization segment.
@@ -87,7 +90,7 @@ export declare abstract class SegmentBuffer {
87
90
  * reference).
88
91
  *
89
92
  * If you don't need any initialization segment to push the wanted chunk, you
90
- * can just set `data.initSegment` to `null`.
93
+ * can just set the corresponding property to `null`.
91
94
  *
92
95
  * You can also only push an initialization segment by setting the
93
96
  * `data.chunk` argument to null.
@@ -177,12 +180,16 @@ export type IBufferType = "audio" | "video" | "text";
177
180
  */
178
181
  export interface IPushedChunkData<T> {
179
182
  /**
180
- * The whole initialization segment's data related to the chunk you want to
183
+ * The `uniqueId` of the initialization segment linked to the data you want to
181
184
  * push.
185
+ *
186
+ * That identifier should previously have been declared through the
187
+ * `declareInitSegment` method and not freed.
188
+ *
182
189
  * To set to `null` either if no initialization data is needed, or if you are
183
190
  * confident that the last pushed one is compatible.
184
191
  */
185
- initSegment: T | null;
192
+ initSegmentUniqueId: string | null;
186
193
  /**
187
194
  * Chunk you want to push.
188
195
  * This can be the whole decodable segment's data or just a decodable sub-part
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import BufferGarbageCollector from "./garbage_collector";
17
17
  import { IBufferType, IEndOfSegmentInfos, IEndOfSegmentOperation, IPushChunkInfos, IPushedChunkData, IPushOperation, IRemoveOperation, ISBOperation, SegmentBuffer, SegmentBufferOperation } from "./implementations";
18
- import { IBufferedChunk, IChunkContext, getFirstSegmentAfterPeriod, getLastSegmentBeforePeriod } from "./inventory";
18
+ import { IBufferedChunk, IChunkContext, IInsertedChunkInfos, getFirstSegmentAfterPeriod, getLastSegmentBeforePeriod } from "./inventory";
19
19
  import SegmentBuffersStore, { ISegmentBufferOptions, ITextTrackSegmentBufferOptions } from "./segment_buffers_store";
20
20
  export default SegmentBuffersStore;
21
- export { BufferGarbageCollector, ISegmentBufferOptions, ITextTrackSegmentBufferOptions, SegmentBuffer, IBufferType, IBufferedChunk, IChunkContext, IPushChunkInfos, IPushedChunkData, IEndOfSegmentInfos, SegmentBufferOperation, ISBOperation, IEndOfSegmentOperation, IPushOperation, IRemoveOperation, getFirstSegmentAfterPeriod, getLastSegmentBeforePeriod, };
21
+ export { BufferGarbageCollector, ISegmentBufferOptions, ITextTrackSegmentBufferOptions, SegmentBuffer, IBufferType, IBufferedChunk, IChunkContext, IInsertedChunkInfos, IPushChunkInfos, IPushedChunkData, IEndOfSegmentInfos, SegmentBufferOperation, ISBOperation, IEndOfSegmentOperation, IPushOperation, IRemoveOperation, getFirstSegmentAfterPeriod, getLastSegmentBeforePeriod, };
@@ -0,0 +1,47 @@
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 Manifest, { Adaptation, Period, Representation } from "../../../../manifest";
17
+ import { IPlayerError } from "../../../../public_types";
18
+ import { IReadOnlySharedReference } from "../../../../utils/reference";
19
+ import { CancellationSignal } from "../../../../utils/task_canceller";
20
+ import { IABREstimate, IRepresentationEstimatorPlaybackObservation, IRepresentationEstimator, IRepresentationEstimatorCallbacks } from "../../../adaptive";
21
+ import { IReadOnlyPlaybackObserver } from "../../../api";
22
+ /**
23
+ * Produce estimates to know which Representation should be played.
24
+ * @param {Object} content - The Manifest, Period and Adaptation wanted.
25
+ * @param {Object} representationEstimator - `IRepresentationEstimator` which
26
+ * will produce Representation estimates.
27
+ * @param {Object} currentRepresentation - Reference emitting the
28
+ * currently-loaded Representation.
29
+ * @param {Object} playbackObserver - Allows to observe the current playback
30
+ * conditions.
31
+ * @param {Function} onFatalError - Callback called when a fatal error was
32
+ * thrown. Once this callback is called, no estimate will be produced.
33
+ * @param {Object} cancellationSignal - `CancellationSignal` allowing to abort
34
+ * the production of estimates (and clean-up all linked resources).
35
+ * @returns {Object} - Returns an object with the following properties:
36
+ * - `estimateRef`: Reference emitting the last estimate
37
+ * - `abrCallbacks`: Callbacks allowing to report back network and playback
38
+ * activities to improve the estimates given.
39
+ */
40
+ export default function getRepresentationEstimate(content: {
41
+ manifest: Manifest;
42
+ period: Period;
43
+ adaptation: Adaptation;
44
+ }, representationEstimator: IRepresentationEstimator, currentRepresentation: IReadOnlySharedReference<Representation | null>, playbackObserver: IReadOnlyPlaybackObserver<IRepresentationEstimatorPlaybackObservation>, onFatalError: (err: IPlayerError) => void, cancellationSignal: CancellationSignal): {
45
+ estimateRef: IReadOnlySharedReference<IABREstimate>;
46
+ abrCallbacks: IRepresentationEstimatorCallbacks;
47
+ };
@@ -0,0 +1,70 @@
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 { MediaError } from "../../../../errors";
17
+ import createSharedReference from "../../../../utils/reference";
18
+ /**
19
+ * Produce estimates to know which Representation should be played.
20
+ * @param {Object} content - The Manifest, Period and Adaptation wanted.
21
+ * @param {Object} representationEstimator - `IRepresentationEstimator` which
22
+ * will produce Representation estimates.
23
+ * @param {Object} currentRepresentation - Reference emitting the
24
+ * currently-loaded Representation.
25
+ * @param {Object} playbackObserver - Allows to observe the current playback
26
+ * conditions.
27
+ * @param {Function} onFatalError - Callback called when a fatal error was
28
+ * thrown. Once this callback is called, no estimate will be produced.
29
+ * @param {Object} cancellationSignal - `CancellationSignal` allowing to abort
30
+ * the production of estimates (and clean-up all linked resources).
31
+ * @returns {Object} - Returns an object with the following properties:
32
+ * - `estimateRef`: Reference emitting the last estimate
33
+ * - `abrCallbacks`: Callbacks allowing to report back network and playback
34
+ * activities to improve the estimates given.
35
+ */
36
+ export default function getRepresentationEstimate(content, representationEstimator, currentRepresentation, playbackObserver, onFatalError, cancellationSignal) {
37
+ var manifest = content.manifest, adaptation = content.adaptation;
38
+ var representations = createSharedReference([], cancellationSignal);
39
+ updateRepresentationsReference();
40
+ manifest.addEventListener("decipherabilityUpdate", updateRepresentationsReference);
41
+ var unregisterCleanUp = cancellationSignal.register(cleanUp);
42
+ var _a = representationEstimator(content, currentRepresentation, representations, playbackObserver, cancellationSignal), estimateRef = _a.estimates, abrCallbacks = _a.callbacks;
43
+ return { abrCallbacks: abrCallbacks, estimateRef: estimateRef };
44
+ function updateRepresentationsReference() {
45
+ /** Representations for which a `RepresentationStream` can be created. */
46
+ var newRepr = adaptation.getPlayableRepresentations();
47
+ if (newRepr.length === 0) {
48
+ var noRepErr = new MediaError("NO_PLAYABLE_REPRESENTATION", "No Representation in the chosen " +
49
+ adaptation.type + " Adaptation can be played", { adaptation: adaptation });
50
+ cleanUp();
51
+ onFatalError(noRepErr);
52
+ return;
53
+ }
54
+ var prevRepr = representations.getValue();
55
+ if (prevRepr.length === newRepr.length) {
56
+ if (prevRepr.every(function (r, idx) { return r.id === newRepr[idx].id; })) {
57
+ return;
58
+ }
59
+ }
60
+ representations.setValue(newRepr);
61
+ }
62
+ /** Clean-up all resources taken here. */
63
+ function cleanUp() {
64
+ manifest.removeEventListener("decipherabilityUpdate", updateRepresentationsReference);
65
+ // check to protect against the case where it is not yet defined.
66
+ if (typeof unregisterCleanUp !== "undefined") {
67
+ unregisterCleanUp();
68
+ }
69
+ }
70
+ }
@@ -201,7 +201,13 @@ export default function StreamOrchestrator(content, playbackObserver, representa
201
201
  launchConsecutiveStreamsForPeriod(nextPeriod);
202
202
  }, { clearSignal: orchestratorCancelSignal, includeLastObservation: true });
203
203
  manifest.addEventListener("decipherabilityUpdate", function (evt) {
204
+ if (orchestratorCancelSignal.isCancelled()) {
205
+ return;
206
+ }
204
207
  onDecipherabilityUpdates(evt).catch(function (err) {
208
+ if (orchestratorCancelSignal.isCancelled()) {
209
+ return;
210
+ }
205
211
  currentCanceller.cancel();
206
212
  callbacks.error(err);
207
213
  });
@@ -408,12 +414,10 @@ export default function StreamOrchestrator(content, playbackObserver, representa
408
414
  var periodStreamArgs = { bufferType: bufferType, content: { manifest: manifest, period: basePeriod }, garbageCollectors: garbageCollectors, maxVideoBufferSize: maxVideoBufferSize, segmentFetcherCreator: segmentFetcherCreator, segmentBuffersStore: segmentBuffersStore, options: options, playbackObserver: playbackObserver, representationEstimator: representationEstimator, wantedBufferAhead: wantedBufferAhead };
409
415
  var periodStreamCallbacks = __assign(__assign({}, consecutivePeriodStreamCb), { streamStatusUpdate: function (value) {
410
416
  if (value.hasFinishedLoading) {
411
- if (nextStreamInfo === null) {
412
- var nextPeriod = manifest.getPeriodAfter(basePeriod);
413
- if (nextPeriod !== null) {
414
- // current Stream is full, create the next one if not
415
- createNextPeriodStream(nextPeriod);
416
- }
417
+ var nextPeriod = manifest.getPeriodAfter(basePeriod);
418
+ if (nextPeriod !== null) {
419
+ // current Stream is full, create the next one if not
420
+ checkOrCreateNextPeriodStream(nextPeriod);
417
421
  }
418
422
  }
419
423
  else if (nextStreamInfo !== null) {
@@ -439,9 +443,12 @@ export default function StreamOrchestrator(content, playbackObserver, representa
439
443
  * Create `PeriodStream` for the next Period, specified under `nextPeriod`.
440
444
  * @param {Object} nextPeriod
441
445
  */
442
- function createNextPeriodStream(nextPeriod) {
446
+ function checkOrCreateNextPeriodStream(nextPeriod) {
443
447
  if (nextStreamInfo !== null) {
444
- log.warn("Stream: Creating next `PeriodStream` while it was already created.");
448
+ if (nextStreamInfo.period.id === nextPeriod.id) {
449
+ return;
450
+ }
451
+ log.warn("Stream: Creating next `PeriodStream` while one was already created.", bufferType, nextPeriod.id, nextStreamInfo.period.id);
445
452
  consecutivePeriodStreamCb.periodStreamCleared({ type: bufferType, manifest: manifest, period: nextStreamInfo.period });
446
453
  nextStreamInfo.canceller.cancel();
447
454
  }
@@ -325,7 +325,7 @@ function getFirstDeclaredMimeType(adaptation) {
325
325
  var representations = adaptation.getPlayableRepresentations();
326
326
  if (representations.length === 0) {
327
327
  var noRepErr = new MediaError("NO_PLAYABLE_REPRESENTATION", "No Representation in the chosen " +
328
- adaptation.type + " Adaptation can be played");
328
+ adaptation.type + " Adaptation can be played", { adaptation: adaptation });
329
329
  throw noRepErr;
330
330
  }
331
331
  return representations[0].getMimeTypeString();