rx-player 3.30.0-dev.2023020100 → 3.30.0-dev.2023022200

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 (167) hide show
  1. package/CHANGELOG.md +2 -1
  2. package/VERSION +1 -1
  3. package/dist/_esm5.processed/compat/eme/close_session.js +2 -2
  4. package/dist/_esm5.processed/compat/event_listeners.js +1 -1
  5. package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +4 -2
  6. package/dist/_esm5.processed/core/api/debug/buffer_graph.d.ts +28 -0
  7. package/dist/_esm5.processed/core/api/debug/buffer_graph.js +175 -0
  8. package/dist/_esm5.processed/core/api/debug/buffer_size_graph.d.ts +10 -0
  9. package/dist/_esm5.processed/core/api/debug/buffer_size_graph.js +105 -0
  10. package/dist/_esm5.processed/core/api/debug/constants.d.ts +2 -0
  11. package/dist/_esm5.processed/core/api/debug/constants.js +2 -0
  12. package/dist/_esm5.processed/core/api/debug/index.d.ts +2 -0
  13. package/dist/_esm5.processed/core/api/debug/index.js +2 -0
  14. package/dist/_esm5.processed/core/api/debug/modules/general_info.d.ts +3 -0
  15. package/dist/_esm5.processed/core/api/debug/modules/general_info.js +199 -0
  16. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.d.ts +4 -0
  17. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.js +121 -0
  18. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.d.ts +3 -0
  19. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.js +35 -0
  20. package/dist/_esm5.processed/core/api/debug/render.d.ts +3 -0
  21. package/dist/_esm5.processed/core/api/debug/render.js +32 -0
  22. package/dist/_esm5.processed/core/api/debug/utils.d.ts +39 -0
  23. package/dist/_esm5.processed/core/api/debug/utils.js +57 -0
  24. package/dist/_esm5.processed/core/api/playback_observer.js +3 -2
  25. package/dist/_esm5.processed/core/api/public_api.d.ts +3 -0
  26. package/dist/_esm5.processed/core/api/public_api.js +24 -13
  27. package/dist/_esm5.processed/core/api/utils.js +3 -3
  28. package/dist/_esm5.processed/core/decrypt/__tests__/__global__/utils.d.ts +5 -5
  29. package/dist/_esm5.processed/core/decrypt/attach_media_keys.js +1 -1
  30. package/dist/_esm5.processed/core/decrypt/content_decryptor.js +1 -1
  31. package/dist/_esm5.processed/core/decrypt/session_events_listener.js +37 -47
  32. package/dist/_esm5.processed/core/decrypt/utils/check_key_statuses.js +4 -0
  33. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.d.ts +17 -8
  34. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.js +10 -6
  35. package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.js +5 -4
  36. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +22 -5
  37. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +37 -21
  38. package/dist/_esm5.processed/core/fetchers/segment/task_prioritizer.js +21 -23
  39. package/dist/_esm5.processed/core/fetchers/utils/schedule_request.js +6 -5
  40. package/dist/_esm5.processed/core/init/directfile_content_initializer.js +1 -1
  41. package/dist/_esm5.processed/core/init/media_source_content_initializer.js +27 -31
  42. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.js +2 -2
  43. package/dist/_esm5.processed/core/init/utils/create_media_source.js +3 -12
  44. package/dist/_esm5.processed/core/init/utils/end_of_stream.js +6 -3
  45. package/dist/_esm5.processed/core/init/utils/get_loaded_reference.js +2 -1
  46. package/dist/_esm5.processed/core/init/utils/initial_seek_and_play.js +9 -5
  47. package/dist/_esm5.processed/core/init/utils/initialize_content_decryption.js +2 -1
  48. package/dist/_esm5.processed/core/init/utils/media_duration_updater.js +23 -19
  49. package/dist/_esm5.processed/core/init/utils/stream_events_emitter/stream_events_emitter.js +6 -4
  50. package/dist/_esm5.processed/core/init/utils/throw_on_media_error.js +1 -1
  51. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +7 -10
  52. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +4 -2
  53. package/dist/_esm5.processed/core/segment_buffers/segment_buffers_store.js +13 -9
  54. package/dist/_esm5.processed/core/stream/adaptation/adaptation_stream.js +10 -11
  55. package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +26 -12
  56. package/dist/_esm5.processed/core/stream/period/period_stream.js +11 -10
  57. package/dist/_esm5.processed/core/stream/representation/representation_stream.js +15 -15
  58. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.js +1 -1
  59. package/dist/_esm5.processed/core/stream/representation/utils/downloading_queue.js +16 -6
  60. package/dist/_esm5.processed/experimental/features/debug_element.d.ts +8 -0
  61. package/dist/_esm5.processed/experimental/features/debug_element.js +10 -0
  62. package/dist/_esm5.processed/experimental/features/index.d.ts +1 -0
  63. package/dist/_esm5.processed/experimental/features/index.js +1 -0
  64. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.js +7 -4
  65. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +5 -4
  66. package/dist/_esm5.processed/features/features_object.js +1 -0
  67. package/dist/_esm5.processed/features/initialize_features.js +13 -10
  68. package/dist/_esm5.processed/features/types.d.ts +3 -0
  69. package/dist/_esm5.processed/manifest/adaptation.js +4 -0
  70. package/dist/_esm5.processed/manifest/manifest.js +2 -0
  71. package/dist/_esm5.processed/manifest/representation.js +11 -4
  72. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_adaptation_sets.js +105 -137
  73. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +25 -5
  74. package/dist/_esm5.processed/public_types.d.ts +1 -0
  75. package/dist/_esm5.processed/transports/dash/add_segment_integrity_checks_to_loader.js +13 -12
  76. package/dist/_esm5.processed/transports/dash/low_latency_segment_loader.js +2 -2
  77. package/dist/_esm5.processed/transports/dash/manifest_parser.js +1 -1
  78. package/dist/_esm5.processed/transports/dash/segment_loader.js +4 -4
  79. package/dist/_esm5.processed/transports/local/segment_loader.js +13 -26
  80. package/dist/_esm5.processed/transports/smooth/segment_loader.js +4 -4
  81. package/dist/_esm5.processed/transports/utils/call_custom_manifest_loader.js +3 -3
  82. package/dist/_esm5.processed/utils/cancellable_sleep.js +4 -10
  83. package/dist/_esm5.processed/utils/create_cancellable_promise.d.ts +26 -0
  84. package/dist/_esm5.processed/utils/create_cancellable_promise.js +52 -0
  85. package/dist/_esm5.processed/utils/reference.js +6 -0
  86. package/dist/_esm5.processed/utils/request/xhr.js +1 -1
  87. package/dist/_esm5.processed/utils/task_canceller.d.ts +34 -15
  88. package/dist/_esm5.processed/utils/task_canceller.js +55 -22
  89. package/dist/rx-player.js +739 -626
  90. package/dist/rx-player.min.js +1 -1
  91. package/jest.config.js +1 -0
  92. package/package.json +18 -18
  93. package/scripts/build/constants.d.ts +1 -0
  94. package/scripts/report_build_sizes +4 -0
  95. package/sonar-project.properties +1 -1
  96. package/src/compat/eme/close_session.ts +2 -2
  97. package/src/compat/event_listeners.ts +1 -1
  98. package/src/core/adaptive/adaptive_representation_selector.ts +4 -2
  99. package/src/core/api/debug/buffer_graph.ts +247 -0
  100. package/src/core/api/debug/buffer_size_graph.ts +131 -0
  101. package/src/core/api/debug/constants.ts +2 -0
  102. package/src/core/api/debug/index.ts +3 -0
  103. package/src/core/api/debug/modules/general_info.ts +204 -0
  104. package/src/core/api/debug/modules/segment_buffer_content.ts +155 -0
  105. package/src/core/api/debug/modules/segment_buffer_size.ts +48 -0
  106. package/src/core/api/debug/render.ts +40 -0
  107. package/src/core/api/debug/utils.ts +103 -0
  108. package/src/core/api/playback_observer.ts +4 -2
  109. package/src/core/api/public_api.ts +27 -13
  110. package/src/core/api/utils.ts +3 -3
  111. package/src/core/decrypt/attach_media_keys.ts +1 -1
  112. package/src/core/decrypt/content_decryptor.ts +1 -1
  113. package/src/core/decrypt/session_events_listener.ts +37 -49
  114. package/src/core/decrypt/utils/check_key_statuses.ts +6 -0
  115. package/src/core/fetchers/cdn_prioritizer.ts +18 -9
  116. package/src/core/fetchers/manifest/manifest_fetcher.ts +5 -4
  117. package/src/core/fetchers/segment/segment_fetcher.ts +36 -14
  118. package/src/core/fetchers/segment/task_prioritizer.ts +25 -30
  119. package/src/core/fetchers/utils/schedule_request.ts +6 -5
  120. package/src/core/init/directfile_content_initializer.ts +1 -1
  121. package/src/core/init/media_source_content_initializer.ts +37 -41
  122. package/src/core/init/utils/content_time_boundaries_observer.ts +2 -2
  123. package/src/core/init/utils/create_media_source.ts +4 -16
  124. package/src/core/init/utils/end_of_stream.ts +6 -3
  125. package/src/core/init/utils/get_loaded_reference.ts +2 -1
  126. package/src/core/init/utils/initial_seek_and_play.ts +9 -5
  127. package/src/core/init/utils/initialize_content_decryption.ts +2 -1
  128. package/src/core/init/utils/media_duration_updater.ts +25 -20
  129. package/src/core/init/utils/stream_events_emitter/stream_events_emitter.ts +6 -4
  130. package/src/core/init/utils/throw_on_media_error.ts +1 -1
  131. package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +7 -11
  132. package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +4 -2
  133. package/src/core/segment_buffers/segment_buffers_store.ts +16 -13
  134. package/src/core/stream/adaptation/adaptation_stream.ts +10 -11
  135. package/src/core/stream/orchestrator/stream_orchestrator.ts +26 -12
  136. package/src/core/stream/period/period_stream.ts +11 -10
  137. package/src/core/stream/representation/representation_stream.ts +15 -15
  138. package/src/core/stream/representation/utils/append_segment_to_buffer.ts +1 -1
  139. package/src/core/stream/representation/utils/downloading_queue.ts +16 -4
  140. package/src/experimental/features/__tests__/debug_element.test.ts +26 -0
  141. package/src/experimental/features/debug_element.ts +13 -0
  142. package/src/experimental/features/index.ts +1 -0
  143. package/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts +7 -4
  144. package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +5 -4
  145. package/src/features/__tests__/initialize_features.test.ts +11 -0
  146. package/src/features/features_object.ts +1 -0
  147. package/src/features/initialize_features.ts +15 -10
  148. package/src/features/types.ts +9 -0
  149. package/src/manifest/adaptation.ts +7 -0
  150. package/src/manifest/manifest.ts +4 -0
  151. package/src/manifest/representation.ts +10 -4
  152. package/src/parsers/manifest/dash/common/parse_adaptation_sets.ts +116 -151
  153. package/src/parsers/manifest/dash/common/parse_representations.ts +21 -4
  154. package/src/public_types.ts +1 -0
  155. package/src/transports/dash/add_segment_integrity_checks_to_loader.ts +30 -24
  156. package/src/transports/dash/low_latency_segment_loader.ts +2 -2
  157. package/src/transports/dash/manifest_parser.ts +1 -1
  158. package/src/transports/dash/segment_loader.ts +4 -4
  159. package/src/transports/local/segment_loader.ts +14 -30
  160. package/src/transports/smooth/segment_loader.ts +4 -4
  161. package/src/transports/utils/call_custom_manifest_loader.ts +3 -3
  162. package/src/typings/globals.d.ts +2 -0
  163. package/src/utils/cancellable_sleep.ts +5 -14
  164. package/src/utils/create_cancellable_promise.ts +69 -0
  165. package/src/utils/reference.ts +6 -0
  166. package/src/utils/request/xhr.ts +1 -1
  167. package/src/utils/task_canceller.ts +63 -34
@@ -84,7 +84,8 @@ export default function AdaptationStream<T>(
84
84
  const { manifest, period, adaptation } = content;
85
85
 
86
86
  /** Allows to cancel everything the `AdaptationStream` is doing. */
87
- const adapStreamCanceller = new TaskCanceller({ cancelOn: parentCancelSignal });
87
+ const adapStreamCanceller = new TaskCanceller();
88
+ adapStreamCanceller.linkToSignal(parentCancelSignal);
88
89
 
89
90
  /**
90
91
  * The buffer goal ratio base itself on the value given by `wantedBufferAhead`
@@ -162,9 +163,8 @@ export default function AdaptationStream<T>(
162
163
  * terminating and as such the next one might be immediately created
163
164
  * recursively.
164
165
  */
165
- const repStreamTerminatingCanceller = new TaskCanceller({
166
- cancelOn: adapStreamCanceller.signal,
167
- });
166
+ const repStreamTerminatingCanceller = new TaskCanceller();
167
+ repStreamTerminatingCanceller.linkToSignal(adapStreamCanceller.signal);
168
168
  const { representation, manual } = estimateRef.getValue();
169
169
  if (representation === null) {
170
170
  return;
@@ -247,11 +247,11 @@ export default function AdaptationStream<T>(
247
247
 
248
248
  const repInfo = { type: adaptation.type, period, representation };
249
249
  currentRepresentation.setValue(representation);
250
- if (adapStreamCanceller.isUsed) {
250
+ if (adapStreamCanceller.isUsed()) {
251
251
  return ; // previous callback has stopped everything by side-effect
252
252
  }
253
253
  callbacks.representationChange(repInfo);
254
- if (adapStreamCanceller.isUsed) {
254
+ if (adapStreamCanceller.isUsed()) {
255
255
  return ; // previous callback has stopped everything by side-effect
256
256
  }
257
257
 
@@ -268,13 +268,13 @@ export default function AdaptationStream<T>(
268
268
  },
269
269
  addedSegment(segmentInfo) {
270
270
  abrCallbacks.addedSegment(segmentInfo);
271
- if (adapStreamCanceller.isUsed) {
271
+ if (adapStreamCanceller.isUsed()) {
272
272
  return;
273
273
  }
274
274
  callbacks.addedSegment(segmentInfo);
275
275
  },
276
276
  terminating() {
277
- if (repStreamTerminatingCanceller.isUsed) {
277
+ if (repStreamTerminatingCanceller.isUsed()) {
278
278
  return; // Already handled
279
279
  }
280
280
  repStreamTerminatingCanceller.cancel();
@@ -306,9 +306,8 @@ export default function AdaptationStream<T>(
306
306
  * `TaskCanceller` triggered when the `RepresentationStream` calls its
307
307
  * `terminating` callback.
308
308
  */
309
- const terminatingRepStreamCanceller = new TaskCanceller({
310
- cancelOn: adapStreamCanceller.signal,
311
- });
309
+ const terminatingRepStreamCanceller = new TaskCanceller();
310
+ terminatingRepStreamCanceller.linkToSignal(adapStreamCanceller.signal);
312
311
  const bufferGoal = createMappedReference(wantedBufferAhead, prev => {
313
312
  return prev * getBufferGoalRatio(representation);
314
313
  }, terminatingRepStreamCanceller.signal);
@@ -140,9 +140,9 @@ export default function StreamOrchestrator(
140
140
  });
141
141
 
142
142
  // Create automatically the right `PeriodStream` for every possible types
143
- segmentBuffersStore.getBufferTypes().map((bufferType) => {
143
+ for (const bufferType of segmentBuffersStore.getBufferTypes()) {
144
144
  manageEveryStreams(bufferType, initialPeriod);
145
- });
145
+ }
146
146
 
147
147
  /**
148
148
  * Manage creation and removal of Streams for every Periods for a given type.
@@ -167,7 +167,8 @@ export default function StreamOrchestrator(
167
167
  let enableOutOfBoundsCheck = false;
168
168
 
169
169
  /** Cancels currently created `PeriodStream`s. */
170
- let currentCanceller = new TaskCanceller({ cancelOn: orchestratorCancelSignal });
170
+ let currentCanceller = new TaskCanceller();
171
+ currentCanceller.linkToSignal(orchestratorCancelSignal);
171
172
 
172
173
  // Restart the current Stream when the wanted time is in another period
173
174
  // than the ones already considered
@@ -186,7 +187,8 @@ export default function StreamOrchestrator(
186
187
  callbacks.periodStreamCleared({ type: bufferType, period });
187
188
  }
188
189
  currentCanceller.cancel();
189
- currentCanceller = new TaskCanceller({ cancelOn: orchestratorCancelSignal });
190
+ currentCanceller = new TaskCanceller();
191
+ currentCanceller.linkToSignal(orchestratorCancelSignal);
190
192
 
191
193
  const nextPeriod = manifest.getPeriodForTime(time) ??
192
194
  manifest.getNextPeriod(time);
@@ -275,8 +277,16 @@ export default function StreamOrchestrator(
275
277
  const segmentBufferStatus = segmentBuffersStore.getStatus(bufferType);
276
278
  const ofCurrentType = updates
277
279
  .filter(update => update.adaptation.type === bufferType);
278
- if (ofCurrentType.length === 0 || segmentBufferStatus.type !== "initialized") {
279
- return ; // no need to stop the current Streams.
280
+ if (
281
+ // No update concerns the current type of data
282
+ ofCurrentType.length === 0 ||
283
+ segmentBufferStatus.type !== "initialized" ||
284
+ // The update only notifies of now-decipherable streams
285
+ ofCurrentType.every(x => x.representation.decipherable === true)
286
+ ) {
287
+ // Data won't have to be removed from the buffers, no need to stop the
288
+ // current Streams.
289
+ return ;
280
290
  }
281
291
 
282
292
  const segmentBuffer = segmentBufferStatus.value;
@@ -316,7 +326,8 @@ export default function StreamOrchestrator(
316
326
  }
317
327
 
318
328
  currentCanceller.cancel();
319
- currentCanceller = new TaskCanceller({ cancelOn: orchestratorCancelSignal });
329
+ currentCanceller = new TaskCanceller();
330
+ currentCanceller.linkToSignal(orchestratorCancelSignal);
320
331
 
321
332
  /** Remove from the `SegmentBuffer` all the concerned time ranges. */
322
333
  for (const { start, end } of [...undecipherableRanges, ...rangesToRemove]) {
@@ -329,7 +340,7 @@ export default function StreamOrchestrator(
329
340
  // to reduce the risk of race conditions where the next observation
330
341
  // was going to be emitted synchronously.
331
342
  nextTick(() => {
332
- if (orchestratorCancelSignal.isCancelled) {
343
+ if (orchestratorCancelSignal.isCancelled()) {
333
344
  return ;
334
345
  }
335
346
  const observation = playbackObserver.getReference().getValue();
@@ -339,12 +350,12 @@ export default function StreamOrchestrator(
339
350
  callbacks.needsDecipherabilityFlush({ position: observation.position.last,
340
351
  autoPlay: shouldAutoPlay,
341
352
  duration: observation.duration });
342
- if (orchestratorCancelSignal.isCancelled) {
353
+ if (orchestratorCancelSignal.isCancelled()) {
343
354
  return ;
344
355
  }
345
356
  } else if (needsFlushingAfterClean(observation, rangesToRemove)) {
346
357
  callbacks.needsBufferFlush();
347
- if (orchestratorCancelSignal.isCancelled) {
358
+ if (orchestratorCancelSignal.isCancelled()) {
348
359
  return ;
349
360
  }
350
361
  }
@@ -417,7 +428,8 @@ export default function StreamOrchestrator(
417
428
  } | null = null;
418
429
 
419
430
  /** Emits when the `PeriodStream` linked to `basePeriod` should be destroyed. */
420
- const currentStreamCanceller = new TaskCanceller({ cancelOn: cancelSignal });
431
+ const currentStreamCanceller = new TaskCanceller();
432
+ currentStreamCanceller.linkToSignal(cancelSignal);
421
433
 
422
434
  // Stop current PeriodStream when the current position goes over the end of
423
435
  // that Period.
@@ -490,7 +502,9 @@ export default function StreamOrchestrator(
490
502
  period: nextStreamInfo.period });
491
503
  nextStreamInfo.canceller.cancel();
492
504
  }
493
- nextStreamInfo = { canceller: new TaskCanceller({ cancelOn: cancelSignal }),
505
+ const nextStreamCanceller = new TaskCanceller();
506
+ nextStreamCanceller.linkToSignal(cancelSignal);
507
+ nextStreamInfo = { canceller: nextStreamCanceller,
494
508
  period: nextPeriod };
495
509
  manageConsecutivePeriodStreams(bufferType,
496
510
  nextPeriod,
@@ -109,7 +109,7 @@ export default function PeriodStream(
109
109
  );
110
110
 
111
111
  callbacks.periodStreamReady({ type: bufferType, period, adaptationRef });
112
- if (parentCancelSignal.isCancelled) {
112
+ if (parentCancelSignal.isCancelled()) {
113
113
  return;
114
114
  }
115
115
 
@@ -122,7 +122,8 @@ export default function PeriodStream(
122
122
  if (adaptation === undefined) {
123
123
  return;
124
124
  }
125
- const streamCanceller = new TaskCanceller({ cancelOn: parentCancelSignal });
125
+ const streamCanceller = new TaskCanceller();
126
+ streamCanceller.linkToSignal(parentCancelSignal);
126
127
  currentStreamCanceller?.cancel(); // Cancel oreviously created stream if one
127
128
  currentStreamCanceller = streamCanceller;
128
129
 
@@ -142,20 +143,20 @@ export default function PeriodStream(
142
143
  await segmentBufferStatus.value.removeBuffer(period.start,
143
144
  periodEnd,
144
145
  streamCanceller.signal);
145
- if (streamCanceller.isUsed) {
146
+ if (streamCanceller.isUsed()) {
146
147
  return; // The stream has been cancelled
147
148
  }
148
149
  }
149
150
  }
150
151
  } else if (segmentBufferStatus.type === "uninitialized") {
151
152
  segmentBuffersStore.disableSegmentBuffer(bufferType);
152
- if (streamCanceller.isUsed) {
153
+ if (streamCanceller.isUsed()) {
153
154
  return; // The stream has been cancelled
154
155
  }
155
156
  }
156
157
 
157
158
  callbacks.adaptationChange({ type: bufferType, adaptation: null, period });
158
- if (streamCanceller.isUsed) {
159
+ if (streamCanceller.isUsed()) {
159
160
  return; // Previous call has provoken Stream cancellation by side-effect
160
161
  }
161
162
 
@@ -193,7 +194,7 @@ export default function PeriodStream(
193
194
  `P: ${period.start}`);
194
195
 
195
196
  callbacks.adaptationChange({ type: bufferType, adaptation, period });
196
- if (streamCanceller.isUsed) {
197
+ if (streamCanceller.isUsed()) {
197
198
  return; // Previous call has provoken cancellation by side-effect
198
199
  }
199
200
 
@@ -214,19 +215,19 @@ export default function PeriodStream(
214
215
  }
215
216
 
216
217
  await segmentBuffersStore.waitForUsableBuffers(streamCanceller.signal);
217
- if (streamCanceller.isUsed) {
218
+ if (streamCanceller.isUsed()) {
218
219
  return; // The Stream has since been cancelled
219
220
  }
220
221
  if (strategy.type === "flush-buffer" || strategy.type === "clean-buffer") {
221
222
  for (const { start, end } of strategy.value) {
222
223
  await segmentBuffer.removeBuffer(start, end, streamCanceller.signal);
223
- if (streamCanceller.isUsed) {
224
+ if (streamCanceller.isUsed()) {
224
225
  return; // The Stream has since been cancelled
225
226
  }
226
227
  }
227
228
  if (strategy.type === "flush-buffer") {
228
229
  callbacks.needsBufferFlush();
229
- if (streamCanceller.isUsed) {
230
+ if (streamCanceller.isUsed()) {
230
231
  return ; // Previous callback cancelled the Stream by side-effect
231
232
  }
232
233
  }
@@ -282,7 +283,7 @@ export default function PeriodStream(
282
283
  defaultReason: "Unknown `AdaptationStream` error",
283
284
  });
284
285
  callbacks.warning(formattedError);
285
- if (cancelSignal.isCancelled) {
286
+ if (cancelSignal.isCancelled()) {
286
287
  return ; // Previous callback cancelled the Stream by side-effect
287
288
  }
288
289
 
@@ -97,16 +97,16 @@ export default function RepresentationStream<TSegmentDataType>(
97
97
  const bufferType = adaptation.type;
98
98
 
99
99
  /** `TaskCanceller` stopping ALL operations performed by the `RepresentationStream` */
100
- const globalCanceller = new TaskCanceller({ cancelOn: parentCancelSignal });
100
+ const globalCanceller = new TaskCanceller();
101
+ globalCanceller.linkToSignal(parentCancelSignal);
101
102
 
102
103
  /**
103
104
  * `TaskCanceller` allowing to only stop segment loading and checking operations.
104
105
  * This allows to stop only tasks linked to network resource usage, which is
105
106
  * often a limited resource, while still letting buffer operations to finish.
106
107
  */
107
- const segmentsLoadingCanceller = new TaskCanceller({
108
- cancelOn: globalCanceller.signal,
109
- });
108
+ const segmentsLoadingCanceller = new TaskCanceller();
109
+ segmentsLoadingCanceller.linkToSignal(globalCanceller.signal);
110
110
 
111
111
  /** Saved initialization segment state for this representation. */
112
112
  const initSegmentState : IInitSegmentState<TSegmentDataType> = {
@@ -149,7 +149,7 @@ export default function RepresentationStream<TSegmentDataType>(
149
149
  callbacks.encryptionDataEncountered(
150
150
  encryptionData.map(d => objectAssign({ content }, d))
151
151
  );
152
- if (globalCanceller.isUsed) {
152
+ if (globalCanceller.isUsed()) {
153
153
  return ; // previous callback has stopped everything by side-effect
154
154
  }
155
155
  }
@@ -161,7 +161,7 @@ export default function RepresentationStream<TSegmentDataType>(
161
161
  segmentFetcher,
162
162
  hasInitSegment);
163
163
  downloadingQueue.addEventListener("error", (err) => {
164
- if (segmentsLoadingCanceller.signal.isCancelled) {
164
+ if (segmentsLoadingCanceller.signal.isCancelled()) {
165
165
  return; // ignore post requests-cancellation loading-related errors,
166
166
  }
167
167
  globalCanceller.cancel(); // Stop every operations
@@ -172,7 +172,7 @@ export default function RepresentationStream<TSegmentDataType>(
172
172
  downloadingQueue.addEventListener("emptyQueue", checkStatus);
173
173
  downloadingQueue.addEventListener("requestRetry", (payload) => {
174
174
  callbacks.warning(payload.error);
175
- if (segmentsLoadingCanceller.signal.isCancelled) {
175
+ if (segmentsLoadingCanceller.signal.isCancelled()) {
176
176
  return; // If the previous callback led to loading operations being stopped, skip
177
177
  }
178
178
  const retriedSegment = payload.segment;
@@ -218,7 +218,7 @@ export default function RepresentationStream<TSegmentDataType>(
218
218
  * issues at the current time, calling the right callbacks if necessary.
219
219
  */
220
220
  function checkStatus() : void {
221
- if (segmentsLoadingCanceller.isUsed) {
221
+ if (segmentsLoadingCanceller.isUsed()) {
222
222
  return ; // Stop all buffer status checking if load operations are stopped
223
223
  }
224
224
  const observation = playbackObserver.getReference().getValue();
@@ -305,7 +305,7 @@ export default function RepresentationStream<TSegmentDataType>(
305
305
  isEmptyStream: false,
306
306
  hasFinishedLoading: status.hasFinishedLoading,
307
307
  neededSegments: status.neededSegments });
308
- if (segmentsLoadingCanceller.signal.isCancelled) {
308
+ if (segmentsLoadingCanceller.signal.isCancelled()) {
309
309
  return ; // previous callback has stopped loading operations by side-effect
310
310
  }
311
311
  const { UPTO_CURRENT_POSITION_CLEANUP } = config.getCurrent();
@@ -314,7 +314,7 @@ export default function RepresentationStream<TSegmentDataType>(
314
314
  0,
315
315
  initialWantedTime - UPTO_CURRENT_POSITION_CLEANUP);
316
316
  if (gcedPosition > 0) {
317
- segmentBuffer.removeBuffer(0, gcedPosition, segmentsLoadingCanceller.signal)
317
+ segmentBuffer.removeBuffer(0, gcedPosition, globalCanceller.signal)
318
318
  .catch(onFatalBufferError);
319
319
  }
320
320
  }
@@ -332,7 +332,7 @@ export default function RepresentationStream<TSegmentDataType>(
332
332
  evt : IParsedInitSegmentPayload<TSegmentDataType> |
333
333
  IParsedSegmentPayload<TSegmentDataType>
334
334
  ) : void {
335
- if (globalCanceller.isUsed) {
335
+ if (globalCanceller.isUsed()) {
336
336
  // We should not do anything with segments if the `RepresentationStream`
337
337
  // is not running anymore.
338
338
  return ;
@@ -382,7 +382,7 @@ export default function RepresentationStream<TSegmentDataType>(
382
382
  callbacks.encryptionDataEncountered(
383
383
  allEncryptionData.map(p => objectAssign({ content }, p))
384
384
  );
385
- if (globalCanceller.isUsed) {
385
+ if (globalCanceller.isUsed()) {
386
386
  return ; // previous callback has stopped everything by side-effect
387
387
  }
388
388
  }
@@ -390,13 +390,13 @@ export default function RepresentationStream<TSegmentDataType>(
390
390
 
391
391
  if (needsManifestRefresh === true) {
392
392
  callbacks.needsManifestRefresh();
393
- if (globalCanceller.isUsed) {
393
+ if (globalCanceller.isUsed()) {
394
394
  return ; // previous callback has stopped everything by side-effect
395
395
  }
396
396
  }
397
397
  if (inbandEvents !== undefined && inbandEvents.length > 0) {
398
398
  callbacks.inbandEvent(inbandEvents);
399
- if (globalCanceller.isUsed) {
399
+ if (globalCanceller.isUsed()) {
400
400
  return ; // previous callback has stopped everything by side-effect
401
401
  }
402
402
  }
@@ -425,7 +425,7 @@ export default function RepresentationStream<TSegmentDataType>(
425
425
  * @param {*} err
426
426
  */
427
427
  function onFatalBufferError(err : unknown) : void {
428
- if (globalCanceller.isUsed && err instanceof CancellationError) {
428
+ if (globalCanceller.isUsed() && err instanceof CancellationError) {
429
429
  // The error is linked to cancellation AND we explicitely cancelled buffer
430
430
  // operations.
431
431
  // We can thus ignore it, it is very unlikely to lead to true buffer issues.
@@ -47,7 +47,7 @@ export default async function appendSegmentToBuffer<T>(
47
47
  try {
48
48
  await segmentBuffer.pushChunk(dataInfos, cancellationSignal);
49
49
  } catch (appendError : unknown) {
50
- if (cancellationSignal.isCancelled && appendError instanceof CancellationError) {
50
+ if (cancellationSignal.isCancelled() && appendError instanceof CancellationError) {
51
51
  throw appendError;
52
52
  } else if (!(appendError instanceof Error) ||
53
53
  appendError.name !== "QuotaExceededError")
@@ -28,6 +28,7 @@ import {
28
28
  } from "../../../../transports";
29
29
  import assert from "../../../../utils/assert";
30
30
  import EventEmitter from "../../../../utils/event_emitter";
31
+ import noop from "../../../../utils/noop";
31
32
  import objectAssign from "../../../../utils/object_assign";
32
33
  import createSharedReference, {
33
34
  IReadOnlySharedReference,
@@ -231,6 +232,7 @@ export default class DownloadingQueue<T>
231
232
 
232
233
  public stop() {
233
234
  this._currentCanceller?.cancel();
235
+ this._currentCanceller = null;
234
236
  }
235
237
 
236
238
  /**
@@ -245,7 +247,7 @@ export default class DownloadingQueue<T>
245
247
  const recursivelyRequestSegments = (
246
248
  startingSegment : IQueuedSegment | undefined
247
249
  ) : void => {
248
- if (this._currentCanceller !== null && this._currentCanceller.isUsed) {
250
+ if (this._currentCanceller !== null && this._currentCanceller.isUsed()) {
249
251
  this._mediaSegmentRequest = null;
250
252
  return;
251
253
  }
@@ -254,7 +256,10 @@ export default class DownloadingQueue<T>
254
256
  this.trigger("emptyQueue", null);
255
257
  return;
256
258
  }
257
- const canceller = new TaskCanceller({ cancelOn: this._currentCanceller?.signal });
259
+ const canceller = new TaskCanceller();
260
+ const unlinkCanceller = this._currentCanceller === null ?
261
+ noop :
262
+ canceller.linkToSignal(this._currentCanceller.signal);
258
263
 
259
264
  const { segment, priority } = startingSegment;
260
265
  const context = objectAssign({ segment }, this._content);
@@ -368,6 +373,7 @@ export default class DownloadingQueue<T>
368
373
  * requests are scheduled. It is used to schedule the next segment.
369
374
  */
370
375
  beforeEnded: () : void => {
376
+ unlinkCanceller();
371
377
  this._mediaSegmentRequest = null;
372
378
 
373
379
  if (isWaitingOnInitSegment) {
@@ -381,6 +387,7 @@ export default class DownloadingQueue<T>
381
387
  }, canceller.signal);
382
388
 
383
389
  request.catch((error : unknown) => {
390
+ unlinkCanceller();
384
391
  if (!isComplete) {
385
392
  isComplete = true;
386
393
  this.stop();
@@ -400,7 +407,7 @@ export default class DownloadingQueue<T>
400
407
  private _restartInitSegmentDownloadingQueue(
401
408
  queuedInitSegment : IQueuedSegment | null
402
409
  ) : void {
403
- if (this._currentCanceller !== null && this._currentCanceller.isUsed) {
410
+ if (this._currentCanceller !== null && this._currentCanceller.isUsed()) {
404
411
  return;
405
412
  }
406
413
  if (this._initSegmentRequest !== null) {
@@ -410,7 +417,10 @@ export default class DownloadingQueue<T>
410
417
  return ;
411
418
  }
412
419
 
413
- const canceller = new TaskCanceller({ cancelOn: this._currentCanceller?.signal });
420
+ const canceller = new TaskCanceller();
421
+ const unlinkCanceller = this._currentCanceller === null ?
422
+ noop :
423
+ canceller.linkToSignal(this._currentCanceller.signal);
414
424
  const { segment, priority } = queuedInitSegment;
415
425
  const context = objectAssign({ segment }, this._content);
416
426
 
@@ -428,6 +438,7 @@ export default class DownloadingQueue<T>
428
438
  log.info("Stream: init segment request interrupted temporarly.", segment.id);
429
439
  },
430
440
  beforeEnded: () => {
441
+ unlinkCanceller();
431
442
  this._initSegmentRequest = null;
432
443
  isComplete = true;
433
444
  },
@@ -446,6 +457,7 @@ export default class DownloadingQueue<T>
446
457
  }, canceller.signal);
447
458
 
448
459
  request.catch((error : unknown) => {
460
+ unlinkCanceller();
449
461
  if (!isComplete) {
450
462
  isComplete = true;
451
463
  this.stop();
@@ -0,0 +1,26 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3
+ /* eslint-disable @typescript-eslint/no-var-requires */
4
+ /* eslint-disable @typescript-eslint/no-unsafe-call */
5
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
6
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
7
+
8
+ describe("Features list - DEBUG_ELEMENT", () => {
9
+ beforeEach(() => {
10
+ jest.resetModules();
11
+ });
12
+
13
+ it("should add DEBUG_ELEMENT in the current features", () => {
14
+ const feat = {};
15
+ jest.mock("../../../core/api/debug", () => ({ __esModule: true as const,
16
+ default: feat }));
17
+ const addFeature = jest.requireActual("../debug_element").default;
18
+
19
+ const featureObject : {
20
+ createDebugElement? : unknown;
21
+ } = {};
22
+ addFeature(featureObject);
23
+ expect(featureObject).toEqual({ createDebugElement: {} });
24
+ expect(featureObject.createDebugElement).toBe(feat);
25
+ });
26
+ });
@@ -0,0 +1,13 @@
1
+ import createDebugElement from "../../core/api/debug";
2
+ import { IFeaturesObject } from "../../features/types";
3
+
4
+ /**
5
+ * Add ability to parse SAMI text tracks in an HTML textrack mode.
6
+ * @param {Object} features
7
+ */
8
+ function addDebugElementFeature(features : IFeaturesObject) : void {
9
+ features.createDebugElement = createDebugElement;
10
+ }
11
+
12
+ export { addDebugElementFeature as DEBUG_ELEMENT };
13
+ export default addDebugElementFeature;
@@ -15,5 +15,6 @@
15
15
  */
16
16
 
17
17
  export { DASH_WASM } from "./dash_wasm";
18
+ export { DEBUG_ELEMENT } from "./debug_element";
18
19
  export { LOCAL_MANIFEST } from "./local";
19
20
  export { METAPLAYLIST } from "./metaplaylist";
@@ -18,6 +18,7 @@ import { MediaSource_ } from "../../../compat";
18
18
  import { resetMediaSource } from "../../../core/init/utils/create_media_source";
19
19
  import { AudioVideoSegmentBuffer } from "../../../core/segment_buffers/implementations";
20
20
  import log from "../../../log";
21
+ import createCancellablePromise from "../../../utils/create_cancellable_promise";
21
22
  import isNonEmptyString from "../../../utils/is_non_empty_string";
22
23
  import { CancellationSignal } from "../../../utils/task_canceller";
23
24
 
@@ -33,7 +34,7 @@ export default function prepareSourceBuffer(
33
34
  codec: string,
34
35
  cleanUpSignal: CancellationSignal
35
36
  ): Promise<AudioVideoSegmentBuffer> {
36
- return new Promise((resolve, reject) => {
37
+ return createCancellablePromise(cleanUpSignal, (resolve, reject) => {
37
38
  if (MediaSource_ == null) {
38
39
  throw new Error("No MediaSource Object was found in the current browser.");
39
40
  }
@@ -49,15 +50,17 @@ export default function prepareSourceBuffer(
49
50
 
50
51
  log.info("Init: Attaching MediaSource URL to the media element", objectURL);
51
52
  videoElement.src = objectURL;
53
+ cleanUpSignal.register(() => {
54
+ resetMediaSource(videoElement, mediaSource, objectURL);
55
+ });
52
56
 
53
57
  mediaSource.addEventListener("sourceopen", onSourceOpen);
54
58
  mediaSource.addEventListener("webkitsourceopen", onSourceOpen);
55
59
 
56
- cleanUpSignal.register(() => {
60
+ return () => {
57
61
  mediaSource.removeEventListener("sourceopen", onSourceOpen);
58
62
  mediaSource.removeEventListener("webkitsourceopen", onSourceOpen);
59
- resetMediaSource(videoElement, mediaSource, objectURL);
60
- });
63
+ };
61
64
 
62
65
  function onSourceOpen() {
63
66
  try {
@@ -243,15 +243,16 @@ export default class VideoThumbnailLoader {
243
243
  if (pending !== undefined) {
244
244
  promises.push(pending.promise);
245
245
  } else {
246
- const requestCanceller = new TaskCanceller({
247
- cancelOn: lastRepInfo.cleaner.signal,
248
- });
246
+ const requestCanceller = new TaskCanceller();
247
+ const unlinkSignal = requestCanceller
248
+ .linkToSignal(lastRepInfo.cleaner.signal);
249
249
  const segmentInfo = objectAssign({ segment },
250
250
  content);
251
251
  const prom = loadAndPushSegment(segmentInfo,
252
252
  segmentBuffer,
253
253
  lastRepInfo.segmentFetcher,
254
- requestCanceller.signal);
254
+ requestCanceller.signal)
255
+ .finally(unlinkSignal);
255
256
  const newReq = {
256
257
  segmentId: segment.id,
257
258
  canceller: requestCanceller,
@@ -48,6 +48,7 @@ describe("Features - initializeFeaturesObject", () => {
48
48
  HTML_VTT: 0,
49
49
  LOCAL_MANIFEST: 0,
50
50
  METAPLAYLIST: 0,
51
+ DEBUG_ELEMENT: 0,
51
52
  NATIVE_SAMI: 0,
52
53
  NATIVE_SRT: 0,
53
54
  NATIVE_TTML: 0,
@@ -78,6 +79,7 @@ describe("Features - initializeFeaturesObject", () => {
78
79
  HTML_VTT: 1,
79
80
  LOCAL_MANIFEST: 1,
80
81
  METAPLAYLIST: 1,
82
+ DEBUG_ELEMENT: 1,
81
83
  NATIVE_SAMI: 1,
82
84
  NATIVE_SRT: 1,
83
85
  NATIVE_TTML: 1,
@@ -114,6 +116,7 @@ describe("Features - initializeFeaturesObject", () => {
114
116
  wasm: null,
115
117
  },
116
118
  ContentDecryptor: jest.requireActual("../../core/decrypt/index").default,
119
+ createDebugElement: jest.requireActual("../../core/api/debug").default,
117
120
  directfile: {
118
121
  initDirectFile: jest.requireActual("../../core/init/directfile_content_initializer").default,
119
122
  mediaElementTrackChoiceManager:
@@ -161,6 +164,7 @@ describe("Features - initializeFeaturesObject", () => {
161
164
  HTML_VTT: 1,
162
165
  LOCAL_MANIFEST: 0,
163
166
  METAPLAYLIST: 0,
167
+ DEBUG_ELEMENT: 0,
164
168
  NATIVE_SAMI: 0,
165
169
  NATIVE_SRT: 0,
166
170
  NATIVE_TTML: 0,
@@ -203,6 +207,7 @@ describe("Features - initializeFeaturesObject", () => {
203
207
  HTML_VTT: 0,
204
208
  LOCAL_MANIFEST: 0,
205
209
  METAPLAYLIST: 0,
210
+ DEBUG_ELEMENT: 0,
206
211
  NATIVE_SAMI: 0,
207
212
  NATIVE_SRT: 0,
208
213
  NATIVE_TTML: 0,
@@ -245,6 +250,7 @@ describe("Features - initializeFeaturesObject", () => {
245
250
  HTML_VTT: 0,
246
251
  LOCAL_MANIFEST: 0,
247
252
  METAPLAYLIST: 0,
253
+ DEBUG_ELEMENT: 0,
248
254
  NATIVE_SAMI: 0,
249
255
  NATIVE_SRT: 0,
250
256
  NATIVE_TTML: 0,
@@ -287,6 +293,7 @@ describe("Features - initializeFeaturesObject", () => {
287
293
  HTML_VTT: 0,
288
294
  LOCAL_MANIFEST: 0,
289
295
  METAPLAYLIST: 0,
296
+ DEBUG_ELEMENT: 0,
290
297
  NATIVE_SAMI: 0,
291
298
  NATIVE_SRT: 0,
292
299
  NATIVE_TTML: 0,
@@ -329,6 +336,7 @@ describe("Features - initializeFeaturesObject", () => {
329
336
  HTML_VTT: 0,
330
337
  LOCAL_MANIFEST: 0,
331
338
  METAPLAYLIST: 0,
339
+ DEBUG_ELEMENT: 0,
332
340
  NATIVE_SAMI: 0,
333
341
  NATIVE_SRT: 0,
334
342
  NATIVE_TTML: 0,
@@ -371,6 +379,7 @@ describe("Features - initializeFeaturesObject", () => {
371
379
  HTML_VTT: 0,
372
380
  LOCAL_MANIFEST: 0,
373
381
  METAPLAYLIST: 0,
382
+ DEBUG_ELEMENT: 0,
374
383
  NATIVE_SAMI: 1,
375
384
  NATIVE_SRT: 0,
376
385
  NATIVE_TTML: 0,
@@ -413,6 +422,7 @@ describe("Features - initializeFeaturesObject", () => {
413
422
  HTML_VTT: 0,
414
423
  LOCAL_MANIFEST: 0,
415
424
  METAPLAYLIST: 0,
425
+ DEBUG_ELEMENT: 0,
416
426
  NATIVE_SAMI: 0,
417
427
  NATIVE_SRT: 0,
418
428
  NATIVE_TTML: 1,
@@ -455,6 +465,7 @@ describe("Features - initializeFeaturesObject", () => {
455
465
  HTML_VTT: 0,
456
466
  LOCAL_MANIFEST: 0,
457
467
  METAPLAYLIST: 0,
468
+ DEBUG_ELEMENT: 0,
458
469
  NATIVE_SAMI: 0,
459
470
  NATIVE_SRT: 1,
460
471
  NATIVE_TTML: 0,
@@ -22,6 +22,7 @@ import { IFeaturesObject } from "./types";
22
22
  */
23
23
  const features : IFeaturesObject = { dashParsers: { wasm: null,
24
24
  js: null },
25
+ createDebugElement: null,
25
26
  directfile: null,
26
27
  ContentDecryptor: null,
27
28
  htmlTextTracksBuffer: null,