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

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 (183) hide show
  1. package/.eslintrc.js +8 -0
  2. package/CHANGELOG.md +5 -1
  3. package/VERSION +1 -1
  4. package/dist/_esm5.processed/compat/browser_detection.d.ts +23 -12
  5. package/dist/_esm5.processed/compat/browser_detection.js +80 -38
  6. package/dist/_esm5.processed/compat/can_reuse_media_keys.js +2 -2
  7. package/dist/_esm5.processed/compat/eme/close_session.js +2 -2
  8. package/dist/_esm5.processed/compat/event_listeners.js +1 -1
  9. package/dist/_esm5.processed/config.d.ts +2 -0
  10. package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +4 -2
  11. package/dist/_esm5.processed/core/api/debug/buffer_graph.d.ts +28 -0
  12. package/dist/_esm5.processed/core/api/debug/buffer_graph.js +175 -0
  13. package/dist/_esm5.processed/core/api/debug/buffer_size_graph.d.ts +10 -0
  14. package/dist/_esm5.processed/core/api/debug/buffer_size_graph.js +104 -0
  15. package/dist/_esm5.processed/core/api/debug/constants.d.ts +2 -0
  16. package/dist/_esm5.processed/core/api/debug/constants.js +2 -0
  17. package/dist/_esm5.processed/core/api/debug/index.d.ts +2 -0
  18. package/dist/_esm5.processed/core/api/debug/index.js +2 -0
  19. package/dist/_esm5.processed/core/api/debug/modules/general_info.d.ts +3 -0
  20. package/dist/_esm5.processed/core/api/debug/modules/general_info.js +199 -0
  21. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.d.ts +4 -0
  22. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.js +121 -0
  23. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.d.ts +3 -0
  24. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.js +35 -0
  25. package/dist/_esm5.processed/core/api/debug/render.d.ts +3 -0
  26. package/dist/_esm5.processed/core/api/debug/render.js +32 -0
  27. package/dist/_esm5.processed/core/api/debug/utils.d.ts +39 -0
  28. package/dist/_esm5.processed/core/api/debug/utils.js +57 -0
  29. package/dist/_esm5.processed/core/api/playback_observer.js +3 -2
  30. package/dist/_esm5.processed/core/api/public_api.d.ts +3 -0
  31. package/dist/_esm5.processed/core/api/public_api.js +25 -14
  32. package/dist/_esm5.processed/core/api/utils.js +3 -3
  33. package/dist/_esm5.processed/core/decrypt/__tests__/__global__/utils.d.ts +32 -13
  34. package/dist/_esm5.processed/core/decrypt/__tests__/__global__/utils.js +28 -7
  35. package/dist/_esm5.processed/core/decrypt/attach_media_keys.js +1 -1
  36. package/dist/_esm5.processed/core/decrypt/content_decryptor.js +1 -1
  37. package/dist/_esm5.processed/core/decrypt/find_key_system.js +33 -24
  38. package/dist/_esm5.processed/core/decrypt/session_events_listener.js +54 -50
  39. package/dist/_esm5.processed/core/decrypt/utils/check_key_statuses.js +4 -0
  40. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.d.ts +17 -8
  41. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.js +10 -6
  42. package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.js +5 -4
  43. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +22 -5
  44. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +37 -21
  45. package/dist/_esm5.processed/core/fetchers/segment/task_prioritizer.js +21 -23
  46. package/dist/_esm5.processed/core/fetchers/utils/schedule_request.js +17 -7
  47. package/dist/_esm5.processed/core/init/directfile_content_initializer.js +1 -1
  48. package/dist/_esm5.processed/core/init/media_source_content_initializer.js +27 -31
  49. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.js +2 -2
  50. package/dist/_esm5.processed/core/init/utils/create_media_source.js +3 -12
  51. package/dist/_esm5.processed/core/init/utils/end_of_stream.js +6 -3
  52. package/dist/_esm5.processed/core/init/utils/get_loaded_reference.js +2 -1
  53. package/dist/_esm5.processed/core/init/utils/initial_seek_and_play.js +9 -5
  54. package/dist/_esm5.processed/core/init/utils/initialize_content_decryption.js +2 -1
  55. package/dist/_esm5.processed/core/init/utils/media_duration_updater.js +23 -19
  56. package/dist/_esm5.processed/core/init/utils/rebuffering_controller.js +1 -1
  57. package/dist/_esm5.processed/core/init/utils/stream_events_emitter/stream_events_emitter.js +6 -4
  58. package/dist/_esm5.processed/core/init/utils/throw_on_media_error.js +1 -1
  59. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +7 -10
  60. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +4 -2
  61. package/dist/_esm5.processed/core/segment_buffers/segment_buffers_store.js +13 -9
  62. package/dist/_esm5.processed/core/stream/adaptation/adaptation_stream.js +25 -16
  63. package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +26 -12
  64. package/dist/_esm5.processed/core/stream/period/period_stream.js +11 -10
  65. package/dist/_esm5.processed/core/stream/representation/representation_stream.js +15 -15
  66. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.js +1 -1
  67. package/dist/_esm5.processed/core/stream/representation/utils/downloading_queue.js +16 -6
  68. package/dist/_esm5.processed/default_config.d.ts +16 -0
  69. package/dist/_esm5.processed/default_config.js +19 -0
  70. package/dist/_esm5.processed/experimental/features/debug_element.d.ts +8 -0
  71. package/dist/_esm5.processed/experimental/features/debug_element.js +10 -0
  72. package/dist/_esm5.processed/experimental/features/index.d.ts +1 -0
  73. package/dist/_esm5.processed/experimental/features/index.js +1 -0
  74. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.js +7 -4
  75. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +8 -4
  76. package/dist/_esm5.processed/features/features_object.js +1 -0
  77. package/dist/_esm5.processed/features/initialize_features.js +13 -10
  78. package/dist/_esm5.processed/features/types.d.ts +3 -0
  79. package/dist/_esm5.processed/manifest/adaptation.js +4 -0
  80. package/dist/_esm5.processed/manifest/manifest.js +2 -0
  81. package/dist/_esm5.processed/manifest/representation.js +11 -4
  82. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_adaptation_sets.js +105 -137
  83. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +25 -5
  84. package/dist/_esm5.processed/public_types.d.ts +1 -0
  85. package/dist/_esm5.processed/transports/dash/add_segment_integrity_checks_to_loader.js +15 -11
  86. package/dist/_esm5.processed/transports/dash/low_latency_segment_loader.js +2 -2
  87. package/dist/_esm5.processed/transports/dash/manifest_parser.js +1 -1
  88. package/dist/_esm5.processed/transports/dash/segment_loader.js +4 -4
  89. package/dist/_esm5.processed/transports/local/segment_loader.js +13 -26
  90. package/dist/_esm5.processed/transports/smooth/segment_loader.js +4 -4
  91. package/dist/_esm5.processed/transports/utils/call_custom_manifest_loader.js +3 -3
  92. package/dist/_esm5.processed/utils/cancellable_sleep.js +4 -10
  93. package/dist/_esm5.processed/utils/create_cancellable_promise.d.ts +26 -0
  94. package/dist/_esm5.processed/utils/create_cancellable_promise.js +52 -0
  95. package/dist/_esm5.processed/utils/reference.js +6 -0
  96. package/dist/_esm5.processed/utils/request/xhr.js +1 -1
  97. package/dist/_esm5.processed/utils/task_canceller.d.ts +34 -15
  98. package/dist/_esm5.processed/utils/task_canceller.js +55 -22
  99. package/dist/rx-player.js +880 -677
  100. package/dist/rx-player.min.js +1 -1
  101. package/jest.config.js +1 -0
  102. package/package.json +19 -18
  103. package/scripts/build/constants.d.ts +1 -0
  104. package/scripts/report_build_sizes +4 -0
  105. package/sonar-project.properties +1 -1
  106. package/src/compat/browser_detection.ts +99 -52
  107. package/src/compat/can_reuse_media_keys.ts +5 -2
  108. package/src/compat/eme/close_session.ts +2 -2
  109. package/src/compat/event_listeners.ts +1 -1
  110. package/src/core/adaptive/adaptive_representation_selector.ts +4 -2
  111. package/src/core/api/debug/buffer_graph.ts +247 -0
  112. package/src/core/api/debug/buffer_size_graph.ts +130 -0
  113. package/src/core/api/debug/constants.ts +2 -0
  114. package/src/core/api/debug/index.ts +3 -0
  115. package/src/core/api/debug/modules/general_info.ts +204 -0
  116. package/src/core/api/debug/modules/segment_buffer_content.ts +155 -0
  117. package/src/core/api/debug/modules/segment_buffer_size.ts +48 -0
  118. package/src/core/api/debug/render.ts +40 -0
  119. package/src/core/api/debug/utils.ts +103 -0
  120. package/src/core/api/playback_observer.ts +4 -2
  121. package/src/core/api/public_api.ts +28 -14
  122. package/src/core/api/utils.ts +3 -3
  123. package/src/core/decrypt/__tests__/__global__/utils.ts +61 -40
  124. package/src/core/decrypt/attach_media_keys.ts +1 -1
  125. package/src/core/decrypt/content_decryptor.ts +1 -1
  126. package/src/core/decrypt/find_key_system.ts +36 -35
  127. package/src/core/decrypt/session_events_listener.ts +57 -56
  128. package/src/core/decrypt/utils/check_key_statuses.ts +6 -0
  129. package/src/core/fetchers/cdn_prioritizer.ts +18 -9
  130. package/src/core/fetchers/manifest/manifest_fetcher.ts +5 -4
  131. package/src/core/fetchers/segment/segment_fetcher.ts +36 -14
  132. package/src/core/fetchers/segment/task_prioritizer.ts +25 -30
  133. package/src/core/fetchers/utils/schedule_request.ts +18 -7
  134. package/src/core/init/directfile_content_initializer.ts +1 -1
  135. package/src/core/init/media_source_content_initializer.ts +37 -41
  136. package/src/core/init/utils/content_time_boundaries_observer.ts +2 -2
  137. package/src/core/init/utils/create_media_source.ts +4 -16
  138. package/src/core/init/utils/end_of_stream.ts +6 -3
  139. package/src/core/init/utils/get_loaded_reference.ts +2 -1
  140. package/src/core/init/utils/initial_seek_and_play.ts +9 -5
  141. package/src/core/init/utils/initialize_content_decryption.ts +2 -1
  142. package/src/core/init/utils/media_duration_updater.ts +25 -20
  143. package/src/core/init/utils/rebuffering_controller.ts +1 -1
  144. package/src/core/init/utils/stream_events_emitter/stream_events_emitter.ts +6 -4
  145. package/src/core/init/utils/throw_on_media_error.ts +1 -1
  146. package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +7 -11
  147. package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +4 -2
  148. package/src/core/segment_buffers/segment_buffers_store.ts +16 -13
  149. package/src/core/stream/adaptation/adaptation_stream.ts +28 -19
  150. package/src/core/stream/orchestrator/stream_orchestrator.ts +26 -12
  151. package/src/core/stream/period/period_stream.ts +11 -10
  152. package/src/core/stream/representation/representation_stream.ts +15 -15
  153. package/src/core/stream/representation/utils/append_segment_to_buffer.ts +1 -1
  154. package/src/core/stream/representation/utils/downloading_queue.ts +16 -4
  155. package/src/default_config.ts +30 -9
  156. package/src/experimental/features/__tests__/debug_element.test.ts +26 -0
  157. package/src/experimental/features/debug_element.ts +13 -0
  158. package/src/experimental/features/index.ts +1 -0
  159. package/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts +7 -4
  160. package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +8 -4
  161. package/src/features/__tests__/initialize_features.test.ts +11 -0
  162. package/src/features/features_object.ts +1 -0
  163. package/src/features/initialize_features.ts +15 -10
  164. package/src/features/types.ts +9 -0
  165. package/src/manifest/adaptation.ts +7 -0
  166. package/src/manifest/manifest.ts +4 -0
  167. package/src/manifest/representation.ts +10 -4
  168. package/src/parsers/manifest/dash/common/parse_adaptation_sets.ts +116 -151
  169. package/src/parsers/manifest/dash/common/parse_representations.ts +21 -4
  170. package/src/public_types.ts +1 -0
  171. package/src/transports/dash/add_segment_integrity_checks_to_loader.ts +31 -22
  172. package/src/transports/dash/low_latency_segment_loader.ts +2 -2
  173. package/src/transports/dash/manifest_parser.ts +1 -1
  174. package/src/transports/dash/segment_loader.ts +4 -4
  175. package/src/transports/local/segment_loader.ts +14 -30
  176. package/src/transports/smooth/segment_loader.ts +4 -4
  177. package/src/transports/utils/call_custom_manifest_loader.ts +3 -3
  178. package/src/typings/globals.d.ts +2 -0
  179. package/src/utils/cancellable_sleep.ts +5 -14
  180. package/src/utils/create_cancellable_promise.ts +69 -0
  181. package/src/utils/reference.ts +6 -0
  182. package/src/utils/request/xhr.ts +1 -1
  183. package/src/utils/task_canceller.ts +63 -34
@@ -217,7 +217,7 @@ export default class PlaybackObserver {
217
217
  options? : { includeLastObservation? : boolean | undefined;
218
218
  clearSignal? : CancellationSignal | undefined; }
219
219
  ) {
220
- if (this._canceller.isUsed || options?.clearSignal?.isCancelled === true) {
220
+ if (this._canceller.isUsed() || options?.clearSignal?.isCancelled() === true) {
221
221
  return noop;
222
222
  }
223
223
  this._observationRef.onUpdate(cb, {
@@ -971,7 +971,9 @@ function generateReadOnlyObserver<TSource, TDest>(
971
971
  options? : { includeLastObservation? : boolean | undefined;
972
972
  clearSignal? : CancellationSignal | undefined; }
973
973
  ) : void {
974
- if (cancellationSignal.isCancelled || options?.clearSignal?.isCancelled === true) {
974
+ if (cancellationSignal.isCancelled() ||
975
+ options?.clearSignal?.isCancelled() === true)
976
+ {
975
977
  return ;
976
978
  }
977
979
  mappedRef.onUpdate(cb, {
@@ -364,7 +364,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
364
364
  // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1194624
365
365
  videoElement.preload = "auto";
366
366
 
367
- this.version = /* PLAYER_VERSION */"3.30.0-dev.2023020100";
367
+ this.version = /* PLAYER_VERSION */"3.30.0-dev.2023030200";
368
368
  this.log = log;
369
369
  this.state = "STOPPED";
370
370
  this.videoElement = videoElement;
@@ -602,6 +602,21 @@ class Player extends EventEmitter<IPublicAPIEvent> {
602
602
  this._priv_initializeContentPlayback(newOptions);
603
603
  }
604
604
 
605
+ public createDebugElement(element : HTMLElement) : {
606
+ dispose() : void;
607
+ } {
608
+ if (features.createDebugElement === null) {
609
+ throw new Error("Feature `DEBUG_ELEMENT` not added to the RxPlayer");
610
+ }
611
+ const canceller = new TaskCanceller() ;
612
+ features.createDebugElement(element, this, canceller.signal);
613
+ return {
614
+ dispose() {
615
+ canceller.cancel();
616
+ },
617
+ };
618
+ }
619
+
605
620
  /**
606
621
  * From given options, initialize content playback.
607
622
  * @param {Object} options
@@ -764,7 +779,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
764
779
  defaultTextTrack,
765
780
  currentContentCanceller.signal
766
781
  );
767
- if (currentContentCanceller.isUsed) {
782
+ if (currentContentCanceller.isUsed()) {
768
783
  return;
769
784
  }
770
785
  initializer = new features.directfile.initDirectFile({ autoPlay,
@@ -943,7 +958,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
943
958
  updateReloadingMetadata(newState);
944
959
  this._priv_setPlayerState(newState);
945
960
 
946
- if (currentContentCanceller.isUsed) {
961
+ if (currentContentCanceller.isUsed()) {
947
962
  return;
948
963
  }
949
964
 
@@ -953,9 +968,8 @@ class Player extends EventEmitter<IPublicAPIEvent> {
953
968
  seekEventsCanceller = null;
954
969
  }
955
970
  } else if (isLoadedState(this.state)) {
956
- seekEventsCanceller = new TaskCanceller({
957
- cancelOn: currentContentCanceller.signal,
958
- });
971
+ seekEventsCanceller = new TaskCanceller();
972
+ seekEventsCanceller.linkToSignal(currentContentCanceller.signal);
959
973
  emitSeekEvents(videoElement,
960
974
  playbackObserver,
961
975
  () => this.trigger("seeking", null),
@@ -966,7 +980,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
966
980
  // Previous call could have performed all kind of side-effects, thus,
967
981
  // we re-check the current state associated to the RxPlayer
968
982
  if (this.state === PLAYER_STATES.ENDED && this._priv_stopAtEnd) {
969
- currentContentCanceller.cancel();
983
+ this.stop();
970
984
  }
971
985
  }, { emitCurrentValue: true, clearSignal: currentContentCanceller.signal });
972
986
 
@@ -2468,20 +2482,20 @@ class Player extends EventEmitter<IPublicAPIEvent> {
2468
2482
  this._priv_triggerAvailableBitratesChangeEvent("availableAudioBitratesChange",
2469
2483
  this.getAvailableAudioBitrates(),
2470
2484
  cancelSignal);
2471
- if (contentInfos.currentContentCanceller.isUsed) {
2485
+ if (contentInfos.currentContentCanceller.isUsed()) {
2472
2486
  return;
2473
2487
  }
2474
2488
  this._priv_triggerAvailableBitratesChangeEvent("availableVideoBitratesChange",
2475
2489
  this.getAvailableVideoBitrates(),
2476
2490
  cancelSignal);
2477
- if (contentInfos.currentContentCanceller.isUsed) {
2491
+ if (contentInfos.currentContentCanceller.isUsed()) {
2478
2492
  return;
2479
2493
  }
2480
2494
  const audioBitrate = this._priv_getCurrentRepresentations()?.audio?.bitrate ?? -1;
2481
2495
  this._priv_triggerCurrentBitrateChangeEvent("audioBitrateChange",
2482
2496
  audioBitrate,
2483
2497
  cancelSignal);
2484
- if (contentInfos.currentContentCanceller.isUsed) {
2498
+ if (contentInfos.currentContentCanceller.isUsed()) {
2485
2499
  return;
2486
2500
  }
2487
2501
 
@@ -2833,7 +2847,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
2833
2847
  currentContentCancelSignal : CancellationSignal
2834
2848
  ) : void {
2835
2849
  const prevVal = this._priv_contentEventsMemory[event];
2836
- if (!currentContentCancelSignal.isCancelled &&
2850
+ if (!currentContentCancelSignal.isCancelled() &&
2837
2851
  (prevVal === undefined || !areArraysOfNumbersEqual(newVal, prevVal)))
2838
2852
  {
2839
2853
  this._priv_contentEventsMemory[event] = newVal;
@@ -2853,7 +2867,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
2853
2867
  newVal : number,
2854
2868
  currentContentCancelSignal : CancellationSignal
2855
2869
  ) : void {
2856
- if (!currentContentCancelSignal.isCancelled &&
2870
+ if (!currentContentCancelSignal.isCancelled() &&
2857
2871
  newVal !== this._priv_contentEventsMemory[event])
2858
2872
  {
2859
2873
  this._priv_contentEventsMemory[event] = newVal;
@@ -2886,7 +2900,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
2886
2900
  arg : IEventPayload<IPublicAPIEvent, TEventName>,
2887
2901
  currentContentCancelSignal : CancellationSignal
2888
2902
  ) {
2889
- if (!currentContentCancelSignal.isCancelled) {
2903
+ if (!currentContentCancelSignal.isCancelled()) {
2890
2904
  this.trigger(evt, arg);
2891
2905
  }
2892
2906
  }
@@ -2971,7 +2985,7 @@ class Player extends EventEmitter<IPublicAPIEvent> {
2971
2985
  return mediaElementTrackChoiceManager;
2972
2986
  }
2973
2987
  }
2974
- Player.version = /* PLAYER_VERSION */"3.30.0-dev.2023020100";
2988
+ Player.version = /* PLAYER_VERSION */"3.30.0-dev.2023030200";
2975
2989
 
2976
2990
  /** Every events sent by the RxPlayer's public API. */
2977
2991
  interface IPublicAPIEvent {
@@ -48,14 +48,14 @@ export function emitSeekEvents(
48
48
  onSeeked: () => void,
49
49
  cancelSignal : CancellationSignal
50
50
  ) : void {
51
- if (cancelSignal.isCancelled || mediaElement === null) {
51
+ if (cancelSignal.isCancelled() || mediaElement === null) {
52
52
  return ;
53
53
  }
54
54
 
55
55
  let wasSeeking = playbackObserver.getReference().getValue().seeking;
56
56
  if (wasSeeking) {
57
57
  onSeeking();
58
- if (cancelSignal.isCancelled) {
58
+ if (cancelSignal.isCancelled()) {
59
59
  return;
60
60
  }
61
61
  }
@@ -94,7 +94,7 @@ export function constructPlayerStateReference(
94
94
  initializer.addEventListener("loaded", () => {
95
95
  if (playerStateRef.getValue() === PLAYER_STATES.LOADING) {
96
96
  playerStateRef.setValue(PLAYER_STATES.LOADED);
97
- if (!cancelSignal.isCancelled) {
97
+ if (!cancelSignal.isCancelled()) {
98
98
  const newState = getLoadedContentState(mediaElement, null);
99
99
  if (newState !== PLAYER_STATES.PAUSED) {
100
100
  playerStateRef.setValue(newState);
@@ -40,48 +40,68 @@ import {
40
40
  import { CancellationSignal } from "../../../../utils/task_canceller";
41
41
 
42
42
  /** Default MediaKeySystemAccess configuration used by the RxPlayer. */
43
- export const defaultKSConfig = [{
44
- audioCapabilities: [ { contentType: "audio/mp4;codecs=\"mp4a.40.2\"" },
45
- { contentType: "audio/webm;codecs=opus" } ],
46
- distinctiveIdentifier: "optional" as const,
47
- initDataTypes: ["cenc"] as const,
48
- persistentState: "optional" as const,
49
- sessionTypes: ["temporary"] as const,
50
- videoCapabilities: [ { contentType: "video/mp4;codecs=\"avc1.4d401e\"" },
51
- { contentType: "video/mp4;codecs=\"avc1.42e01e\"" },
52
- { contentType: "video/webm;codecs=\"vp8\"" } ],
53
- }];
43
+ export const defaultKSConfig = [
44
+ {
45
+ audioCapabilities: [ { contentType: "audio/mp4;codecs=\"mp4a.40.2\"" },
46
+ { contentType: "audio/webm;codecs=opus" } ],
47
+ distinctiveIdentifier: "optional" as const,
48
+ initDataTypes: ["cenc"] as const,
49
+ persistentState: "optional" as const,
50
+ sessionTypes: ["temporary"] as const,
51
+ videoCapabilities: [ { contentType: "video/mp4;codecs=\"avc1.4d401e\"" },
52
+ { contentType: "video/mp4;codecs=\"avc1.42e01e\"" },
53
+ { contentType: "video/webm;codecs=\"vp8\"" } ],
54
+ },
55
+ {
56
+ audioCapabilities: undefined,
57
+ distinctiveIdentifier: "optional" as const,
58
+ initDataTypes: ["cenc"] as const,
59
+ persistentState: "optional" as const,
60
+ sessionTypes: ["temporary"] as const,
61
+ videoCapabilities: undefined,
62
+ },
63
+ ];
54
64
 
55
65
  /**
56
66
  * Default "com.microsoft.playready.recommendation" MediaKeySystemAccess
57
67
  * configuration used by the RxPlayer.
58
68
  */
59
- export const defaultPRRecommendationKSConfig = [{
60
- audioCapabilities: [ { robustness: "3000",
61
- contentType: "audio/mp4;codecs=\"mp4a.40.2\"" },
62
- { robustness: "3000",
63
- contentType: "audio/webm;codecs=opus" },
64
- { robustness: "2000",
65
- contentType: "audio/mp4;codecs=\"mp4a.40.2\"" },
66
- { robustness: "2000",
67
- contentType: "audio/webm;codecs=opus" } ],
68
- distinctiveIdentifier: "optional" as const,
69
- initDataTypes: ["cenc"] as const,
70
- persistentState: "optional" as const,
71
- sessionTypes: ["temporary"] as const,
72
- videoCapabilities: [ { robustness: "3000",
73
- contentType: "video/mp4;codecs=\"avc1.4d401e\"" },
74
- { robustness: "3000",
75
- contentType: "video/mp4;codecs=\"avc1.42e01e\"" },
76
- { robustness: "3000",
77
- contentType: "video/webm;codecs=\"vp8\"" },
78
- { robustness: "2000",
79
- contentType: "video/mp4;codecs=\"avc1.4d401e\"" },
80
- { robustness: "2000",
81
- contentType: "video/mp4;codecs=\"avc1.42e01e\"" },
82
- { robustness: "2000",
83
- contentType: "video/webm;codecs=\"vp8\"" } ],
84
- }];
69
+ export const defaultPRRecommendationKSConfig = [
70
+ {
71
+ audioCapabilities: [ { robustness: "3000",
72
+ contentType: "audio/mp4;codecs=\"mp4a.40.2\"" },
73
+ { robustness: "3000",
74
+ contentType: "audio/webm;codecs=opus" },
75
+ { robustness: "2000",
76
+ contentType: "audio/mp4;codecs=\"mp4a.40.2\"" },
77
+ { robustness: "2000",
78
+ contentType: "audio/webm;codecs=opus" } ],
79
+ distinctiveIdentifier: "optional" as const,
80
+ initDataTypes: ["cenc"] as const,
81
+ persistentState: "optional" as const,
82
+ sessionTypes: ["temporary"] as const,
83
+ videoCapabilities: [ { robustness: "3000",
84
+ contentType: "video/mp4;codecs=\"avc1.4d401e\"" },
85
+ { robustness: "3000",
86
+ contentType: "video/mp4;codecs=\"avc1.42e01e\"" },
87
+ { robustness: "3000",
88
+ contentType: "video/webm;codecs=\"vp8\"" },
89
+ { robustness: "2000",
90
+ contentType: "video/mp4;codecs=\"avc1.4d401e\"" },
91
+ { robustness: "2000",
92
+ contentType: "video/mp4;codecs=\"avc1.42e01e\"" },
93
+ { robustness: "2000",
94
+ contentType: "video/webm;codecs=\"vp8\"" } ],
95
+ },
96
+ {
97
+ audioCapabilities: undefined,
98
+ distinctiveIdentifier: "optional" as const,
99
+ initDataTypes: ["cenc"] as const,
100
+ persistentState: "optional" as const,
101
+ sessionTypes: ["temporary"] as const,
102
+ videoCapabilities: undefined,
103
+ },
104
+ ];
85
105
 
86
106
  /** Default Widevine MediaKeySystemAccess configuration used by the RxPlayer. */
87
107
  export const defaultWidevineConfig = (() => {
@@ -104,9 +124,10 @@ export const defaultWidevineConfig = (() => {
104
124
  { contentType: "audio/webm;codecs=opus",
105
125
  robustness } ];
106
126
  });
107
- return defaultKSConfig.map(conf => {
108
- return { ...conf, audioCapabilities, videoCapabilities };
109
- });
127
+ return [
128
+ { ...defaultKSConfig[0], audioCapabilities, videoCapabilities },
129
+ defaultKSConfig[1],
130
+ ];
110
131
  })();
111
132
 
112
133
  /**
@@ -62,7 +62,7 @@ export default async function attachMediaKeys(
62
62
 
63
63
  // If this task has been cancelled while we were closing previous sessions,
64
64
  // stop now (and thus avoid setting the new media keys);
65
- if (cancelSignal.isCancelled) {
65
+ if (cancelSignal.isCancelled()) {
66
66
  throw cancelSignal.cancellationError;
67
67
  }
68
68
 
@@ -727,7 +727,7 @@ export default class ContentDecryptor extends EventEmitter<IContentDecryptorEven
727
727
  * formatted and sent in an "error" event.
728
728
  */
729
729
  private _onFatalError(err : unknown) : void {
730
- if (this._canceller.isUsed) {
730
+ if (this._canceller.isUsed()) {
731
731
  return;
732
732
  }
733
733
  const formattedErr = err instanceof Error ?
@@ -155,7 +155,9 @@ function buildKeySystemConfigurations(
155
155
  if (keySystem.distinctiveIdentifierRequired === true) {
156
156
  distinctiveIdentifier = "required";
157
157
  }
158
- const { EME_DEFAULT_WIDEVINE_ROBUSTNESSES,
158
+ const { EME_DEFAULT_AUDIO_CODECS,
159
+ EME_DEFAULT_VIDEO_CODECS,
160
+ EME_DEFAULT_WIDEVINE_ROBUSTNESSES,
159
161
  EME_DEFAULT_PLAYREADY_ROBUSTNESSES } = config.getCurrent();
160
162
 
161
163
  // Set robustness, in order of consideration:
@@ -206,42 +208,41 @@ function buildKeySystemConfigurations(
206
208
  // https://www.w3.org/TR/encrypted-media/#get-supported-configuration-and-consent
207
209
 
208
210
  const videoCapabilities: IMediaCapability[] =
209
- flatMap(videoRobustnesses, (robustness) =>
210
- ["video/mp4;codecs=\"avc1.4d401e\"",
211
- "video/mp4;codecs=\"avc1.42e01e\"",
212
- "video/webm;codecs=\"vp8\""].map(contentType => {
213
- return robustness !== undefined ? { contentType, robustness } :
214
- { contentType };
215
- }));
211
+ flatMap(videoRobustnesses, (robustness) => {
212
+ return EME_DEFAULT_VIDEO_CODECS.map(contentType => {
213
+ return robustness === undefined ? { contentType } :
214
+ { contentType, robustness };
215
+ });
216
+ });
216
217
 
217
218
  const audioCapabilities: IMediaCapability[] =
218
- flatMap(audioRobustnesses, (robustness) =>
219
- ["audio/mp4;codecs=\"mp4a.40.2\"",
220
- "audio/webm;codecs=opus"].map(contentType => {
221
- return robustness !== undefined ? { contentType, robustness } :
222
- { contentType };
223
- }));
224
-
225
- // TODO Re-test with a set contentType but an undefined robustness on the
226
- // STBs on which this problem was found.
227
- //
228
- // add another with no {audio,video}Capabilities for some legacy browsers.
229
- // As of today's spec, this should return NotSupported but the first
230
- // candidate configuration should be good, so we should have no downside
231
- // doing that.
232
- // initDataTypes: ["cenc"],
233
- // videoCapabilities: undefined,
234
- // audioCapabilities: undefined,
235
- // distinctiveIdentifier,
236
- // persistentState,
237
- // sessionTypes,
238
-
239
- return [{ initDataTypes: ["cenc"],
240
- videoCapabilities,
241
- audioCapabilities,
242
- distinctiveIdentifier,
243
- persistentState,
244
- sessionTypes }];
219
+ flatMap(audioRobustnesses, (robustness) => {
220
+ return EME_DEFAULT_AUDIO_CODECS.map(contentType => {
221
+ return robustness === undefined ? { contentType } :
222
+ { contentType, robustness };
223
+ });
224
+ });
225
+
226
+ const wantedMediaKeySystemConfiguration : MediaKeySystemConfiguration = {
227
+ initDataTypes: ["cenc"],
228
+ videoCapabilities,
229
+ audioCapabilities,
230
+ distinctiveIdentifier,
231
+ persistentState,
232
+ sessionTypes,
233
+ };
234
+
235
+ return [
236
+ wantedMediaKeySystemConfiguration,
237
+
238
+ // Some legacy implementations have issues with `audioCapabilities` and
239
+ // `videoCapabilities`, so we're including a supplementary
240
+ // `MediaKeySystemConfiguration` without those properties.
241
+ { ...wantedMediaKeySystemConfiguration,
242
+ audioCapabilities: undefined ,
243
+ videoCapabilities: undefined,
244
+ } as unknown as MediaKeySystemConfiguration,
245
+ ];
245
246
  }
246
247
 
247
248
  /**
@@ -58,13 +58,14 @@ export default function SessionEventsListener(
58
58
  const { getLicenseConfig = {} } = keySystemOptions;
59
59
 
60
60
  /** Allows to manually cancel everything the `SessionEventsListener` is doing. */
61
- const manualCanceller = new TaskCanceller({ cancelOn: cancelSignal });
61
+ const manualCanceller = new TaskCanceller();
62
+ manualCanceller.linkToSignal(cancelSignal);
62
63
 
63
64
  if (!isNullOrUndefined(session.closed)) {
64
65
  session.closed
65
66
  .then(() => manualCanceller.cancel())
66
67
  .catch((err) => { // Should never happen
67
- if (cancelSignal.isCancelled) {
68
+ if (cancelSignal.isCancelled()) {
68
69
  return;
69
70
  }
70
71
  manualCanceller.cancel();
@@ -79,8 +80,8 @@ export default function SessionEventsListener(
79
80
 
80
81
  onKeyStatusesChange(session, (keyStatusesEvent) => {
81
82
  handleKeyStatusesChangeEvent(keyStatusesEvent as Event).catch(error => {
82
- if (cancelSignal.isCancelled ||
83
- (manualCanceller.isUsed && error instanceof CancellationSignal))
83
+ if (cancelSignal.isCancelled() ||
84
+ (manualCanceller.isUsed() && error instanceof CancellationSignal))
84
85
  {
85
86
  return;
86
87
  }
@@ -104,7 +105,7 @@ export default function SessionEventsListener(
104
105
  backoffOptions,
105
106
  manualCanceller.signal)
106
107
  .then((licenseObject) => {
107
- if (manualCanceller.isUsed) {
108
+ if (manualCanceller.isUsed()) {
108
109
  return Promise.resolve();
109
110
  }
110
111
  if (isNullOrUndefined(licenseObject)) {
@@ -114,7 +115,7 @@ export default function SessionEventsListener(
114
115
  }
115
116
  })
116
117
  .catch((err : unknown) => {
117
- if (manualCanceller.isUsed) {
118
+ if (manualCanceller.isUsed()) {
118
119
  return;
119
120
  }
120
121
  manualCanceller.cancel();
@@ -133,6 +134,8 @@ export default function SessionEventsListener(
133
134
  });
134
135
  }, manualCanceller.signal);
135
136
 
137
+ checkAndHandleCurrentKeyStatuses();
138
+ return;
136
139
  /**
137
140
  * @param {Event} keyStatusesEvent
138
141
  * @returns {Promise}
@@ -144,22 +147,22 @@ export default function SessionEventsListener(
144
147
 
145
148
  await Promise.all([
146
149
  runOnKeyStatusesChangeCallback(),
147
- Promise.resolve(handleKeyStatusEvent()),
150
+ Promise.resolve(checkAndHandleCurrentKeyStatuses()),
148
151
  ]);
149
152
 
150
153
  async function runOnKeyStatusesChangeCallback() {
151
- if (manualCanceller.isUsed) {
154
+ if (manualCanceller.isUsed()) {
152
155
  return;
153
156
  }
154
157
  if (typeof keySystemOptions.onKeyStatusesChange === "function") {
155
158
  let ret;
156
159
  try {
157
160
  ret = await keySystemOptions.onKeyStatusesChange(keyStatusesEvent, session);
158
- if (manualCanceller.isUsed) {
161
+ if (manualCanceller.isUsed()) {
159
162
  return;
160
163
  }
161
164
  } catch (error) {
162
- if (cancelSignal.isCancelled) {
165
+ if (cancelSignal.isCancelled()) {
163
166
  return;
164
167
  }
165
168
  const err = new EncryptedMediaError("KEY_STATUS_CHANGE_ERROR",
@@ -178,67 +181,65 @@ export default function SessionEventsListener(
178
181
  }
179
182
  }
180
183
  }
184
+ }
181
185
 
182
- /**
183
- * Check current MediaKeyStatus for each key in the given MediaKeySession and:
184
- * - throw if at least one status is a non-recoverable error
185
- * - call warning callback for recoverable errors
186
- * - call onKeyUpdate callback when the MediaKeyStatus of any key is updated
187
- */
188
- function handleKeyStatusEvent() : void {
189
- if (manualCanceller.isUsed || session.keyStatuses.size === 0) {
190
- return ;
191
- }
192
- const { warning, blacklistedKeyIds, whitelistedKeyIds } =
193
- checkKeyStatuses(session, keySystemOptions, keySystem);
194
- if (warning !== undefined) {
195
- callbacks.onWarning(warning);
196
- if (manualCanceller.isUsed) {
197
- return;
198
- }
186
+ /**
187
+ * Check current MediaKeyStatus for each key in the given MediaKeySession and:
188
+ * - throw if at least one status is a non-recoverable error
189
+ * - call warning callback for recoverable errors
190
+ * - call onKeyUpdate callback when the MediaKeyStatus of any key is updated
191
+ */
192
+ function checkAndHandleCurrentKeyStatuses() : void {
193
+ if (manualCanceller.isUsed() || session.keyStatuses.size === 0) {
194
+ return ;
195
+ }
196
+ const { warning, blacklistedKeyIds, whitelistedKeyIds } =
197
+ checkKeyStatuses(session, keySystemOptions, keySystem);
198
+ if (warning !== undefined) {
199
+ callbacks.onWarning(warning);
200
+ if (manualCanceller.isUsed()) {
201
+ return;
199
202
  }
200
- callbacks.onKeyUpdate({ whitelistedKeyIds, blacklistedKeyIds });
201
203
  }
204
+ callbacks.onKeyUpdate({ whitelistedKeyIds, blacklistedKeyIds });
202
205
  }
203
206
 
204
207
  function runGetLicense(
205
208
  message : Uint8Array,
206
209
  messageType : MediaKeyMessageType
207
210
  ) : Promise<BufferSource | null> {
208
- return new Promise((res, rej) => {
209
- log.debug("DRM: Calling `getLicense`", messageType);
210
- const getLicense = keySystemOptions.getLicense(message, messageType);
211
- const getLicenseTimeout = isNullOrUndefined(getLicenseConfig.timeout) ?
212
- 10 * 1000 :
213
- getLicenseConfig.timeout;
214
-
215
- let timeoutId : number | undefined;
216
- if (getLicenseTimeout >= 0) {
217
- timeoutId = setTimeout(() => {
218
- rej(new GetLicenseTimeoutError(
219
- `"getLicense" timeout exceeded (${getLicenseTimeout} ms)`
220
- ));
221
- }, getLicenseTimeout) as unknown as number;
222
- }
223
-
211
+ let timeoutId : number | undefined;
212
+ return new Promise<BufferSource | null>((res, rej) => {
224
213
  try {
225
- Promise.resolve(getLicense).then(
226
- (val) => {
227
- clearTimeoutIfOne();
228
- res(val);
229
- },
230
- (err) => {
231
- clearTimeoutIfOne();
232
- rej(err);
233
- });
214
+ log.debug("DRM: Calling `getLicense`", messageType);
215
+ const getLicense = keySystemOptions.getLicense(message, messageType);
216
+ const getLicenseTimeout = isNullOrUndefined(getLicenseConfig.timeout) ?
217
+ 10 * 1000 :
218
+ getLicenseConfig.timeout;
219
+
220
+ if (getLicenseTimeout >= 0) {
221
+ timeoutId = setTimeout(() => {
222
+ rej(new GetLicenseTimeoutError(
223
+ `"getLicense" timeout exceeded (${getLicenseTimeout} ms)`
224
+ ));
225
+ }, getLicenseTimeout) as unknown as number;
226
+ }
227
+ Promise.resolve(getLicense)
228
+ .then(clearTimeoutAndResolve, clearTimeoutAndReject);
234
229
  } catch (err) {
235
- clearTimeoutIfOne();
236
- rej(err);
230
+ clearTimeoutAndReject(err);
237
231
  }
238
- function clearTimeoutIfOne() {
232
+ function clearTimeoutAndResolve(data : BufferSource | null) {
239
233
  if (timeoutId !== undefined) {
240
234
  clearTimeout(timeoutId);
241
235
  }
236
+ res(data);
237
+ }
238
+ function clearTimeoutAndReject(err : unknown) {
239
+ if (timeoutId !== undefined) {
240
+ clearTimeout(timeoutId);
241
+ }
242
+ rej(err);
242
243
  }
243
244
  });
244
245
  }
@@ -18,6 +18,7 @@ import { ICustomMediaKeySession } from "../../../compat";
18
18
  /* eslint-disable-next-line max-len */
19
19
  import getUUIDKidFromKeyStatusKID from "../../../compat/eme/get_uuid_kid_from_keystatus_kid";
20
20
  import { EncryptedMediaError } from "../../../errors";
21
+ import log from "../../../log";
21
22
  import {
22
23
  IEncryptedMediaErrorKeyStatusObject,
23
24
  IKeySystemOption,
@@ -109,6 +110,11 @@ export default function checkKeyStatuses(
109
110
  new Uint8Array(keyStatusKeyId));
110
111
 
111
112
  const keyStatusObj = { keyId: keyId.buffer, keyStatus };
113
+
114
+ if (log.hasLevel("DEBUG")) {
115
+ log.debug(`DRM: key status update (${bytesToHex(keyId)}): ${keyStatus}`);
116
+ }
117
+
112
118
  switch (keyStatus) {
113
119
  case KEY_STATUSES.EXPIRED: {
114
120
  const error = new EncryptedMediaError(