rx-player 3.26.2 → 3.27.0-dev.20220317

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 (500) hide show
  1. package/.github/workflows/perfs.yml +22 -0
  2. package/CHANGELOG.md +33 -1
  3. package/FILES.md +5 -4
  4. package/VERSION +1 -1
  5. package/dist/_esm5.processed/compat/browser_detection.d.ts +4 -2
  6. package/dist/_esm5.processed/compat/browser_detection.js +4 -2
  7. package/dist/_esm5.processed/compat/eme/close_session.d.ts +11 -5
  8. package/dist/_esm5.processed/compat/eme/close_session.js +144 -36
  9. package/dist/_esm5.processed/compat/eme/custom_media_keys/index.d.ts +3 -5
  10. package/dist/_esm5.processed/compat/eme/custom_media_keys/index.js +27 -24
  11. package/dist/_esm5.processed/compat/eme/custom_media_keys/old_webkit_media_keys.js +53 -34
  12. package/dist/_esm5.processed/compat/eme/custom_media_keys/webkit_media_keys.js +43 -41
  13. package/dist/_esm5.processed/compat/eme/generate_key_request.d.ts +2 -3
  14. package/dist/_esm5.processed/compat/eme/generate_key_request.js +22 -26
  15. package/dist/_esm5.processed/compat/eme/load_session.d.ts +1 -2
  16. package/dist/_esm5.processed/compat/eme/load_session.js +68 -17
  17. package/dist/_esm5.processed/compat/event_listeners.js +2 -1
  18. package/dist/_esm5.processed/compat/should_favour_custom_safari_EME.js +2 -2
  19. package/dist/_esm5.processed/config.d.ts +166 -1080
  20. package/dist/_esm5.processed/config.js +17 -1119
  21. package/dist/_esm5.processed/core/abr/bandwidth_estimator.js +4 -1
  22. package/dist/_esm5.processed/core/abr/buffer_based_chooser.d.ts +28 -6
  23. package/dist/_esm5.processed/core/abr/buffer_based_chooser.js +63 -12
  24. package/dist/_esm5.processed/core/abr/network_analyzer.d.ts +1 -1
  25. package/dist/_esm5.processed/core/abr/network_analyzer.js +2 -1
  26. package/dist/_esm5.processed/core/abr/pending_requests_store.js +3 -5
  27. package/dist/_esm5.processed/core/abr/representation_estimator.d.ts +1 -1
  28. package/dist/_esm5.processed/core/abr/representation_estimator.js +2 -2
  29. package/dist/_esm5.processed/core/api/get_player_state.js +1 -1
  30. package/dist/_esm5.processed/core/api/index.d.ts +2 -1
  31. package/dist/_esm5.processed/core/api/media_element_track_choice_manager.d.ts +6 -0
  32. package/dist/_esm5.processed/core/api/media_element_track_choice_manager.js +22 -4
  33. package/dist/_esm5.processed/core/api/option_utils.d.ts +3 -1
  34. package/dist/_esm5.processed/core/api/option_utils.js +19 -6
  35. package/dist/_esm5.processed/core/api/playback_observer.js +5 -1
  36. package/dist/_esm5.processed/core/api/public_api.d.ts +82 -71
  37. package/dist/_esm5.processed/core/api/public_api.js +72 -33
  38. package/dist/_esm5.processed/core/api/track_choice_manager.d.ts +6 -6
  39. package/dist/_esm5.processed/core/{eme → decrypt}/__tests__/__global__/utils.d.ts +7 -51
  40. package/dist/_esm5.processed/core/{eme → decrypt}/__tests__/__global__/utils.js +30 -75
  41. package/dist/_esm5.processed/core/{eme → decrypt}/attach_media_keys.d.ts +12 -12
  42. package/dist/_esm5.processed/core/decrypt/attach_media_keys.js +104 -0
  43. package/dist/_esm5.processed/core/{eme/clear_eme_session.d.ts → decrypt/clear_on_stop.d.ts} +3 -4
  44. package/dist/_esm5.processed/core/decrypt/clear_on_stop.js +41 -0
  45. package/dist/_esm5.processed/core/decrypt/content_decryptor.d.ts +216 -0
  46. package/dist/_esm5.processed/core/decrypt/content_decryptor.js +866 -0
  47. package/dist/_esm5.processed/core/{eme/get_session.d.ts → decrypt/create_or_load_session.d.ts} +28 -26
  48. package/dist/_esm5.processed/core/decrypt/create_or_load_session.js +124 -0
  49. package/dist/_esm5.processed/core/{eme → decrypt}/create_session.d.ts +22 -19
  50. package/dist/_esm5.processed/core/decrypt/create_session.js +174 -0
  51. package/dist/_esm5.processed/core/decrypt/dispose_decryption_resources.d.ts +21 -0
  52. package/dist/_esm5.processed/core/decrypt/dispose_decryption_resources.js +81 -0
  53. package/dist/_esm5.processed/core/{eme → decrypt}/find_key_system.d.ts +11 -14
  54. package/dist/_esm5.processed/core/decrypt/find_key_system.js +300 -0
  55. package/dist/_esm5.processed/core/{eme → decrypt}/get_current_key_system.d.ts +0 -0
  56. package/dist/_esm5.processed/core/{eme → decrypt}/get_current_key_system.js +1 -1
  57. package/dist/_esm5.processed/core/{eme → decrypt}/get_media_keys.d.ts +13 -5
  58. package/dist/_esm5.processed/core/decrypt/get_media_keys.js +153 -0
  59. package/dist/_esm5.processed/core/{eme → decrypt}/index.d.ts +5 -6
  60. package/dist/_esm5.processed/core/{eme → decrypt}/index.js +5 -5
  61. package/dist/_esm5.processed/core/{eme → decrypt}/init_media_keys.d.ts +6 -4
  62. package/dist/_esm5.processed/core/decrypt/init_media_keys.js +82 -0
  63. package/dist/_esm5.processed/core/decrypt/session_events_listener.d.ts +77 -0
  64. package/dist/_esm5.processed/core/{eme → decrypt}/session_events_listener.js +25 -24
  65. package/dist/_esm5.processed/core/{eme → decrypt}/set_server_certificate.d.ts +15 -6
  66. package/dist/_esm5.processed/core/decrypt/set_server_certificate.js +141 -0
  67. package/dist/_esm5.processed/core/{eme → decrypt}/types.d.ts +120 -242
  68. package/dist/_esm5.processed/core/{eme → decrypt}/types.js +0 -0
  69. package/dist/_esm5.processed/core/{eme → decrypt}/utils/are_init_values_compatible.d.ts +3 -3
  70. package/dist/_esm5.processed/core/{eme → decrypt}/utils/are_init_values_compatible.js +5 -5
  71. package/dist/_esm5.processed/core/{eme → decrypt/utils}/check_key_statuses.d.ts +2 -2
  72. package/dist/_esm5.processed/core/{eme → decrypt/utils}/check_key_statuses.js +4 -3
  73. package/dist/_esm5.processed/core/{eme/utils/close_session.d.ts → decrypt/utils/clean_old_loaded_sessions.d.ts} +8 -7
  74. package/dist/_esm5.processed/core/decrypt/utils/clean_old_loaded_sessions.js +85 -0
  75. package/dist/_esm5.processed/core/{eme → decrypt/utils}/clean_old_stored_persistent_info.d.ts +1 -1
  76. package/dist/_esm5.processed/core/{eme → decrypt/utils}/clean_old_stored_persistent_info.js +2 -2
  77. package/dist/_esm5.processed/core/{eme → decrypt/utils}/get_drm_system_id.d.ts +0 -0
  78. package/dist/_esm5.processed/core/{eme → decrypt/utils}/get_drm_system_id.js +1 -1
  79. package/dist/_esm5.processed/core/decrypt/utils/init_data_values_container.d.ts +69 -0
  80. package/dist/_esm5.processed/core/decrypt/utils/init_data_values_container.js +99 -0
  81. package/dist/_esm5.processed/core/{eme → decrypt}/utils/is_session_usable.d.ts +0 -1
  82. package/dist/_esm5.processed/core/{eme → decrypt}/utils/is_session_usable.js +4 -5
  83. package/dist/_esm5.processed/core/decrypt/utils/key_id_comparison.d.ts +44 -0
  84. package/dist/_esm5.processed/core/decrypt/utils/key_id_comparison.js +77 -0
  85. package/dist/_esm5.processed/core/decrypt/utils/key_session_record.d.ts +104 -0
  86. package/dist/_esm5.processed/core/decrypt/utils/key_session_record.js +155 -0
  87. package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.d.ts +108 -0
  88. package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +303 -0
  89. package/dist/_esm5.processed/core/{eme → decrypt/utils}/media_keys_infos_store.d.ts +4 -4
  90. package/dist/_esm5.processed/core/{eme → decrypt/utils}/media_keys_infos_store.js +0 -0
  91. package/dist/_esm5.processed/core/{eme → decrypt}/utils/persistent_sessions_store.d.ts +8 -18
  92. package/dist/_esm5.processed/core/{eme → decrypt}/utils/persistent_sessions_store.js +119 -97
  93. package/dist/_esm5.processed/core/{eme/utils/init_data_container.d.ts → decrypt/utils/serializable_bytes.d.ts} +8 -5
  94. package/dist/_esm5.processed/core/{eme/utils/init_data_container.js → decrypt/utils/serializable_bytes.js} +9 -9
  95. package/dist/_esm5.processed/core/{eme → decrypt/utils}/server_certificate_store.d.ts +1 -1
  96. package/dist/_esm5.processed/core/{eme → decrypt/utils}/server_certificate_store.js +1 -1
  97. package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.d.ts +4 -4
  98. package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.js +3 -3
  99. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +2 -2
  100. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +6 -2
  101. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher_creator.js +1 -1
  102. package/dist/_esm5.processed/core/fetchers/utils/try_urls_with_backoff.js +1 -1
  103. package/dist/_esm5.processed/core/init/get_initial_time.js +1 -1
  104. package/dist/_esm5.processed/core/init/initialize_directfile.d.ts +3 -3
  105. package/dist/_esm5.processed/core/init/initialize_directfile.js +11 -17
  106. package/dist/_esm5.processed/core/init/initialize_media_source.d.ts +5 -3
  107. package/dist/_esm5.processed/core/init/initialize_media_source.js +18 -69
  108. package/dist/_esm5.processed/core/init/link_drm_and_content.d.ts +61 -0
  109. package/dist/_esm5.processed/core/init/link_drm_and_content.js +94 -0
  110. package/dist/_esm5.processed/core/init/manifest_update_scheduler.d.ts +4 -4
  111. package/dist/_esm5.processed/core/init/manifest_update_scheduler.js +2 -1
  112. package/dist/_esm5.processed/core/init/stall_avoider.js +1 -1
  113. package/dist/_esm5.processed/core/init/stream_events_emitter/are_same_stream_events.d.ts +4 -4
  114. package/dist/_esm5.processed/core/init/stream_events_emitter/stream_events_emitter.js +1 -1
  115. package/dist/_esm5.processed/core/init/stream_events_emitter/types.d.ts +2 -2
  116. package/dist/_esm5.processed/core/init/types.d.ts +2 -4
  117. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +1 -1
  118. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.d.ts +3 -3
  119. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +3 -1
  120. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/text_track_cues_store.js +32 -31
  121. package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.d.ts +4 -4
  122. package/dist/_esm5.processed/core/segment_buffers/inventory/segment_inventory.d.ts +17 -1
  123. package/dist/_esm5.processed/core/segment_buffers/inventory/segment_inventory.js +22 -5
  124. package/dist/_esm5.processed/core/stream/adaptation/adaptation_stream.d.ts +2 -1
  125. package/dist/_esm5.processed/core/stream/adaptation/adaptation_stream.js +6 -3
  126. package/dist/_esm5.processed/core/stream/events_generators.d.ts +8 -3
  127. package/dist/_esm5.processed/core/stream/events_generators.js +3 -2
  128. package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.d.ts +1 -0
  129. package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +3 -3
  130. package/dist/_esm5.processed/core/stream/period/create_empty_adaptation_stream.js +2 -1
  131. package/dist/_esm5.processed/core/stream/period/get_adaptation_switch_strategy.js +1 -1
  132. package/dist/_esm5.processed/core/stream/period/period_stream.d.ts +2 -1
  133. package/dist/_esm5.processed/core/stream/period/period_stream.js +3 -3
  134. package/dist/_esm5.processed/core/stream/representation/force_garbage_collection.js +5 -6
  135. package/dist/_esm5.processed/core/stream/representation/get_buffer_status.d.ts +6 -1
  136. package/dist/_esm5.processed/core/stream/representation/get_buffer_status.js +12 -9
  137. package/dist/_esm5.processed/core/stream/representation/get_needed_segments.d.ts +19 -14
  138. package/dist/_esm5.processed/core/stream/representation/get_needed_segments.js +86 -10
  139. package/dist/_esm5.processed/core/stream/representation/get_segment_priority.js +1 -1
  140. package/dist/_esm5.processed/core/stream/representation/push_media_segment.js +3 -3
  141. package/dist/_esm5.processed/core/stream/representation/representation_stream.d.ts +6 -0
  142. package/dist/_esm5.processed/core/stream/representation/representation_stream.js +19 -8
  143. package/dist/_esm5.processed/core/stream/types.d.ts +1 -1
  144. package/dist/_esm5.processed/default_config.d.ts +1114 -0
  145. package/dist/_esm5.processed/default_config.js +1145 -0
  146. package/dist/_esm5.processed/errors/request_error.js +3 -1
  147. package/dist/_esm5.processed/experimental/index.d.ts +2 -0
  148. package/dist/_esm5.processed/experimental/index.js +2 -0
  149. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/push_data.d.ts +1 -0
  150. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/thumbnail_loader.d.ts +2 -2
  151. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/thumbnail_loader.js +2 -4
  152. package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/api/probeMediaConfiguration.d.ts +1 -1
  153. package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/api/probeMediaConfiguration.js +1 -1
  154. package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/probers/DRMInfos.js +1 -2
  155. package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/probers/HDCPPolicy.js +1 -2
  156. package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/types.d.ts +3 -3
  157. package/dist/_esm5.processed/features/features_object.js +1 -1
  158. package/dist/_esm5.processed/features/initialize_features.js +1 -1
  159. package/dist/_esm5.processed/features/list/eme.d.ts +3 -3
  160. package/dist/_esm5.processed/features/list/eme.js +5 -5
  161. package/dist/_esm5.processed/features/types.d.ts +3 -3
  162. package/dist/_esm5.processed/manifest/adaptation.d.ts +2 -2
  163. package/dist/_esm5.processed/manifest/adaptation.js +3 -1
  164. package/dist/_esm5.processed/manifest/manifest.d.ts +10 -23
  165. package/dist/_esm5.processed/manifest/manifest.js +10 -74
  166. package/dist/_esm5.processed/manifest/period.d.ts +3 -3
  167. package/dist/_esm5.processed/manifest/representation.d.ts +37 -5
  168. package/dist/_esm5.processed/manifest/representation_index/types.d.ts +18 -18
  169. package/dist/_esm5.processed/manifest/types.d.ts +3 -3
  170. package/dist/_esm5.processed/parsers/manifest/dash/common/get_hdr_information.d.ts +1 -1
  171. package/dist/_esm5.processed/parsers/manifest/dash/common/get_periods_time_infos.d.ts +3 -3
  172. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.d.ts +6 -6
  173. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/get_init_segment.d.ts +3 -3
  174. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/get_segments_from_timeline.d.ts +2 -2
  175. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/is_period_fulfilled.js +1 -2
  176. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.d.ts +14 -14
  177. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.d.ts +17 -17
  178. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.js +1 -2
  179. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_elements.js +1 -1
  180. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.d.ts +28 -20
  181. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.js +20 -5
  182. package/dist/_esm5.processed/parsers/manifest/dash/common/infer_adaptation_type.d.ts +2 -2
  183. package/dist/_esm5.processed/parsers/manifest/dash/common/manifest_bounds_calculator.d.ts +1 -1
  184. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_adaptation_sets.d.ts +17 -35
  185. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_adaptation_sets.js +109 -96
  186. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_mpd.d.ts +8 -8
  187. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_mpd.js +1 -2
  188. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_periods.d.ts +18 -27
  189. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_periods.js +25 -23
  190. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representation_index.d.ts +21 -15
  191. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representation_index.js +19 -19
  192. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.d.ts +15 -38
  193. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +8 -8
  194. package/dist/_esm5.processed/parsers/manifest/dash/node_parser_types.d.ts +30 -30
  195. package/dist/_esm5.processed/parsers/manifest/dash/parsers_types.d.ts +3 -3
  196. package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.js +1 -1
  197. package/dist/_esm5.processed/parsers/manifest/metaplaylist/metaplaylist_parser.d.ts +2 -2
  198. package/dist/_esm5.processed/parsers/manifest/smooth/create_parser.d.ts +7 -7
  199. package/dist/_esm5.processed/parsers/manifest/smooth/create_parser.js +1 -0
  200. package/dist/_esm5.processed/parsers/manifest/smooth/representation_index.d.ts +8 -8
  201. package/dist/_esm5.processed/parsers/manifest/types.d.ts +28 -28
  202. package/dist/_esm5.processed/parsers/manifest/utils/clear_timeline_from_position.d.ts +3 -2
  203. package/dist/_esm5.processed/parsers/manifest/utils/clear_timeline_from_position.js +15 -5
  204. package/dist/_esm5.processed/parsers/manifest/utils/index_helpers.d.ts +2 -2
  205. package/dist/_esm5.processed/parsers/manifest/utils/update_segment_timeline.d.ts +11 -1
  206. package/dist/_esm5.processed/parsers/manifest/utils/update_segment_timeline.js +31 -19
  207. package/dist/_esm5.processed/parsers/texttracks/webvtt/html/to_html.d.ts +2 -2
  208. package/dist/_esm5.processed/parsers/texttracks/webvtt/parse_cue_block.d.ts +1 -1
  209. package/dist/_esm5.processed/public_types.d.ts +2 -2
  210. package/dist/_esm5.processed/transports/dash/add_segment_integrity_checks_to_loader.js +2 -1
  211. package/dist/_esm5.processed/transports/dash/image_pipelines.js +4 -1
  212. package/dist/_esm5.processed/transports/dash/init_segment_loader.js +1 -1
  213. package/dist/_esm5.processed/transports/dash/manifest_parser.js +1 -1
  214. package/dist/_esm5.processed/transports/dash/segment_loader.d.ts +2 -2
  215. package/dist/_esm5.processed/transports/dash/segment_loader.js +2 -2
  216. package/dist/_esm5.processed/transports/dash/segment_parser.d.ts +1 -1
  217. package/dist/_esm5.processed/transports/dash/segment_parser.js +6 -3
  218. package/dist/_esm5.processed/transports/dash/text_loader.d.ts +1 -1
  219. package/dist/_esm5.processed/transports/dash/text_loader.js +1 -1
  220. package/dist/_esm5.processed/transports/dash/text_parser.d.ts +1 -1
  221. package/dist/_esm5.processed/transports/dash/text_parser.js +8 -2
  222. package/dist/_esm5.processed/transports/local/segment_loader.d.ts +1 -2
  223. package/dist/_esm5.processed/transports/local/segment_loader.js +1 -1
  224. package/dist/_esm5.processed/transports/local/segment_parser.js +4 -1
  225. package/dist/_esm5.processed/transports/local/text_parser.js +8 -2
  226. package/dist/_esm5.processed/transports/metaplaylist/manifest_loader.d.ts +1 -1
  227. package/dist/_esm5.processed/transports/metaplaylist/pipelines.js +1 -1
  228. package/dist/_esm5.processed/transports/smooth/pipelines.js +69 -11
  229. package/dist/_esm5.processed/transports/smooth/segment_loader.d.ts +0 -1
  230. package/dist/_esm5.processed/transports/smooth/segment_loader.js +2 -2
  231. package/dist/_esm5.processed/transports/types.d.ts +58 -30
  232. package/dist/_esm5.processed/transports/utils/call_custom_manifest_loader.js +1 -1
  233. package/dist/_esm5.processed/transports/utils/generate_manifest_loader.d.ts +1 -1
  234. package/dist/_esm5.processed/utils/cancellable_sleep.js +1 -1
  235. package/dist/_esm5.processed/utils/cast_to_observable.d.ts +1 -2
  236. package/dist/_esm5.processed/utils/cast_to_observable.js +1 -1
  237. package/dist/_esm5.processed/utils/deep_merge.d.ts +12 -0
  238. package/dist/_esm5.processed/utils/deep_merge.js +53 -0
  239. package/dist/_esm5.processed/utils/reference.d.ts +29 -0
  240. package/dist/_esm5.processed/utils/reference.js +72 -24
  241. package/dist/_esm5.processed/utils/request/fetch.d.ts +4 -5
  242. package/dist/_esm5.processed/utils/request/fetch.js +8 -6
  243. package/dist/_esm5.processed/utils/request/xhr.d.ts +6 -6
  244. package/dist/_esm5.processed/utils/request/xhr.js +3 -2
  245. package/dist/_esm5.processed/utils/rx-from_cancellable_promise.d.ts +1 -2
  246. package/dist/_esm5.processed/utils/rx-from_cancellable_promise.js +7 -2
  247. package/dist/_esm5.processed/utils/task_canceller.d.ts +5 -3
  248. package/dist/_esm5.processed/utils/task_canceller.js +3 -3
  249. package/dist/rx-player.js +5242 -3190
  250. package/dist/rx-player.min.js +1 -1
  251. package/dummy +1 -0
  252. package/{dist/_esm5.processed/core/eme/dispose_eme.d.ts → experimental/index.d.ts} +1 -4
  253. package/{dist/_esm5.processed/core/eme/dispose_media_keys.d.ts → experimental/index.js} +1 -6
  254. package/package.json +33 -36
  255. package/scripts/build/templates/experimental/index.d.ts +16 -0
  256. package/scripts/build/templates/experimental/index.js +16 -0
  257. package/scripts/doc-generator/generate_header_html.js +6 -7
  258. package/scripts/doc-generator/generate_page_html.js +3 -4
  259. package/scripts/doc-generator/generate_page_list_html.js +4 -5
  260. package/scripts/doc-generator/generate_sidebar_html.js +4 -7
  261. package/scripts/doc-generator/utils.js +0 -11
  262. package/scripts/generate_demo_list.js +3 -3
  263. package/scripts/generate_documentation_list.js +3 -3
  264. package/scripts/launch_static_server.js +127 -67
  265. package/scripts/run_standalone_demo.js +1 -0
  266. package/scripts/start_demo_web_server.js +1 -0
  267. package/sonar-project.properties +1 -1
  268. package/src/README.md +6 -6
  269. package/src/compat/__tests__/fullscreen.test.ts +7 -7
  270. package/src/compat/__tests__/is_vtt_cue.test.ts +1 -1
  271. package/src/compat/__tests__/should_favour_custom_safari_EME.test.ts +45 -5
  272. package/src/compat/browser_detection.ts +4 -2
  273. package/src/compat/eme/close_session.ts +90 -56
  274. package/src/compat/eme/custom_media_keys/ie11_media_keys.ts +1 -1
  275. package/src/compat/eme/custom_media_keys/index.ts +28 -41
  276. package/src/compat/eme/custom_media_keys/old_webkit_media_keys.ts +63 -46
  277. package/src/compat/eme/custom_media_keys/webkit_media_keys.ts +51 -49
  278. package/src/compat/eme/generate_key_request.ts +25 -33
  279. package/src/compat/eme/load_session.ts +29 -31
  280. package/src/compat/event_listeners.ts +2 -1
  281. package/src/compat/should_favour_custom_safari_EME.ts +5 -2
  282. package/src/config.ts +17 -1210
  283. package/src/core/README.md +1 -1
  284. package/src/core/abr/__tests__/{get_estimate_from_buffer_levels.test.ts → buffer_based_chooser.test.ts} +94 -123
  285. package/src/core/abr/bandwidth_estimator.ts +4 -4
  286. package/src/core/abr/buffer_based_chooser.ts +85 -20
  287. package/src/core/abr/network_analyzer.ts +6 -7
  288. package/src/core/abr/pending_requests_store.ts +3 -5
  289. package/src/core/abr/representation_estimator.ts +6 -3
  290. package/src/core/api/__tests__/get_player_state.test.ts +3 -3
  291. package/src/core/api/__tests__/option_utils.test.ts +17 -17
  292. package/src/core/api/get_player_state.ts +1 -1
  293. package/src/core/api/index.ts +3 -0
  294. package/src/core/api/media_element_track_choice_manager.ts +22 -3
  295. package/src/core/api/option_utils.ts +37 -20
  296. package/src/core/api/playback_observer.ts +12 -8
  297. package/src/core/api/public_api.ts +152 -112
  298. package/src/core/api/track_choice_manager.ts +10 -9
  299. package/src/core/decrypt/README.md +22 -0
  300. package/src/core/decrypt/__tests__/__global__/get_license.test.ts +418 -0
  301. package/src/core/decrypt/__tests__/__global__/init_data.test.ts +675 -0
  302. package/src/core/{eme → decrypt}/__tests__/__global__/media_key_system_access.test.ts +99 -92
  303. package/src/core/decrypt/__tests__/__global__/media_keys.test.ts +156 -0
  304. package/src/core/decrypt/__tests__/__global__/server_certificate.test.ts +262 -0
  305. package/src/core/{eme → decrypt}/__tests__/__global__/utils.ts +36 -103
  306. package/src/core/{eme → decrypt}/attach_media_keys.ts +49 -56
  307. package/src/core/decrypt/clear_on_stop.ts +48 -0
  308. package/src/core/decrypt/content_decryptor.ts +1158 -0
  309. package/src/core/decrypt/create_or_load_session.ts +130 -0
  310. package/src/core/decrypt/create_session.ts +175 -0
  311. package/src/core/decrypt/dispose_decryption_resources.ts +39 -0
  312. package/src/core/{eme → decrypt}/find_key_system.ts +126 -134
  313. package/src/core/{eme → decrypt}/get_current_key_system.ts +1 -1
  314. package/src/core/decrypt/get_media_keys.ts +145 -0
  315. package/src/core/{eme → decrypt}/index.ts +11 -8
  316. package/src/core/decrypt/init_media_keys.ts +51 -0
  317. package/src/core/{eme → decrypt}/session_events_listener.ts +93 -55
  318. package/src/core/decrypt/set_server_certificate.ts +104 -0
  319. package/src/core/{eme → decrypt}/types.ts +129 -259
  320. package/src/core/{eme → decrypt}/utils/__tests__/are_init_values_compatible.test.ts +1 -1
  321. package/src/core/{eme → decrypt/utils}/__tests__/clean_old_loaded_sessions.test.ts +29 -71
  322. package/src/core/{eme → decrypt/utils}/__tests__/clean_old_stored_persistent_info.test.ts +6 -6
  323. package/src/core/{eme → decrypt}/utils/are_init_values_compatible.ts +9 -9
  324. package/src/core/{eme → decrypt/utils}/check_key_statuses.ts +6 -5
  325. package/{dist/_esm5.processed/core/eme/clean_old_loaded_sessions.js → src/core/decrypt/utils/clean_old_loaded_sessions.ts} +20 -20
  326. package/src/core/{eme → decrypt/utils}/clean_old_stored_persistent_info.ts +3 -3
  327. package/src/core/{eme → decrypt/utils}/get_drm_system_id.ts +1 -1
  328. package/src/core/decrypt/utils/init_data_values_container.ts +119 -0
  329. package/src/core/{eme → decrypt}/utils/is_session_usable.ts +4 -5
  330. package/src/core/decrypt/utils/key_id_comparison.ts +82 -0
  331. package/src/core/decrypt/utils/key_session_record.ts +175 -0
  332. package/src/core/decrypt/utils/loaded_sessions_store.ts +318 -0
  333. package/src/core/{eme → decrypt/utils}/media_keys_infos_store.ts +4 -4
  334. package/src/core/{eme → decrypt}/utils/persistent_sessions_store.ts +122 -104
  335. package/src/core/{eme/utils/init_data_container.ts → decrypt/utils/serializable_bytes.ts} +8 -5
  336. package/src/core/{eme → decrypt/utils}/server_certificate_store.ts +2 -2
  337. package/src/core/fetchers/manifest/manifest_fetcher.ts +9 -9
  338. package/src/core/fetchers/segment/segment_fetcher.ts +10 -7
  339. package/src/core/fetchers/segment/segment_fetcher_creator.ts +2 -2
  340. package/src/core/fetchers/utils/try_urls_with_backoff.ts +1 -1
  341. package/src/core/init/.initialize_media_source.ts.un~ +0 -0
  342. package/src/core/init/get_initial_time.ts +2 -1
  343. package/src/core/init/initialize_directfile.ts +19 -22
  344. package/src/core/init/initialize_media_source.ts +43 -106
  345. package/src/core/init/link_drm_and_content.ts +176 -0
  346. package/src/core/init/manifest_update_scheduler.ts +12 -10
  347. package/src/core/init/stall_avoider.ts +6 -5
  348. package/src/core/init/stream_events_emitter/are_same_stream_events.ts +4 -4
  349. package/src/core/init/stream_events_emitter/stream_events_emitter.ts +2 -1
  350. package/src/core/init/stream_events_emitter/types.ts +2 -2
  351. package/src/core/init/types.ts +1 -39
  352. package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +2 -1
  353. package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +6 -7
  354. package/src/core/segment_buffers/implementations/text/html/text_track_cues_store.ts +32 -31
  355. package/src/core/segment_buffers/implementations/text/native/native_text_segment_buffer.ts +4 -4
  356. package/src/core/segment_buffers/inventory/segment_inventory.ts +42 -8
  357. package/src/core/stream/adaptation/adaptation_stream.ts +7 -1
  358. package/src/core/stream/events_generators.ts +9 -4
  359. package/src/core/stream/orchestrator/stream_orchestrator.ts +9 -4
  360. package/src/core/stream/period/create_empty_adaptation_stream.ts +2 -1
  361. package/src/core/stream/period/get_adaptation_switch_strategy.ts +1 -1
  362. package/src/core/stream/period/period_stream.ts +5 -2
  363. package/src/core/stream/representation/force_garbage_collection.ts +5 -7
  364. package/src/core/stream/representation/get_buffer_status.ts +28 -16
  365. package/src/core/stream/representation/get_needed_segments.ts +124 -28
  366. package/src/core/stream/representation/get_segment_priority.ts +1 -2
  367. package/src/core/stream/representation/push_media_segment.ts +3 -2
  368. package/src/core/stream/representation/representation_stream.ts +30 -7
  369. package/src/core/stream/types.ts +1 -1
  370. package/src/default_config.ts +1241 -0
  371. package/src/errors/request_error.ts +4 -1
  372. package/src/experimental/index.ts +5 -0
  373. package/src/experimental/tools/VideoThumbnailLoader/push_data.ts +1 -0
  374. package/src/experimental/tools/VideoThumbnailLoader/thumbnail_loader.ts +5 -7
  375. package/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/DRMInfos.test.ts +3 -10
  376. package/src/experimental/tools/mediaCapabilitiesProber/__tests__/probers/HDCPPolicy.test.ts +4 -4
  377. package/src/experimental/tools/mediaCapabilitiesProber/api/index.ts +1 -1
  378. package/src/experimental/tools/mediaCapabilitiesProber/api/probeMediaConfiguration.ts +3 -3
  379. package/src/experimental/tools/mediaCapabilitiesProber/probers/DRMInfos.ts +1 -2
  380. package/src/experimental/tools/mediaCapabilitiesProber/probers/HDCPPolicy.ts +1 -2
  381. package/src/experimental/tools/mediaCapabilitiesProber/types.ts +3 -3
  382. package/src/features/__tests__/initialize_features.test.ts +2 -2
  383. package/src/features/features_object.ts +1 -1
  384. package/src/features/initialize_features.ts +1 -1
  385. package/src/features/list/__tests__/eme.test.ts +5 -5
  386. package/src/features/list/eme.ts +5 -5
  387. package/src/features/types.ts +3 -10
  388. package/src/manifest/adaptation.ts +6 -4
  389. package/src/manifest/manifest.ts +16 -86
  390. package/src/manifest/period.ts +3 -3
  391. package/src/manifest/representation.ts +38 -5
  392. package/src/manifest/representation_index/types.ts +18 -18
  393. package/src/manifest/types.ts +3 -3
  394. package/src/parsers/manifest/dash/common/__tests__/manifest_bounds_calculator.test.ts +1 -0
  395. package/src/parsers/manifest/dash/common/get_hdr_information.ts +1 -1
  396. package/src/parsers/manifest/dash/common/get_periods_time_infos.ts +3 -3
  397. package/src/parsers/manifest/dash/common/indexes/base.ts +6 -6
  398. package/src/parsers/manifest/dash/common/indexes/get_init_segment.ts +4 -2
  399. package/src/parsers/manifest/dash/common/indexes/get_segments_from_timeline.ts +2 -2
  400. package/src/parsers/manifest/dash/common/indexes/is_period_fulfilled.ts +1 -2
  401. package/src/parsers/manifest/dash/common/indexes/list.ts +14 -14
  402. package/src/parsers/manifest/dash/common/indexes/template.ts +18 -18
  403. package/src/parsers/manifest/dash/common/indexes/timeline/construct_timeline_from_elements.ts +1 -1
  404. package/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +51 -23
  405. package/src/parsers/manifest/dash/common/infer_adaptation_type.ts +2 -2
  406. package/src/parsers/manifest/dash/common/manifest_bounds_calculator.ts +1 -1
  407. package/src/parsers/manifest/dash/common/parse_adaptation_sets.ts +167 -134
  408. package/src/parsers/manifest/dash/common/parse_mpd.ts +9 -10
  409. package/src/parsers/manifest/dash/common/parse_periods.ts +80 -79
  410. package/src/parsers/manifest/dash/common/parse_representation_index.ts +83 -75
  411. package/src/parsers/manifest/dash/common/parse_representations.ts +44 -63
  412. package/src/parsers/manifest/dash/node_parser_types.ts +30 -30
  413. package/src/parsers/manifest/dash/parsers_types.ts +3 -3
  414. package/src/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.ts +1 -1
  415. package/src/parsers/manifest/metaplaylist/metaplaylist_parser.ts +4 -4
  416. package/src/parsers/manifest/smooth/create_parser.ts +24 -21
  417. package/src/parsers/manifest/smooth/representation_index.ts +14 -14
  418. package/src/parsers/manifest/types.ts +28 -28
  419. package/src/parsers/manifest/utils/__tests__/update_segment_timeline.test.ts +31 -33
  420. package/src/parsers/manifest/utils/clear_timeline_from_position.ts +15 -6
  421. package/src/parsers/manifest/utils/index_helpers.ts +2 -2
  422. package/src/parsers/manifest/utils/update_segment_timeline.ts +32 -21
  423. package/src/parsers/texttracks/webvtt/html/__tests__/create_styled_element.test.ts +1 -0
  424. package/src/parsers/texttracks/webvtt/html/to_html.ts +2 -2
  425. package/src/parsers/texttracks/webvtt/parse_cue_block.ts +1 -1
  426. package/src/public_types.ts +5 -1
  427. package/src/transports/dash/add_segment_integrity_checks_to_loader.ts +2 -2
  428. package/src/transports/dash/image_pipelines.ts +4 -1
  429. package/src/transports/dash/init_segment_loader.ts +1 -1
  430. package/src/transports/dash/manifest_parser.ts +1 -1
  431. package/src/transports/dash/segment_loader.ts +7 -7
  432. package/src/transports/dash/segment_parser.ts +8 -1
  433. package/src/transports/dash/text_loader.ts +2 -2
  434. package/src/transports/dash/text_parser.ts +11 -1
  435. package/src/transports/local/segment_loader.ts +4 -4
  436. package/src/transports/local/segment_parser.ts +4 -0
  437. package/src/transports/local/text_parser.ts +8 -0
  438. package/src/transports/metaplaylist/manifest_loader.ts +1 -1
  439. package/src/transports/metaplaylist/pipelines.ts +1 -1
  440. package/src/transports/smooth/pipelines.ts +29 -16
  441. package/src/transports/smooth/segment_loader.ts +8 -8
  442. package/src/transports/types.ts +59 -30
  443. package/src/transports/utils/call_custom_manifest_loader.ts +6 -6
  444. package/src/transports/utils/generate_manifest_loader.ts +1 -1
  445. package/src/utils/__tests__/deep_merge.test.ts +48 -0
  446. package/src/utils/__tests__/flat_map.test.ts +12 -7
  447. package/src/utils/cancellable_sleep.ts +1 -1
  448. package/src/utils/cast_to_observable.ts +1 -2
  449. package/src/utils/deep_merge.ts +46 -0
  450. package/src/utils/reference.ts +116 -23
  451. package/src/utils/request/fetch.ts +17 -15
  452. package/src/utils/request/xhr.ts +11 -8
  453. package/src/utils/rx-from_cancellable_promise.ts +8 -4
  454. package/src/utils/task_canceller.ts +6 -4
  455. package/tsconfig.json +1 -2
  456. package/tsconfig.modules.json +1 -2
  457. package/dist/_esm5.processed/core/abr/get_estimate_from_buffer_levels.d.ts +0 -29
  458. package/dist/_esm5.processed/core/abr/get_estimate_from_buffer_levels.js +0 -67
  459. package/dist/_esm5.processed/core/eme/attach_media_keys.js +0 -57
  460. package/dist/_esm5.processed/core/eme/clean_old_loaded_sessions.d.ts +0 -59
  461. package/dist/_esm5.processed/core/eme/clear_eme_session.js +0 -50
  462. package/dist/_esm5.processed/core/eme/create_session.js +0 -126
  463. package/dist/_esm5.processed/core/eme/dispose_eme.js +0 -23
  464. package/dist/_esm5.processed/core/eme/dispose_media_keys.js +0 -36
  465. package/dist/_esm5.processed/core/eme/eme_manager.d.ts +0 -31
  466. package/dist/_esm5.processed/core/eme/eme_manager.js +0 -278
  467. package/dist/_esm5.processed/core/eme/find_key_system.js +0 -243
  468. package/dist/_esm5.processed/core/eme/get_media_keys.js +0 -85
  469. package/dist/_esm5.processed/core/eme/get_session.js +0 -68
  470. package/dist/_esm5.processed/core/eme/init_media_keys.js +0 -66
  471. package/dist/_esm5.processed/core/eme/session_events_listener.d.ts +0 -41
  472. package/dist/_esm5.processed/core/eme/set_server_certificate.js +0 -85
  473. package/dist/_esm5.processed/core/eme/utils/close_session.js +0 -81
  474. package/dist/_esm5.processed/core/eme/utils/init_data_store.d.ts +0 -115
  475. package/dist/_esm5.processed/core/eme/utils/init_data_store.js +0 -181
  476. package/dist/_esm5.processed/core/eme/utils/loaded_sessions_store.d.ts +0 -123
  477. package/dist/_esm5.processed/core/eme/utils/loaded_sessions_store.js +0 -173
  478. package/dist/_esm5.processed/core/init/create_eme_manager.d.ts +0 -34
  479. package/dist/_esm5.processed/core/init/create_eme_manager.js +0 -52
  480. package/src/core/abr/get_estimate_from_buffer_levels.ts +0 -85
  481. package/src/core/eme/README.md +0 -26
  482. package/src/core/eme/__tests__/__global__/get_license.test.ts +0 -414
  483. package/src/core/eme/__tests__/__global__/init_data.test.ts +0 -908
  484. package/src/core/eme/__tests__/__global__/media_keys.test.ts +0 -266
  485. package/src/core/eme/__tests__/__global__/server_certificate.test.ts +0 -364
  486. package/src/core/eme/__tests__/init_media_keys.test.ts +0 -182
  487. package/src/core/eme/clean_old_loaded_sessions.ts +0 -96
  488. package/src/core/eme/clear_eme_session.ts +0 -62
  489. package/src/core/eme/create_session.ts +0 -187
  490. package/src/core/eme/dispose_eme.ts +0 -25
  491. package/src/core/eme/dispose_media_keys.ts +0 -46
  492. package/src/core/eme/eme_manager.ts +0 -387
  493. package/src/core/eme/get_media_keys.ts +0 -141
  494. package/src/core/eme/get_session.ts +0 -135
  495. package/src/core/eme/init_media_keys.ts +0 -106
  496. package/src/core/eme/set_server_certificate.ts +0 -115
  497. package/src/core/eme/utils/close_session.ts +0 -113
  498. package/src/core/eme/utils/init_data_store.ts +0 -234
  499. package/src/core/eme/utils/loaded_sessions_store.ts +0 -235
  500. package/src/core/init/create_eme_manager.ts +0 -95
@@ -0,0 +1,1158 @@
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
+
17
+ import PPromise from "pinkie";
18
+ import {
19
+ events,
20
+ generateKeyRequest,
21
+ getInitData,
22
+ ICustomMediaKeys,
23
+ ICustomMediaKeySystemAccess,
24
+ } from "../../compat/";
25
+ import config from "../../config";
26
+ import {
27
+ EncryptedMediaError,
28
+ ICustomError,
29
+ OtherError,
30
+ } from "../../errors";
31
+ import log from "../../log";
32
+ import Manifest, {
33
+ Period,
34
+ } from "../../manifest";
35
+ import areArraysOfNumbersEqual from "../../utils/are_arrays_of_numbers_equal";
36
+ import arrayFind from "../../utils/array_find";
37
+ import arrayIncludes from "../../utils/array_includes";
38
+ import EventEmitter from "../../utils/event_emitter";
39
+ import isNullOrUndefined from "../../utils/is_null_or_undefined";
40
+ import { bytesToHex } from "../../utils/string_parsing";
41
+ import TaskCanceller from "../../utils/task_canceller";
42
+ import attachMediaKeys from "./attach_media_keys";
43
+ import createOrLoadSession from "./create_or_load_session";
44
+ import { IMediaKeysInfos } from "./get_media_keys";
45
+ import initMediaKeys from "./init_media_keys";
46
+ import SessionEventsListener, {
47
+ BlacklistedSessionError,
48
+ } from "./session_events_listener";
49
+ import setServerCertificate from "./set_server_certificate";
50
+ import {
51
+ IProtectionData,
52
+ IKeySystemOption,
53
+ IMediaKeySessionStores,
54
+ MediaKeySessionLoadingType,
55
+ IProcessedProtectionData,
56
+ } from "./types";
57
+ import cleanOldStoredPersistentInfo from "./utils/clean_old_stored_persistent_info";
58
+ import getDrmSystemId from "./utils/get_drm_system_id";
59
+ import InitDataValuesContainer from "./utils/init_data_values_container";
60
+ import {
61
+ areAllKeyIdsContainedIn,
62
+ areKeyIdsEqual,
63
+ areSomeKeyIdsContainedIn,
64
+ isKeyIdContainedIn,
65
+ } from "./utils/key_id_comparison";
66
+ import KeySessionRecord from "./utils/key_session_record";
67
+
68
+ const { onEncrypted$ } = events;
69
+
70
+ /**
71
+ * Module communicating with the Content Decryption Module (or CDM) to be able
72
+ * to decrypt contents.
73
+ *
74
+ * The `ContentDecryptor` starts communicating with the CDM, to initialize the
75
+ * key system, as soon as it is created.
76
+ *
77
+ * You can be notified of various events, such as fatal errors, by registering
78
+ * to one of its multiple events (@see IContentDecryptorEvent).
79
+ *
80
+ * @class ContentDecryptor
81
+ */
82
+ export default class ContentDecryptor extends EventEmitter<IContentDecryptorEvent> {
83
+ /**
84
+ * Hexadecimal id identifying the currently-chosen key system.
85
+ * `undefined` if not known or if the key system hasn't been initialized yet.
86
+ *
87
+ * When providing protection initialization data to the ContentDecryptor, you
88
+ * may only provide those linked to that system id. You can also provide all
89
+ * available protection initialization data, in which case it will be
90
+ * automatically filtered.
91
+ *
92
+ * This `systemId` may only be known once the `ReadyForContent` state (@see
93
+ * ContentDecryptorState) is reached, and even then, it may still be unknown,
94
+ * in which case it will stay to `undefined`.
95
+ */
96
+ public systemId : string | undefined;
97
+
98
+ /**
99
+ * Set only if the `ContentDecryptor` failed on an error.
100
+ * The corresponding Error.
101
+ */
102
+ public error : Error | null;
103
+
104
+ /**
105
+ * State of the ContentDecryptor (@see ContentDecryptorState) and associated
106
+ * data.
107
+ *
108
+ * The ContentDecryptor goes into a series of steps as it is initializing.
109
+ * This private property stores the current state and the potentially linked
110
+ * data.
111
+ */
112
+ private _stateData : IContentDecryptorStateData;
113
+
114
+ /**
115
+ * Contains information about all key sessions loaded for this current
116
+ * content.
117
+ * This object is most notably used to check which keys are already obtained,
118
+ * thus avoiding to perform new unnecessary license requests and CDM interactions.
119
+ */
120
+ private _currentSessions : IActiveSessionInfo[];
121
+
122
+ /**
123
+ * Allows to dispose the resources taken by the current instance of the
124
+ * ContentDecryptor.
125
+ */
126
+ private _canceller : TaskCanceller;
127
+
128
+ /**
129
+ * `true` once the `attach` method has been called`.
130
+ * Allows to avoid calling multiple times that function.
131
+ */
132
+ private _wasAttachCalled : boolean;
133
+
134
+ /**
135
+ * This queue stores initialization data which hasn't been processed yet,
136
+ * probably because the "queue is locked" for now. (@see _stateData private
137
+ * property).
138
+ *
139
+ * For example, this queue stores initialization data communicated while
140
+ * initializing so it can be processed when the initialization is done.
141
+ */
142
+ private _initDataQueue : IProtectionData[];
143
+
144
+ /**
145
+ * Create a new `ContentDecryptor`, and initialize its decryption capabilities
146
+ * right away.
147
+ * Goes into the `WaitingForAttachment` state once that initialization is
148
+ * done, after which you should call the `attach` method when you're ready for
149
+ * those decryption capabilities to be attached to the HTMLMediaElement.
150
+ *
151
+ * @param {HTMLMediaElement} mediaElement - The MediaElement which will be
152
+ * associated to a MediaKeys object
153
+ * @param {Array.<Object>} ksOptions - key system configuration.
154
+ * The `ContentDecryptor` can be given one or multiple key system
155
+ * configurations. It will choose the appropriate one depending on user
156
+ * settings and browser support.
157
+ */
158
+ constructor(mediaElement : HTMLMediaElement, ksOptions: IKeySystemOption[]) {
159
+ super();
160
+
161
+ log.debug("DRM: Starting ContentDecryptor logic.");
162
+
163
+ const canceller = new TaskCanceller();
164
+ this._currentSessions = [];
165
+ this._canceller = canceller;
166
+ this._wasAttachCalled = false;
167
+ this._initDataQueue = [];
168
+ this._stateData = { state: ContentDecryptorState.Initializing,
169
+ isMediaKeysAttached: false,
170
+ isInitDataQueueLocked: true,
171
+ data: null };
172
+ this.error = null;
173
+
174
+ const listenerSub = onEncrypted$(mediaElement).subscribe(evt => {
175
+ log.debug("DRM: Encrypted event received from media element.");
176
+ const initData = getInitData(evt);
177
+ if (initData !== null) {
178
+ this.onInitializationData(initData);
179
+ }
180
+ });
181
+ canceller.signal.register(() => {
182
+ listenerSub.unsubscribe();
183
+ });
184
+
185
+ initMediaKeys(mediaElement, ksOptions, canceller.signal)
186
+ .then((mediaKeysInfo) => {
187
+ const { options, mediaKeySystemAccess } = mediaKeysInfo;
188
+
189
+ /**
190
+ * String identifying the key system, allowing the rest of the code to
191
+ * only advertise the required initialization data for license requests.
192
+ *
193
+ * Note that we only set this value if retro-compatibility to older
194
+ * persistent logic in the RxPlayer is not important, as the
195
+ * optimizations this property unlocks can break the loading of
196
+ * MediaKeySessions persisted in older RxPlayer's versions.
197
+ */
198
+ let systemId : string | undefined;
199
+ if (isNullOrUndefined(options.licenseStorage) ||
200
+ options.licenseStorage.disableRetroCompatibility === true)
201
+ {
202
+ systemId = getDrmSystemId(mediaKeySystemAccess.keySystem);
203
+ }
204
+
205
+ this.systemId = systemId;
206
+ if (this._stateData.state === ContentDecryptorState.Initializing) {
207
+ this._stateData = { state: ContentDecryptorState.WaitingForAttachment,
208
+ isInitDataQueueLocked: true,
209
+ isMediaKeysAttached: false,
210
+ data: { mediaKeysInfo,
211
+ mediaElement } };
212
+
213
+ this.trigger("stateChange", this._stateData.state);
214
+ }
215
+ })
216
+
217
+ .catch((err) => {
218
+ this._onFatalError(err);
219
+ });
220
+ }
221
+
222
+ /**
223
+ * Returns the current state of the ContentDecryptor.
224
+ * @see ContentDecryptorState
225
+ * @returns {Object}
226
+ */
227
+ public getState() : ContentDecryptorState {
228
+ return this._stateData.state;
229
+ }
230
+
231
+ /**
232
+ * Attach the current decryption capabilities to the HTMLMediaElement.
233
+ * This method should only be called once the `ContentDecryptor` is in the
234
+ * `WaitingForAttachment` state.
235
+ *
236
+ * You might want to first set the HTMLMediaElement's `src` attribute before
237
+ * calling this method, and only push data to it once the `ReadyForContent`
238
+ * state is reached, for compatibility reasons.
239
+ */
240
+ public attach() : void {
241
+ if (this._stateData.state !== ContentDecryptorState.WaitingForAttachment) {
242
+ throw new Error("`attach` should only be called when " +
243
+ "in the WaitingForAttachment state");
244
+ } else if (this._wasAttachCalled) {
245
+ log.warn("DRM: ContentDecryptor's `attach` method called more than once.");
246
+ return;
247
+ }
248
+ this._wasAttachCalled = true;
249
+
250
+ const { mediaElement, mediaKeysInfo } = this._stateData.data;
251
+ const { options, mediaKeys, mediaKeySystemAccess, stores } = mediaKeysInfo;
252
+ const stateToAttatch = { loadedSessionsStore: stores.loadedSessionsStore,
253
+ mediaKeySystemAccess,
254
+ mediaKeys,
255
+ keySystemOptions: options };
256
+
257
+ const shouldDisableLock = options.disableMediaKeysAttachmentLock === true;
258
+ if (shouldDisableLock) {
259
+ this._stateData = { state: ContentDecryptorState.ReadyForContent,
260
+ isInitDataQueueLocked: true,
261
+ isMediaKeysAttached: false,
262
+ data: null };
263
+ this.trigger("stateChange", this._stateData.state);
264
+ if (this._isStopped()) { // previous trigger might have lead to disposal
265
+ return ;
266
+ }
267
+ }
268
+
269
+ log.debug("DRM: Attaching current MediaKeys");
270
+ attachMediaKeys(mediaElement, stateToAttatch, this._canceller.signal)
271
+ .then(async () => {
272
+ const { serverCertificate } = options;
273
+
274
+ if (!isNullOrUndefined(serverCertificate)) {
275
+ const resSsc = await setServerCertificate(mediaKeys, serverCertificate);
276
+ if (resSsc.type === "error") {
277
+ this.trigger("warning", resSsc.value);
278
+ }
279
+ }
280
+
281
+ if (this._isStopped()) { // We might be stopped since then
282
+ return;
283
+ }
284
+
285
+ const prevState = this._stateData.state;
286
+ this._stateData = { state: ContentDecryptorState.ReadyForContent,
287
+ isMediaKeysAttached: true,
288
+ isInitDataQueueLocked: false,
289
+ data: { mediaKeysData: mediaKeysInfo } };
290
+ if (prevState !== ContentDecryptorState.ReadyForContent) {
291
+ this.trigger("stateChange", ContentDecryptorState.ReadyForContent);
292
+ }
293
+ if (!this._isStopped()) {
294
+ this._processCurrentInitDataQueue();
295
+ }
296
+ })
297
+
298
+ .catch((err) => {
299
+ this._onFatalError(err);
300
+ });
301
+ }
302
+
303
+ /**
304
+ * Stop this `ContentDecryptor` instance:
305
+ * - stop listening and reacting to the various event listeners
306
+ * - abort all operations.
307
+ *
308
+ * Once disposed, a `ContentDecryptor` cannot be used anymore.
309
+ */
310
+ public dispose() {
311
+ this.removeEventListener();
312
+ this._stateData = { state: ContentDecryptorState.Disposed,
313
+ isMediaKeysAttached: undefined,
314
+ isInitDataQueueLocked: undefined,
315
+ data: null };
316
+ this._canceller.cancel();
317
+ this.trigger("stateChange", this._stateData.state);
318
+ }
319
+
320
+ /**
321
+ * Method to call when new protection initialization data is encounted on the
322
+ * content.
323
+ *
324
+ * When called, the `ContentDecryptor` will try to obtain the decryption key
325
+ * if not already obtained.
326
+ *
327
+ * @param {Object} initializationData
328
+ */
329
+ public onInitializationData(
330
+ initializationData : IProtectionData
331
+ ) : void {
332
+ if (this._stateData.isInitDataQueueLocked !== false) {
333
+ if (this._isStopped()) {
334
+ throw new Error("ContentDecryptor either disposed or stopped.");
335
+ }
336
+ this._initDataQueue.push(initializationData);
337
+ return;
338
+ }
339
+
340
+ const { mediaKeysData } = this._stateData.data;
341
+ const processedInitializationData = {
342
+ ...initializationData,
343
+ values: new InitDataValuesContainer(initializationData.values),
344
+ };
345
+ this._processInitializationData(processedInitializationData, mediaKeysData)
346
+ .catch(err => { this._onFatalError(err); });
347
+ }
348
+
349
+ /**
350
+ * Async logic run each time new initialization data has to be processed.
351
+ * The promise return may reject, in which case a fatal error should be linked
352
+ * the current `ContentDecryptor`.
353
+ *
354
+ * The Promise's resolution however provides no semantic value.
355
+ * @param {Object} initializationData
356
+ * @returns {Promise.<void>}
357
+ */
358
+ private async _processInitializationData(
359
+ initializationData: IProcessedProtectionData,
360
+ mediaKeysData: IAttachedMediaKeysData
361
+ ) : Promise<void> {
362
+ const { mediaKeySystemAccess, stores, options } = mediaKeysData;
363
+
364
+ if (this._tryToUseAlreadyCreatedSession(initializationData, mediaKeysData) ||
365
+ this._isStopped()) // _isStopped is voluntarly checked after here
366
+ {
367
+ return;
368
+ }
369
+
370
+ if (options.singleLicensePer === "content") {
371
+ const firstCreatedSession = arrayFind(this._currentSessions, (x) =>
372
+ x.source === MediaKeySessionLoadingType.Created);
373
+
374
+ if (firstCreatedSession !== undefined) {
375
+ // We already fetched a `singleLicensePer: "content"` license, yet we
376
+ // could not use the already-created MediaKeySession with it.
377
+ // It means that we'll never handle it and we should thus blacklist it.
378
+ const keyIds = initializationData.keyIds;
379
+ if (keyIds === undefined) {
380
+ if (initializationData.content === undefined) {
381
+ log.warn("DRM: Unable to fallback from a non-decipherable quality.");
382
+ } else {
383
+ blackListProtectionData(initializationData.content.manifest,
384
+ initializationData);
385
+ }
386
+ return ;
387
+ }
388
+
389
+ firstCreatedSession.record.associateKeyIds(keyIds);
390
+ if (initializationData.content !== undefined) {
391
+ if (log.getLevel() === "DEBUG") {
392
+ const hexKids = keyIds
393
+ .reduce((acc, kid) => `${acc}, ${bytesToHex(kid)}`, "");
394
+ log.debug("DRM: Blacklisting new key ids", hexKids);
395
+ }
396
+ updateDecipherability(initializationData.content.manifest, [], keyIds);
397
+ }
398
+ return ;
399
+ }
400
+ } else if (options.singleLicensePer === "periods" &&
401
+ initializationData.content !== undefined)
402
+ {
403
+ const { period } = initializationData.content;
404
+ const createdSessions = this._currentSessions
405
+ .filter(x => x.source === MediaKeySessionLoadingType.Created);
406
+ const periodKeys = new Set<Uint8Array>();
407
+ addKeyIdsFromPeriod(periodKeys, period);
408
+ for (const createdSess of createdSessions) {
409
+ const periodKeysArr = Array.from(periodKeys);
410
+ for (const kid of periodKeysArr) {
411
+ if (createdSess.record.isAssociatedWithKeyId(kid)) {
412
+ createdSess.record.associateKeyIds(periodKeys.values());
413
+
414
+ // Re-loop through the Period's key ids to blacklist ones that are missing
415
+ // from `createdSess`'s `keyStatuses` and to update the content's
416
+ // decipherability.
417
+ for (const innerKid of periodKeysArr) {
418
+ if (!isKeyIdContainedIn(innerKid, createdSess.keyStatuses.whitelisted) &&
419
+ !isKeyIdContainedIn(innerKid, createdSess.keyStatuses.blacklisted))
420
+ {
421
+ createdSess.keyStatuses.blacklisted.push(innerKid);
422
+ }
423
+ }
424
+ updateDecipherability(initializationData.content.manifest,
425
+ createdSess.keyStatuses.whitelisted,
426
+ createdSess.keyStatuses.blacklisted);
427
+ return;
428
+ }
429
+ }
430
+ }
431
+ }
432
+
433
+ // /!\ Do not forget to unlock when done
434
+ // TODO this is error-prone and can lead to performance issue when loading
435
+ // persistent sessions.
436
+ // Can we find a better strategy?
437
+ this._lockInitDataQueue();
438
+
439
+ let wantedSessionType : MediaKeySessionType;
440
+ if (options.persistentLicense !== true) {
441
+ wantedSessionType = "temporary";
442
+ } else if (!canCreatePersistentSession(mediaKeySystemAccess)) {
443
+ log.warn("DRM: Cannot create \"persistent-license\" session: not supported");
444
+ wantedSessionType = "temporary";
445
+ } else {
446
+ wantedSessionType = "persistent-license";
447
+ }
448
+
449
+ const { EME_DEFAULT_MAX_SIMULTANEOUS_MEDIA_KEY_SESSIONS,
450
+ EME_MAX_STORED_PERSISTENT_SESSION_INFORMATION } = config.getCurrent();
451
+
452
+ const maxSessionCacheSize = typeof options.maxSessionCacheSize === "number" ?
453
+ options.maxSessionCacheSize :
454
+ EME_DEFAULT_MAX_SIMULTANEOUS_MEDIA_KEY_SESSIONS;
455
+
456
+ const sessionRes = await createOrLoadSession(initializationData,
457
+ stores,
458
+ wantedSessionType,
459
+ maxSessionCacheSize,
460
+ this._canceller.signal);
461
+ if (this._isStopped()) {
462
+ return;
463
+ }
464
+
465
+ const sessionInfo : IActiveSessionInfo = {
466
+ record: sessionRes.value.keySessionRecord,
467
+ source: sessionRes.type,
468
+ keyStatuses: { whitelisted: [], blacklisted: [] },
469
+ blacklistedSessionError: null,
470
+ };
471
+ this._currentSessions.push(sessionInfo);
472
+
473
+ const { mediaKeySession, sessionType } = sessionRes.value;
474
+
475
+ /**
476
+ * We only store persistent sessions once its keys are known.
477
+ * This boolean allows to know if this session has already been
478
+ * persisted or not.
479
+ */
480
+ let isSessionPersisted = false;
481
+
482
+ const sub = SessionEventsListener(mediaKeySession,
483
+ options,
484
+ mediaKeySystemAccess.keySystem)
485
+ .subscribe({
486
+
487
+ next: (evt) : void => {
488
+ switch (evt.type) {
489
+ case "warning":
490
+ this.trigger("warning", evt.value);
491
+ return;
492
+ }
493
+
494
+ let linkedKeys;
495
+ if (sessionInfo.source === MediaKeySessionLoadingType.Created) {
496
+ // When the license has been fetched, there might be implicit key ids
497
+ // linked to the session depending on the `singleLicensePer` option.
498
+ linkedKeys = getFetchedLicenseKeysInfo(initializationData,
499
+ options.singleLicensePer,
500
+ evt.value.whitelistedKeyIds,
501
+ evt.value.blacklistedKeyIDs);
502
+ } else {
503
+ // When the MediaKeySession is just a cached/persisted one, we don't
504
+ // have any concept of "implicit key id".
505
+ linkedKeys = { whitelisted: evt.value.whitelistedKeyIds,
506
+ blacklisted: evt.value.blacklistedKeyIDs };
507
+ }
508
+
509
+ sessionInfo.record.associateKeyIds(linkedKeys.whitelisted);
510
+ sessionInfo.record.associateKeyIds(linkedKeys.blacklisted);
511
+ sessionInfo.keyStatuses = { whitelisted: linkedKeys.whitelisted,
512
+ blacklisted: linkedKeys.blacklisted };
513
+
514
+ if (sessionInfo.record.getAssociatedKeyIds().length !== 0 &&
515
+ sessionType === "persistent-license" &&
516
+ stores.persistentSessionsStore !== null &&
517
+ !isSessionPersisted)
518
+ {
519
+ const { persistentSessionsStore } = stores;
520
+ cleanOldStoredPersistentInfo(
521
+ persistentSessionsStore,
522
+ EME_MAX_STORED_PERSISTENT_SESSION_INFORMATION - 1);
523
+ persistentSessionsStore.add(initializationData,
524
+ sessionInfo.record.getAssociatedKeyIds(),
525
+ mediaKeySession);
526
+ isSessionPersisted = true;
527
+ }
528
+
529
+ if (initializationData.content !== undefined) {
530
+ updateDecipherability(initializationData.content.manifest,
531
+ linkedKeys.whitelisted,
532
+ linkedKeys.blacklisted);
533
+ }
534
+
535
+ this._unlockInitDataQueue();
536
+ },
537
+
538
+ error: (err) => {
539
+ if (!(err instanceof BlacklistedSessionError)) {
540
+ this._onFatalError(err);
541
+ return ;
542
+ }
543
+
544
+ sessionInfo.blacklistedSessionError = err;
545
+
546
+ if (initializationData.content !== undefined) {
547
+ const { manifest } = initializationData.content;
548
+ log.info("DRM: blacklisting Representations based on " +
549
+ "protection data.");
550
+ blackListProtectionData(manifest, initializationData);
551
+ }
552
+
553
+ this._unlockInitDataQueue();
554
+
555
+ // TODO warning for blacklisted session?
556
+ },
557
+ });
558
+ this._canceller.signal.register(() => {
559
+ sub.unsubscribe();
560
+ });
561
+
562
+ if (options.singleLicensePer === undefined ||
563
+ options.singleLicensePer === "init-data")
564
+ {
565
+ this._unlockInitDataQueue();
566
+ }
567
+
568
+ if (sessionRes.type === MediaKeySessionLoadingType.Created) {
569
+ const requestData = initializationData.values.constructRequestData();
570
+ try {
571
+ await generateKeyRequest(mediaKeySession,
572
+ initializationData.type,
573
+ requestData);
574
+ } catch (error) {
575
+ throw new EncryptedMediaError("KEY_GENERATE_REQUEST_ERROR",
576
+ error instanceof Error ? error.toString() :
577
+ "Unknown error");
578
+ }
579
+ }
580
+
581
+ return PPromise.resolve();
582
+ }
583
+
584
+ private _tryToUseAlreadyCreatedSession(
585
+ initializationData : IProcessedProtectionData,
586
+ mediaKeysData : IAttachedMediaKeysData
587
+ ) : boolean {
588
+ const { stores, options } = mediaKeysData;
589
+
590
+ /**
591
+ * If set, a currently-used key session is already compatible to this
592
+ * initialization data.
593
+ */
594
+ const compatibleSessionInfo = arrayFind(
595
+ this._currentSessions,
596
+ (x) => x.record.isCompatibleWith(initializationData));
597
+
598
+ if (compatibleSessionInfo === undefined) {
599
+ return false;
600
+ }
601
+
602
+ // Check if the compatible session is blacklisted
603
+ const blacklistedSessionError = compatibleSessionInfo.blacklistedSessionError;
604
+ if (!isNullOrUndefined(blacklistedSessionError)) {
605
+ if (initializationData.type === undefined ||
606
+ initializationData.content === undefined)
607
+ {
608
+ log.error("DRM: This initialization data has already been blacklisted " +
609
+ "but the current content is not known.");
610
+ return true;
611
+ } else {
612
+ log.info("DRM: This initialization data has already been blacklisted. " +
613
+ "Blacklisting the related content.");
614
+ const { manifest } = initializationData.content;
615
+ blackListProtectionData(manifest, initializationData);
616
+ return true;
617
+ }
618
+ }
619
+
620
+ // Check if the current key id(s) has been blacklisted by this session
621
+ if (initializationData.keyIds !== undefined) {
622
+ /**
623
+ * If set to `true`, the Representation(s) linked to this
624
+ * initialization data's key id should be marked as "not decipherable".
625
+ */
626
+ let isUndecipherable : boolean;
627
+
628
+ if (options.singleLicensePer === undefined ||
629
+ options.singleLicensePer === "init-data")
630
+ {
631
+ // Note: In the default "init-data" mode, we only avoid a
632
+ // Representation if the key id was originally explicitely
633
+ // blacklisted (and not e.g. if its key was just not present in
634
+ // the license).
635
+ //
636
+ // This is to enforce v3.x.x retro-compatibility: we cannot
637
+ // fallback from a Representation unless some RxPlayer option
638
+ // documentating this behavior has been set.
639
+ const { blacklisted } = compatibleSessionInfo.keyStatuses;
640
+ isUndecipherable = areSomeKeyIdsContainedIn(initializationData.keyIds,
641
+ blacklisted);
642
+ } else {
643
+ // In any other mode, as soon as not all of this initialization
644
+ // data's linked key ids are explicitely whitelisted, we can mark
645
+ // the corresponding Representation as "not decipherable".
646
+ // This is because we've no such retro-compatibility guarantee to
647
+ // make there.
648
+ const { whitelisted } = compatibleSessionInfo.keyStatuses;
649
+ isUndecipherable = !areAllKeyIdsContainedIn(initializationData.keyIds,
650
+ whitelisted);
651
+ }
652
+
653
+ if (isUndecipherable) {
654
+ if (initializationData.content === undefined) {
655
+ log.error("DRM: Cannot forbid key id, the content is unknown.");
656
+ return true;
657
+ }
658
+ log.info("DRM: Current initialization data is linked to blacklisted keys. " +
659
+ "Marking Representations as not decipherable");
660
+ updateDecipherability(initializationData.content.manifest,
661
+ [],
662
+ initializationData.keyIds);
663
+ return true;
664
+ }
665
+ }
666
+
667
+ // If we reached here, it means that this initialization data is not
668
+ // blacklisted in any way.
669
+ // Search loaded session and put it on top of the cache if it exists.
670
+ const entry = stores.loadedSessionsStore.reuse(initializationData);
671
+ if (entry !== null) {
672
+ // TODO update decipherability to `true` if not?
673
+ log.debug("DRM: Init data already processed. Skipping it.");
674
+ return true;
675
+ }
676
+
677
+ // Session not found in `loadedSessionsStore`, it might have been closed
678
+ // since.
679
+ // Remove from `this._currentSessions` and start again.
680
+ const indexOf = this._currentSessions.indexOf(compatibleSessionInfo);
681
+ if (indexOf === -1) {
682
+ log.error("DRM: Unable to remove processed init data: not found.");
683
+ } else {
684
+ log.debug("DRM: A session from a processed init data is not available " +
685
+ "anymore. Re-processing it.");
686
+ this._currentSessions.splice(indexOf, 1);
687
+ }
688
+ return false;
689
+ }
690
+
691
+ private _onFatalError(err : unknown) {
692
+ if (this._canceller.isUsed) {
693
+ return;
694
+ }
695
+ const formattedErr = err instanceof Error ?
696
+ err :
697
+ new OtherError("NONE", "Unknown encryption error");
698
+ this.error = formattedErr;
699
+ this._initDataQueue.length = 0;
700
+ this._stateData = { state: ContentDecryptorState.Error,
701
+ isMediaKeysAttached: undefined,
702
+ isInitDataQueueLocked: undefined,
703
+ data: null };
704
+ this._canceller.cancel();
705
+ this.trigger("error", formattedErr);
706
+
707
+ // The previous trigger might have lead to a disposal of the `ContentDecryptor`.
708
+ if (this._stateData.state === ContentDecryptorState.Error) {
709
+ this.trigger("stateChange", this._stateData.state);
710
+ }
711
+ }
712
+
713
+ /**
714
+ * Return `true` if the `ContentDecryptor` has either been disposed or
715
+ * encountered a fatal error which made it stop.
716
+ * @returns {boolean}
717
+ */
718
+ private _isStopped() : boolean {
719
+ return this._stateData.state === ContentDecryptorState.Disposed ||
720
+ this._stateData.state === ContentDecryptorState.Error;
721
+ }
722
+
723
+ private _processCurrentInitDataQueue() {
724
+ while (this._stateData.isInitDataQueueLocked === false) {
725
+ const initData = this._initDataQueue.shift();
726
+ if (initData === undefined) {
727
+ return;
728
+ }
729
+ this.onInitializationData(initData);
730
+ }
731
+ }
732
+
733
+ private _lockInitDataQueue() {
734
+ if (this._stateData.isInitDataQueueLocked === false) {
735
+ this._stateData.isInitDataQueueLocked = true;
736
+ }
737
+ }
738
+
739
+ private _unlockInitDataQueue() {
740
+ if (this._stateData.isMediaKeysAttached !== true) {
741
+ log.error("DRM: Trying to unlock in the wrong state");
742
+ return;
743
+ }
744
+ this._stateData.isInitDataQueueLocked = false;
745
+ this._processCurrentInitDataQueue();
746
+ }
747
+ }
748
+
749
+ /**
750
+ * Returns `true` if the given MediaKeySystemAccess can create
751
+ * "persistent-license" MediaKeySessions.
752
+ * @param {MediaKeySystemAccess} mediaKeySystemAccess
753
+ * @returns {Boolean}
754
+ */
755
+ function canCreatePersistentSession(
756
+ mediaKeySystemAccess : MediaKeySystemAccess | ICustomMediaKeySystemAccess
757
+ ) : boolean {
758
+ const { sessionTypes } = mediaKeySystemAccess.getConfiguration();
759
+ return sessionTypes !== undefined &&
760
+ arrayIncludes(sessionTypes, "persistent-license");
761
+ }
762
+
763
+ function updateDecipherability(
764
+ manifest : Manifest,
765
+ whitelistedKeyIds : Uint8Array[],
766
+ blacklistedKeyIDs : Uint8Array[]
767
+ ) : void {
768
+ manifest.updateRepresentationsDeciperability((representation) => {
769
+ if (representation.contentProtections === undefined) {
770
+ return representation.decipherable;
771
+ }
772
+ const contentKIDs = representation.contentProtections.keyIds;
773
+ for (let i = 0; i < contentKIDs.length; i++) {
774
+ const elt = contentKIDs[i];
775
+ for (let j = 0; j < blacklistedKeyIDs.length; j++) {
776
+ if (areKeyIdsEqual(blacklistedKeyIDs[j], elt.keyId)) {
777
+ return false;
778
+ }
779
+ }
780
+ for (let j = 0; j < whitelistedKeyIds.length; j++) {
781
+ if (areKeyIdsEqual(whitelistedKeyIds[j], elt.keyId)) {
782
+ return true;
783
+ }
784
+ }
785
+ }
786
+ return representation.decipherable;
787
+ });
788
+ }
789
+
790
+ function blackListProtectionData(
791
+ manifest : Manifest,
792
+ initData : IProcessedProtectionData
793
+ ) : void {
794
+ manifest.updateRepresentationsDeciperability((representation) => {
795
+ if (representation.decipherable === false) {
796
+ return false;
797
+ }
798
+ const segmentProtections = representation.contentProtections?.initData ?? [];
799
+ for (let i = 0; i < segmentProtections.length; i++) {
800
+ if (initData.type === undefined ||
801
+ segmentProtections[i].type === initData.type)
802
+ {
803
+ const containedInitData = initData.values.getFormattedValues()
804
+ .every(undecipherableVal => {
805
+ return segmentProtections[i].values.some(currVal => {
806
+ return (undecipherableVal.systemId === undefined ||
807
+ currVal.systemId === undecipherableVal.systemId) &&
808
+ areArraysOfNumbersEqual(currVal.data,
809
+ undecipherableVal.data);
810
+ });
811
+ });
812
+ if (containedInitData) {
813
+ return false;
814
+ }
815
+ }
816
+ }
817
+ return representation.decipherable;
818
+ });
819
+ }
820
+
821
+ /** Events sent by the `ContentDecryptor`, in a `{ event: payload }` format. */
822
+ export interface IContentDecryptorEvent {
823
+ /**
824
+ * Event emitted when a major error occured which made the ContentDecryptor
825
+ * stopped.
826
+ * When that event is sent, the `ContentDecryptor` is in the `Error` state and
827
+ * cannot be used anymore.
828
+ */
829
+ error : Error;
830
+
831
+ /**
832
+ * Event emitted when a minor error occured which the ContentDecryptor can
833
+ * recover from.
834
+ */
835
+ warning : ICustomError;
836
+
837
+ /**
838
+ * Event emitted when the `ContentDecryptor`'s state changed.
839
+ * States are a central aspect of the `ContentDecryptor`, be sure to check the
840
+ * ContentDecryptorState type.
841
+ */
842
+ stateChange: ContentDecryptorState;
843
+ }
844
+
845
+ /** Enumeration of the various "state" the `ContentDecryptor` can be in. */
846
+ export enum ContentDecryptorState {
847
+ /**
848
+ * The `ContentDecryptor` is not yet ready to create key sessions and request
849
+ * licenses.
850
+ * This is is the initial state of the ContentDecryptor.
851
+ */
852
+ Initializing,
853
+
854
+ /**
855
+ * The `ContentDecryptor` has been initialized.
856
+ * You should now called the `attach` method when you want to add decryption
857
+ * capabilities to the HTMLMediaElement. The ContentDecryptor won't go to the
858
+ * `ReadyForContent` state until `attach` is called.
859
+ *
860
+ * For compatibility reasons, this should be done after the HTMLMediaElement's
861
+ * src attribute is set.
862
+ *
863
+ * It is also from when this state is reached that the `ContentDecryptor`'s
864
+ * `systemId` property may be known.
865
+ *
866
+ * This state is always coming after the `Initializing` state.
867
+ */
868
+ WaitingForAttachment,
869
+
870
+ /**
871
+ * Content (encrypted or not) can begin to be pushed on the HTMLMediaElement
872
+ * (this state was needed because some browser quirks sometimes forces us to
873
+ * call EME API before this can be done).
874
+ *
875
+ * This state is always coming after the `WaitingForAttachment` state.
876
+ */
877
+ ReadyForContent,
878
+
879
+ /**
880
+ * The `ContentDecryptor` has encountered a fatal error and has been stopped.
881
+ * It is now unusable.
882
+ */
883
+ Error,
884
+
885
+ /** The `ContentDecryptor` has been disposed of and is now unusable. */
886
+ Disposed,
887
+ }
888
+
889
+ /** Possible states the ContentDecryptor is in and associated data for each one. */
890
+ type IContentDecryptorStateData = IInitializingStateData |
891
+ IWaitingForAttachmentStateData |
892
+ IReadyForContentStateDataUnattached |
893
+ IReadyForContentStateDataAttached |
894
+ IDisposeStateData |
895
+ IErrorStateData;
896
+
897
+ /** Skeleton that all variants of `IContentDecryptorStateData` use. */
898
+ interface IContentDecryptorStateBase<
899
+ TStateName extends ContentDecryptorState,
900
+ TIsQueueLocked extends boolean | undefined,
901
+ TIsMediaKeyAttached extends boolean | undefined,
902
+ TData
903
+ > {
904
+ /** Identify the ContentDecryptor's state. */
905
+ state: TStateName;
906
+ /**
907
+ * If `true`, the `ContentDecryptor` will wait before processing
908
+ * newly-received initialization data.
909
+ * If `false`, it will process them right away.
910
+ * Set to undefined when it won't ever process them like for example in a
911
+ * disposed or errored state.
912
+ */
913
+ isInitDataQueueLocked: TIsQueueLocked;
914
+ /**
915
+ * If `true`, the `MediaKeys` instance has been attached to the HTMLMediaElement.
916
+ * If `false`, it hasn't happened yet.
917
+ * If uncertain or unimportant (for example if the `ContentDecryptor` is an
918
+ * disposed/errored state, set to `undefined`).
919
+ */
920
+ isMediaKeysAttached: TIsMediaKeyAttached;
921
+ /** Data stored relative to that state. */
922
+ data: TData;
923
+ }
924
+
925
+ /** ContentDecryptor's internal data when in the `Initializing` state. */
926
+ type IInitializingStateData = IContentDecryptorStateBase<
927
+ ContentDecryptorState.Initializing,
928
+ true, // isInitDataQueueLocked
929
+ false, // isMediaKeysAttached
930
+ null // data
931
+ >;
932
+
933
+ /** ContentDecryptor's internal data when in the `WaitingForAttachment` state. */
934
+ type IWaitingForAttachmentStateData = IContentDecryptorStateBase<
935
+ ContentDecryptorState.WaitingForAttachment,
936
+ true, // isInitDataQueueLocked
937
+ false, // isMediaKeysAttached
938
+ // data
939
+ { mediaKeysInfo : IMediaKeysInfos;
940
+ mediaElement : HTMLMediaElement; }
941
+ >;
942
+
943
+ /**
944
+ * ContentDecryptor's internal data when in the `ReadyForContent` state before
945
+ * it has attached the `MediaKeys` to the media element.
946
+ */
947
+ type IReadyForContentStateDataUnattached = IContentDecryptorStateBase<
948
+ ContentDecryptorState.ReadyForContent,
949
+ true, // isInitDataQueueLocked
950
+ false, // isMediaKeysAttached
951
+ null // data
952
+ >;
953
+
954
+ /**
955
+ * ContentDecryptor's internal data when in the `ReadyForContent` state once
956
+ * it has attached the `MediaKeys` to the media element.
957
+ */
958
+ type IReadyForContentStateDataAttached = IContentDecryptorStateBase<
959
+ ContentDecryptorState.ReadyForContent,
960
+ boolean, // isInitDataQueueLocked
961
+ true, // isMediaKeysAttached
962
+ {
963
+ /**
964
+ * MediaKeys-related information linked to this instance of the
965
+ * `ContentDecryptor`.
966
+ * Set to `null` until it is known.
967
+ * Should be always set when the `ContentDecryptor` has reached the
968
+ * Initialized state (@see ContentDecryptorState).
969
+ */
970
+ mediaKeysData : IAttachedMediaKeysData;
971
+ }
972
+ >;
973
+
974
+ /** ContentDecryptor's internal data when in the `Disposed` state. */
975
+ type IDisposeStateData = IContentDecryptorStateBase<
976
+ ContentDecryptorState.Disposed,
977
+ undefined, // isInitDataQueueLocked
978
+ undefined, // isMediaKeysAttached
979
+ null // data
980
+ >;
981
+
982
+ /** ContentDecryptor's internal data when in the `Error` state. */
983
+ type IErrorStateData = IContentDecryptorStateBase<
984
+ ContentDecryptorState.Error,
985
+ undefined, // isInitDataQueueLocked
986
+ undefined, // isMediaKeysAttached
987
+ null // data
988
+ >;
989
+
990
+ /** Information linked to a session created by the `ContentDecryptor`. */
991
+ interface IActiveSessionInfo {
992
+ /**
993
+ * Record associated to the session.
994
+ * Most notably, it allows both to identify the session as well as to
995
+ * anounce and find out which key ids are already handled.
996
+ */
997
+ record : KeySessionRecord;
998
+
999
+ /** Current keys' statuses linked that session. */
1000
+ keyStatuses : {
1001
+ /** Key ids linked to keys that are "usable". */
1002
+ whitelisted : Uint8Array[];
1003
+ /**
1004
+ * Key ids linked to keys that are not considered "usable".
1005
+ * Content linked to those keys are not decipherable and may thus be
1006
+ * fallbacked from.
1007
+ */
1008
+ blacklisted : Uint8Array[];
1009
+ };
1010
+
1011
+ /** Source of the MediaKeySession linked to that record. */
1012
+ source : MediaKeySessionLoadingType;
1013
+
1014
+ /**
1015
+ * If different than `null`, all initialization data compatible with this
1016
+ * processed initialization data has been blacklisted with this corresponding
1017
+ * error.
1018
+ */
1019
+ blacklistedSessionError : BlacklistedSessionError | null;
1020
+ }
1021
+
1022
+ /**
1023
+ * Sent when the created (or already created) MediaKeys is attached to the
1024
+ * current HTMLMediaElement element.
1025
+ * On some peculiar devices, we have to wait for that step before the first
1026
+ * media segments are to be pushed to avoid issues.
1027
+ * Because this event is sent after a MediaKeys is created, you will always have
1028
+ * a "created-media-keys" event before an "attached-media-keys" event.
1029
+ */
1030
+ interface IAttachedMediaKeysData {
1031
+ /** The MediaKeySystemAccess which allowed to create the MediaKeys instance. */
1032
+ mediaKeySystemAccess: MediaKeySystemAccess |
1033
+ ICustomMediaKeySystemAccess;
1034
+ /** The MediaKeys instance. */
1035
+ mediaKeys : MediaKeys |
1036
+ ICustomMediaKeys;
1037
+ stores : IMediaKeySessionStores;
1038
+ options : IKeySystemOption;
1039
+ }
1040
+
1041
+ /**
1042
+ * Returns information on all keys - explicit or implicit - that are linked to
1043
+ * a loaded license.
1044
+ *
1045
+ * In the RxPlayer, there is a concept of "explicit" key ids, which are key ids
1046
+ * found in a license whose status can be known through the `keyStatuses`
1047
+ * property from a `MediaKeySession`, and of "implicit" key ids, which are key
1048
+ * ids which were expected to be in a fetched license, but apparently weren't.
1049
+ * @param {Object} initializationData
1050
+ * @param {string|undefined} singleLicensePer
1051
+ * @param {Array.<Uint8Array>} usableKeyIds
1052
+ * @param {Array.<Uint8Array>} unusableKeyIds
1053
+ * @returns {Object}
1054
+ */
1055
+ function getFetchedLicenseKeysInfo(
1056
+ initializationData : IProcessedProtectionData,
1057
+ singleLicensePer : undefined | "init-data" | "content" | "periods",
1058
+ usableKeyIds : Uint8Array[],
1059
+ unusableKeyIds : Uint8Array[]
1060
+ ) : { whitelisted : Uint8Array[];
1061
+ blacklisted : Uint8Array[]; }
1062
+ {
1063
+ /**
1064
+ * Every key id associated with the MediaKeySession, starting with
1065
+ * whitelisted ones.
1066
+ */
1067
+ const associatedKeyIds = [...usableKeyIds,
1068
+ ...unusableKeyIds];
1069
+
1070
+ if (singleLicensePer !== undefined && singleLicensePer !== "init-data") {
1071
+ // We want to add the current key ids in the blacklist if it is
1072
+ // not already there.
1073
+ //
1074
+ // We only do that when `singleLicensePer` is set to something
1075
+ // else than the default `"init-data"` because this logic:
1076
+ // 1. might result in a quality fallback, which is a v3.x.x
1077
+ // breaking change if some APIs (like `singleLicensePer`)
1078
+ // aren't used.
1079
+ // 2. Rely on the EME spec regarding key statuses being well
1080
+ // implemented on all supported devices, which we're not
1081
+ // sure yet. Because in any other `singleLicensePer`, we
1082
+ // need a good implementation anyway, it doesn't matter
1083
+ // there.
1084
+ const { keyIds: expectedKeyIds,
1085
+ content } = initializationData;
1086
+ if (expectedKeyIds !== undefined) {
1087
+ const missingKeyIds = expectedKeyIds.filter(expected => {
1088
+ return !associatedKeyIds.some(k => areKeyIdsEqual(k, expected));
1089
+ });
1090
+ if (missingKeyIds.length > 0) {
1091
+ associatedKeyIds.push(...missingKeyIds) ;
1092
+ }
1093
+ }
1094
+
1095
+ if (content !== undefined) {
1096
+ if (singleLicensePer === "content") {
1097
+ // Put it in a Set to automatically filter out duplicates (by ref)
1098
+ const contentKeys = new Set<Uint8Array>();
1099
+ const { manifest } = content;
1100
+ for (const period of manifest.periods) {
1101
+ addKeyIdsFromPeriod(contentKeys, period);
1102
+ }
1103
+ mergeKeyIdSetIntoArray(contentKeys, associatedKeyIds);
1104
+ } else if (singleLicensePer === "periods") {
1105
+ const { manifest } = content;
1106
+ for (const period of manifest.periods) {
1107
+ const periodKeys = new Set<Uint8Array>();
1108
+ addKeyIdsFromPeriod(periodKeys, period);
1109
+ if (initializationData.content?.period.id === period.id) {
1110
+ mergeKeyIdSetIntoArray(periodKeys, associatedKeyIds);
1111
+ } else {
1112
+ const periodKeysArr = Array.from(periodKeys);
1113
+ for (const kid of periodKeysArr) {
1114
+ const isFound = associatedKeyIds.some(k => areKeyIdsEqual(k, kid));
1115
+ if (isFound) {
1116
+ mergeKeyIdSetIntoArray(periodKeys, associatedKeyIds);
1117
+ break;
1118
+ }
1119
+ }
1120
+ }
1121
+ }
1122
+ }
1123
+ }
1124
+ }
1125
+ return { whitelisted: usableKeyIds,
1126
+ /** associatedKeyIds starts with the whitelisted one. */
1127
+ blacklisted: associatedKeyIds.slice(usableKeyIds.length) };
1128
+ }
1129
+
1130
+ function mergeKeyIdSetIntoArray(
1131
+ set : Set<Uint8Array>,
1132
+ arr : Uint8Array[]
1133
+ ) {
1134
+ const setArr = Array.from(set.values());
1135
+ for (const kid of setArr) {
1136
+ const isFound = arr.some(k => areKeyIdsEqual(k, kid));
1137
+ if (!isFound) {
1138
+ arr.push(kid);
1139
+ }
1140
+ }
1141
+ }
1142
+
1143
+ function addKeyIdsFromPeriod(
1144
+ set : Set<Uint8Array>,
1145
+ period : Period
1146
+ ) {
1147
+ for (const adaptation of period.getAdaptations()) {
1148
+ for (const representation of adaptation.representations) {
1149
+ if (representation.contentProtections !== undefined &&
1150
+ representation.contentProtections.keyIds.length >= - 1)
1151
+ {
1152
+ for (const kidInf of representation.contentProtections.keyIds) {
1153
+ set.add(kidInf.keyId);
1154
+ }
1155
+ }
1156
+ }
1157
+ }
1158
+ }