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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. package/.eslintrc.js +8 -0
  2. package/CHANGELOG.md +93 -0
  3. package/CONTRIBUTING.md +48 -168
  4. package/FILES.md +40 -92
  5. package/VERSION +1 -1
  6. package/dist/_esm5.processed/compat/browser_detection.d.ts +25 -12
  7. package/dist/_esm5.processed/compat/browser_detection.js +85 -38
  8. package/dist/_esm5.processed/compat/can_reuse_media_keys.js +2 -2
  9. package/dist/_esm5.processed/compat/eme/close_session.js +2 -2
  10. package/dist/_esm5.processed/compat/eme/load_session.js +1 -1
  11. package/dist/_esm5.processed/compat/event_listeners.js +1 -1
  12. package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.d.ts +21 -0
  13. package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.js +26 -0
  14. package/dist/_esm5.processed/config.d.ts +4 -0
  15. package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +9 -6
  16. package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.d.ts +18 -1
  17. package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.js +106 -25
  18. package/dist/_esm5.processed/core/adaptive/guess_based_chooser.js +6 -6
  19. package/dist/_esm5.processed/core/adaptive/network_analyzer.js +8 -5
  20. package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.d.ts +19 -1
  21. package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.js +1 -1
  22. package/dist/_esm5.processed/core/api/debug/buffer_graph.d.ts +28 -0
  23. package/dist/_esm5.processed/core/api/debug/buffer_graph.js +175 -0
  24. package/dist/_esm5.processed/core/api/debug/buffer_size_graph.d.ts +10 -0
  25. package/dist/_esm5.processed/core/api/debug/buffer_size_graph.js +104 -0
  26. package/dist/_esm5.processed/core/api/debug/constants.d.ts +2 -0
  27. package/dist/_esm5.processed/core/api/debug/constants.js +2 -0
  28. package/dist/_esm5.processed/core/api/debug/index.d.ts +2 -0
  29. package/dist/_esm5.processed/core/api/debug/index.js +2 -0
  30. package/dist/_esm5.processed/core/api/debug/modules/general_info.d.ts +3 -0
  31. package/dist/_esm5.processed/core/api/debug/modules/general_info.js +180 -0
  32. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.d.ts +4 -0
  33. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.js +121 -0
  34. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.d.ts +3 -0
  35. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.js +35 -0
  36. package/dist/_esm5.processed/core/api/debug/render.d.ts +3 -0
  37. package/dist/_esm5.processed/core/api/debug/render.js +32 -0
  38. package/dist/_esm5.processed/core/api/debug/utils.d.ts +39 -0
  39. package/dist/_esm5.processed/core/api/debug/utils.js +57 -0
  40. package/dist/_esm5.processed/core/api/playback_observer.js +4 -2
  41. package/dist/_esm5.processed/core/api/public_api.d.ts +60 -3
  42. package/dist/_esm5.processed/core/api/public_api.js +280 -60
  43. package/dist/_esm5.processed/core/api/track_management/media_element_tracks_store.js +10 -1
  44. package/dist/_esm5.processed/core/api/track_management/track_dispatcher.d.ts +13 -1
  45. package/dist/_esm5.processed/core/api/track_management/track_dispatcher.js +30 -15
  46. package/dist/_esm5.processed/core/api/track_management/tracks_store.d.ts +3 -1
  47. package/dist/_esm5.processed/core/api/track_management/tracks_store.js +67 -152
  48. package/dist/_esm5.processed/core/api/utils.d.ts +10 -0
  49. package/dist/_esm5.processed/core/api/utils.js +23 -3
  50. package/dist/_esm5.processed/core/decrypt/__tests__/__global__/utils.d.ts +27 -8
  51. package/dist/_esm5.processed/core/decrypt/__tests__/__global__/utils.js +28 -7
  52. package/dist/_esm5.processed/core/decrypt/attach_media_keys.js +1 -1
  53. package/dist/_esm5.processed/core/decrypt/content_decryptor.js +1 -1
  54. package/dist/_esm5.processed/core/decrypt/find_key_system.js +29 -6
  55. package/dist/_esm5.processed/core/decrypt/session_events_listener.js +42 -32
  56. package/dist/_esm5.processed/core/decrypt/utils/check_key_statuses.js +4 -0
  57. package/dist/_esm5.processed/core/decrypt/utils/clean_old_loaded_sessions.js +2 -0
  58. package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +5 -1
  59. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.d.ts +17 -8
  60. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.js +10 -6
  61. package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.js +5 -4
  62. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +22 -5
  63. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +37 -21
  64. package/dist/_esm5.processed/core/fetchers/segment/task_prioritizer.js +21 -23
  65. package/dist/_esm5.processed/core/fetchers/utils/schedule_request.js +17 -7
  66. package/dist/_esm5.processed/core/init/directfile_content_initializer.js +2 -2
  67. package/dist/_esm5.processed/core/init/media_source_content_initializer.js +74 -41
  68. package/dist/_esm5.processed/core/init/types.d.ts +9 -1
  69. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.d.ts +28 -1
  70. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.js +24 -11
  71. package/dist/_esm5.processed/core/init/utils/create_media_source.js +3 -12
  72. package/dist/_esm5.processed/core/init/utils/end_of_stream.js +6 -3
  73. package/dist/_esm5.processed/core/init/utils/get_loaded_reference.js +2 -1
  74. package/dist/_esm5.processed/core/init/utils/initial_seek_and_play.js +9 -5
  75. package/dist/_esm5.processed/core/init/utils/initialize_content_decryption.js +2 -1
  76. package/dist/_esm5.processed/core/init/utils/media_source_duration_updater.d.ts +58 -0
  77. package/dist/_esm5.processed/core/init/utils/{media_duration_updater.js → media_source_duration_updater.js} +87 -86
  78. package/dist/_esm5.processed/core/init/utils/rebuffering_controller.d.ts +36 -2
  79. package/dist/_esm5.processed/core/init/utils/rebuffering_controller.js +83 -3
  80. package/dist/_esm5.processed/core/init/utils/stream_events_emitter/stream_events_emitter.js +6 -4
  81. package/dist/_esm5.processed/core/init/utils/throw_on_media_error.js +1 -1
  82. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.d.ts +18 -7
  83. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +38 -50
  84. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.d.ts +8 -0
  85. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +16 -2
  86. package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.d.ts +8 -0
  87. package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.js +12 -0
  88. package/dist/_esm5.processed/core/segment_buffers/implementations/types.d.ts +11 -4
  89. package/dist/_esm5.processed/core/segment_buffers/index.d.ts +2 -2
  90. package/dist/_esm5.processed/core/segment_buffers/segment_buffers_store.js +13 -9
  91. package/dist/_esm5.processed/core/stream/adaptation/adaptation_stream.js +30 -16
  92. package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.d.ts +47 -0
  93. package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.js +70 -0
  94. package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +41 -20
  95. package/dist/_esm5.processed/core/stream/period/period_stream.js +12 -11
  96. package/dist/_esm5.processed/core/stream/representation/representation_stream.js +37 -28
  97. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.d.ts +4 -2
  98. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.js +3 -3
  99. package/dist/_esm5.processed/core/stream/representation/utils/downloading_queue.js +16 -6
  100. package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.d.ts +3 -2
  101. package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.js +8 -8
  102. package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.d.ts +2 -2
  103. package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.js +2 -3
  104. package/dist/_esm5.processed/core/stream/utils/create_reload_request.js +1 -1
  105. package/dist/_esm5.processed/default_config.d.ts +41 -0
  106. package/dist/_esm5.processed/default_config.js +46 -2
  107. package/dist/_esm5.processed/errors/index.d.ts +2 -2
  108. package/dist/_esm5.processed/errors/media_error.d.ts +23 -1
  109. package/dist/_esm5.processed/errors/media_error.js +18 -5
  110. package/dist/_esm5.processed/experimental/features/debug_element.d.ts +8 -0
  111. package/dist/_esm5.processed/experimental/features/debug_element.js +10 -0
  112. package/dist/_esm5.processed/experimental/features/index.d.ts +1 -0
  113. package/dist/_esm5.processed/experimental/features/index.js +1 -0
  114. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.d.ts +1 -1
  115. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.js +8 -7
  116. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.js +7 -4
  117. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +24 -12
  118. package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/index.js +0 -2
  119. package/dist/_esm5.processed/features/features_object.js +1 -0
  120. package/dist/_esm5.processed/features/initialize_features.js +13 -10
  121. package/dist/_esm5.processed/features/types.d.ts +3 -0
  122. package/dist/_esm5.processed/manifest/adaptation.d.ts +21 -2
  123. package/dist/_esm5.processed/manifest/adaptation.js +80 -1
  124. package/dist/_esm5.processed/manifest/manifest.js +2 -0
  125. package/dist/_esm5.processed/manifest/period.js +2 -2
  126. package/dist/_esm5.processed/manifest/representation.d.ts +33 -2
  127. package/dist/_esm5.processed/manifest/representation.js +32 -4
  128. package/dist/_esm5.processed/manifest/utils.js +1 -3
  129. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_adaptation_sets.js +105 -137
  130. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +25 -5
  131. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.d.ts +1 -1
  132. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.js +1 -1
  133. package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.js +1 -0
  134. package/dist/_esm5.processed/public_types.d.ts +13 -3
  135. package/dist/_esm5.processed/tools/TextTrackRenderer/text_track_renderer.js +1 -1
  136. package/dist/_esm5.processed/transports/dash/add_segment_integrity_checks_to_loader.js +15 -11
  137. package/dist/_esm5.processed/transports/dash/low_latency_segment_loader.js +2 -2
  138. package/dist/_esm5.processed/transports/dash/manifest_parser.js +1 -1
  139. package/dist/_esm5.processed/transports/dash/segment_loader.js +4 -4
  140. package/dist/_esm5.processed/transports/local/segment_loader.js +13 -26
  141. package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.d.ts +4 -6
  142. package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.js +4 -6
  143. package/dist/_esm5.processed/transports/smooth/segment_loader.js +4 -4
  144. package/dist/_esm5.processed/transports/utils/call_custom_manifest_loader.js +3 -3
  145. package/dist/_esm5.processed/utils/cancellable_sleep.js +4 -10
  146. package/dist/_esm5.processed/utils/create_cancellable_promise.d.ts +26 -0
  147. package/dist/_esm5.processed/utils/create_cancellable_promise.js +52 -0
  148. package/dist/_esm5.processed/utils/is_null_or_undefined.d.ts +1 -1
  149. package/dist/_esm5.processed/utils/is_null_or_undefined.js +1 -1
  150. package/dist/_esm5.processed/utils/reference.js +6 -0
  151. package/dist/_esm5.processed/utils/request/xhr.js +1 -1
  152. package/dist/_esm5.processed/utils/task_canceller.d.ts +34 -15
  153. package/dist/_esm5.processed/utils/task_canceller.js +55 -22
  154. package/dist/mpd-parser.wasm +0 -0
  155. package/dist/rx-player.js +5424 -4712
  156. package/dist/rx-player.min.js +1 -1
  157. package/jest.config.js +1 -5
  158. package/package.json +44 -40
  159. package/scripts/build/constants.d.ts +1 -0
  160. package/scripts/build/generate_build.js +1 -1
  161. package/scripts/fast_demo_build.js +40 -40
  162. package/scripts/generate_full_demo.js +1 -1
  163. package/sonar-project.properties +1 -1
  164. package/src/compat/browser_detection.ts +105 -52
  165. package/src/compat/can_reuse_media_keys.ts +5 -2
  166. package/src/compat/eme/close_session.ts +2 -2
  167. package/src/compat/eme/load_session.ts +1 -1
  168. package/src/compat/event_listeners.ts +1 -1
  169. package/src/compat/has_issues_with_high_media_source_duration.ts +27 -0
  170. package/src/core/adaptive/__tests__/buffer_based_chooser.test.ts +147 -48
  171. package/src/core/adaptive/adaptive_representation_selector.ts +11 -6
  172. package/src/core/adaptive/buffer_based_chooser.ts +144 -26
  173. package/src/core/adaptive/guess_based_chooser.ts +9 -8
  174. package/src/core/adaptive/network_analyzer.ts +9 -4
  175. package/src/core/adaptive/utils/representation_score_calculator.ts +22 -2
  176. package/src/core/api/debug/buffer_graph.ts +247 -0
  177. package/src/core/api/debug/buffer_size_graph.ts +130 -0
  178. package/src/core/api/debug/constants.ts +2 -0
  179. package/src/core/api/debug/index.ts +3 -0
  180. package/src/core/api/debug/modules/general_info.ts +184 -0
  181. package/src/core/api/debug/modules/segment_buffer_content.ts +155 -0
  182. package/src/core/api/debug/modules/segment_buffer_size.ts +48 -0
  183. package/src/core/api/debug/render.ts +40 -0
  184. package/src/core/api/debug/utils.ts +103 -0
  185. package/src/core/api/playback_observer.ts +5 -2
  186. package/src/core/api/public_api.ts +334 -73
  187. package/src/core/api/track_management/media_element_tracks_store.ts +17 -8
  188. package/src/core/api/track_management/track_dispatcher.ts +37 -14
  189. package/src/core/api/track_management/tracks_store.ts +77 -167
  190. package/src/core/api/utils.ts +29 -3
  191. package/src/core/decrypt/__tests__/__global__/utils.ts +61 -40
  192. package/src/core/decrypt/attach_media_keys.ts +1 -1
  193. package/src/core/decrypt/content_decryptor.ts +1 -1
  194. package/src/core/decrypt/find_key_system.ts +25 -11
  195. package/src/core/decrypt/session_events_listener.ts +45 -39
  196. package/src/core/decrypt/utils/check_key_statuses.ts +6 -0
  197. package/src/core/decrypt/utils/clean_old_loaded_sessions.ts +2 -1
  198. package/src/core/decrypt/utils/loaded_sessions_store.ts +8 -1
  199. package/src/core/fetchers/cdn_prioritizer.ts +18 -9
  200. package/src/core/fetchers/manifest/manifest_fetcher.ts +5 -4
  201. package/src/core/fetchers/segment/segment_fetcher.ts +36 -14
  202. package/src/core/fetchers/segment/task_prioritizer.ts +25 -30
  203. package/src/core/fetchers/utils/schedule_request.ts +18 -7
  204. package/src/core/init/directfile_content_initializer.ts +2 -1
  205. package/src/core/init/media_source_content_initializer.ts +89 -50
  206. package/src/core/init/types.ts +9 -1
  207. package/src/core/init/utils/content_time_boundaries_observer.ts +48 -12
  208. package/src/core/init/utils/create_media_source.ts +4 -16
  209. package/src/core/init/utils/end_of_stream.ts +6 -3
  210. package/src/core/init/utils/get_loaded_reference.ts +2 -1
  211. package/src/core/init/utils/initial_seek_and_play.ts +9 -5
  212. package/src/core/init/utils/initialize_content_decryption.ts +2 -1
  213. package/src/core/init/utils/{media_duration_updater.ts → media_source_duration_updater.ts} +103 -110
  214. package/src/core/init/utils/rebuffering_controller.ts +115 -4
  215. package/src/core/init/utils/stream_events_emitter/stream_events_emitter.ts +6 -4
  216. package/src/core/init/utils/throw_on_media_error.ts +1 -1
  217. package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +63 -66
  218. package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +20 -2
  219. package/src/core/segment_buffers/implementations/text/native/native_text_segment_buffer.ts +16 -0
  220. package/src/core/segment_buffers/implementations/types.ts +16 -4
  221. package/src/core/segment_buffers/index.ts +2 -0
  222. package/src/core/segment_buffers/segment_buffers_store.ts +16 -13
  223. package/src/core/stream/adaptation/adaptation_stream.ts +33 -19
  224. package/src/core/stream/adaptation/utils/create_representation_estimator.ts +114 -0
  225. package/src/core/stream/orchestrator/stream_orchestrator.ts +42 -20
  226. package/src/core/stream/period/period_stream.ts +13 -11
  227. package/src/core/stream/representation/representation_stream.ts +49 -37
  228. package/src/core/stream/representation/utils/append_segment_to_buffer.ts +9 -4
  229. package/src/core/stream/representation/utils/downloading_queue.ts +16 -4
  230. package/src/core/stream/representation/utils/push_init_segment.ts +11 -6
  231. package/src/core/stream/representation/utils/push_media_segment.ts +3 -3
  232. package/src/core/stream/utils/create_reload_request.ts +1 -1
  233. package/src/default_config.ts +59 -11
  234. package/src/errors/__tests__/media_error.test.ts +6 -6
  235. package/src/errors/index.ts +4 -1
  236. package/src/errors/media_error.ts +67 -1
  237. package/src/experimental/features/__tests__/debug_element.test.ts +26 -0
  238. package/src/experimental/features/debug_element.ts +13 -0
  239. package/src/experimental/features/index.ts +1 -0
  240. package/src/experimental/tools/VideoThumbnailLoader/load_and_push_segment.ts +10 -7
  241. package/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts +7 -4
  242. package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +25 -10
  243. package/src/experimental/tools/mediaCapabilitiesProber/index.ts +0 -4
  244. package/src/features/__tests__/initialize_features.test.ts +11 -0
  245. package/src/features/features_object.ts +1 -0
  246. package/src/features/initialize_features.ts +15 -10
  247. package/src/features/types.ts +9 -0
  248. package/src/manifest/__tests__/manifest.test.ts +7 -7
  249. package/src/manifest/__tests__/period.test.ts +90 -45
  250. package/src/manifest/adaptation.ts +96 -1
  251. package/src/manifest/manifest.ts +4 -0
  252. package/src/manifest/period.ts +4 -2
  253. package/src/manifest/representation.ts +77 -5
  254. package/src/manifest/utils.ts +1 -3
  255. package/src/parsers/manifest/dash/common/parse_adaptation_sets.ts +116 -151
  256. package/src/parsers/manifest/dash/common/parse_representations.ts +21 -4
  257. package/src/parsers/manifest/dash/js-parser/parse_from_document.ts +1 -1
  258. package/src/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.ts +1 -0
  259. package/src/parsers/texttracks/ttml/parse_ttml.ts +1 -1
  260. package/src/public_types.ts +16 -1
  261. package/src/tools/TextTrackRenderer/text_track_renderer.ts +1 -1
  262. package/src/transports/dash/add_segment_integrity_checks_to_loader.ts +31 -22
  263. package/src/transports/dash/low_latency_segment_loader.ts +2 -2
  264. package/src/transports/dash/manifest_parser.ts +1 -1
  265. package/src/transports/dash/segment_loader.ts +4 -4
  266. package/src/transports/local/segment_loader.ts +14 -30
  267. package/src/transports/smooth/isobmff/create_boxes.ts +4 -6
  268. package/src/transports/smooth/segment_loader.ts +4 -4
  269. package/src/transports/utils/call_custom_manifest_loader.ts +3 -3
  270. package/src/typings/globals.d.ts +21 -19
  271. package/src/utils/cancellable_sleep.ts +5 -14
  272. package/src/utils/create_cancellable_promise.ts +69 -0
  273. package/src/utils/is_null_or_undefined.ts +1 -1
  274. package/src/utils/reference.ts +6 -0
  275. package/src/utils/request/xhr.ts +1 -1
  276. package/src/utils/task_canceller.ts +63 -34
  277. package/tsconfig.json +1 -1
  278. package/tsconfig.modules.json +1 -1
  279. package/dist/_esm5.processed/core/init/utils/media_duration_updater.d.ts +0 -56
  280. package/locked_reps.js +0 -46
  281. package/scripts/doc-generator/construct_table_of_contents.js +0 -76
  282. package/scripts/doc-generator/convert_MD_to_HMTL.js +0 -26
  283. package/scripts/doc-generator/create_documentation.js +0 -331
  284. package/scripts/doc-generator/create_documentation_page.js +0 -209
  285. package/scripts/doc-generator/create_page.js +0 -210
  286. package/scripts/doc-generator/generate_header_html.js +0 -147
  287. package/scripts/doc-generator/generate_page_html.js +0 -115
  288. package/scripts/doc-generator/generate_page_list_html.js +0 -92
  289. package/scripts/doc-generator/generate_sidebar_html.js +0 -85
  290. package/scripts/doc-generator/get_search_data_for_content.js +0 -137
  291. package/scripts/doc-generator/index.js +0 -34
  292. package/scripts/doc-generator/parse_doc_configs.js +0 -327
  293. package/scripts/doc-generator/scripts/lunr.js +0 -10
  294. package/scripts/doc-generator/scripts/script.js +0 -451
  295. package/scripts/doc-generator/styles/code.css +0 -99
  296. package/scripts/doc-generator/styles/style.css +0 -835
  297. package/scripts/doc-generator/utils.js +0 -74
@@ -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 ?
@@ -156,7 +156,9 @@ function buildKeySystemConfigurations(
156
156
  if (!isNullOrUndefined(keySystem.distinctiveIdentifier)) {
157
157
  distinctiveIdentifier = keySystem.distinctiveIdentifier;
158
158
  }
159
- const { EME_DEFAULT_WIDEVINE_ROBUSTNESSES,
159
+ const { EME_DEFAULT_AUDIO_CODECS,
160
+ EME_DEFAULT_VIDEO_CODECS,
161
+ EME_DEFAULT_WIDEVINE_ROBUSTNESSES,
160
162
  EME_DEFAULT_PLAYREADY_RECOMMENDATION_ROBUSTNESSES } = config.getCurrent();
161
163
 
162
164
  // From the W3 EME spec, we have to provide videoCapabilities and
@@ -195,7 +197,7 @@ function buildKeySystemConfigurations(
195
197
 
196
198
  const audioCodecs = audioCapabilitiesConfig?.type === "contentType" ?
197
199
  audioCapabilitiesConfig.value :
198
- ["audio/mp4;codecs=\"mp4a.40.2\"", "audio/webm;codecs=opus"];
200
+ EME_DEFAULT_AUDIO_CODECS;
199
201
 
200
202
  audioCapabilities = flatMap(audioRobustnesses, (robustness) =>
201
203
  audioCodecs.map(contentType => {
@@ -223,9 +225,7 @@ function buildKeySystemConfigurations(
223
225
 
224
226
  const videoCodecs = videoCapabilitiesConfig?.type === "contentType" ?
225
227
  videoCapabilitiesConfig.value :
226
- ["video/mp4;codecs=\"avc1.4d401e\"",
227
- "video/mp4;codecs=\"avc1.42e01e\"",
228
- "video/webm;codecs=\"vp8\""];
228
+ EME_DEFAULT_VIDEO_CODECS;
229
229
 
230
230
  videoCapabilities = flatMap(videoRobustnesses, (robustness) =>
231
231
  videoCodecs.map(contentType => {
@@ -234,12 +234,26 @@ function buildKeySystemConfigurations(
234
234
  }));
235
235
  }
236
236
 
237
- return [{ initDataTypes: ["cenc"],
238
- videoCapabilities,
239
- audioCapabilities,
240
- distinctiveIdentifier,
241
- persistentState,
242
- sessionTypes }];
237
+ const wantedMediaKeySystemConfiguration : MediaKeySystemConfiguration = {
238
+ initDataTypes: ["cenc"],
239
+ videoCapabilities,
240
+ audioCapabilities,
241
+ distinctiveIdentifier,
242
+ persistentState,
243
+ sessionTypes,
244
+ };
245
+
246
+ return [
247
+ wantedMediaKeySystemConfiguration,
248
+
249
+ // Some legacy implementations have issues with `audioCapabilities` and
250
+ // `videoCapabilities`, so we're including a supplementary
251
+ // `MediaKeySystemConfiguration` without those properties.
252
+ { ...wantedMediaKeySystemConfiguration,
253
+ audioCapabilities: undefined ,
254
+ videoCapabilities: undefined,
255
+ } as unknown as MediaKeySystemConfiguration,
256
+ ];
243
257
  }
244
258
 
245
259
  /**
@@ -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,10 +80,10 @@ export default function SessionEventsListener(
79
80
 
80
81
  onKeyStatusesChange(session, () => {
81
82
  try {
82
- handleKeyStatusesChangeEvent();
83
+ checkAndHandleCurrentKeyStatuses();
83
84
  } catch (error) {
84
- if (cancelSignal.isCancelled ||
85
- (manualCanceller.isUsed && error instanceof CancellationSignal))
85
+ if (cancelSignal.isCancelled() ||
86
+ (manualCanceller.isUsed() && error instanceof CancellationSignal))
86
87
  {
87
88
  return;
88
89
  }
@@ -106,17 +107,22 @@ export default function SessionEventsListener(
106
107
  backoffOptions,
107
108
  manualCanceller.signal)
108
109
  .then((licenseObject) => {
109
- if (manualCanceller.isUsed) {
110
+ if (manualCanceller.isUsed()) {
110
111
  return Promise.resolve();
111
112
  }
112
113
  if (isNullOrUndefined(licenseObject)) {
113
114
  log.info("DRM: No license given, skipping session.update");
114
115
  } else {
115
- return updateSessionWithMessage(session, licenseObject);
116
+ try {
117
+ return updateSessionWithMessage(session, licenseObject);
118
+ } catch (err) {
119
+ manualCanceller.cancel();
120
+ callbacks.onError(err);
121
+ }
116
122
  }
117
123
  })
118
124
  .catch((err : unknown) => {
119
- if (manualCanceller.isUsed) {
125
+ if (manualCanceller.isUsed()) {
120
126
  return;
121
127
  }
122
128
  manualCanceller.cancel();
@@ -135,23 +141,25 @@ export default function SessionEventsListener(
135
141
  });
136
142
  }, manualCanceller.signal);
137
143
 
144
+ checkAndHandleCurrentKeyStatuses();
145
+ return;
138
146
  /**
139
147
  * Check current MediaKeyStatus for each key in the given MediaKeySession and:
140
148
  * - throw if at least one status is a non-recoverable error
141
149
  * - call warning callback for recoverable errors
142
150
  * - call onKeyUpdate callback when the MediaKeyStatus of any key is updated
143
151
  */
144
- function handleKeyStatusesChangeEvent() : void {
152
+ function checkAndHandleCurrentKeyStatuses() : void {
145
153
  log.info("DRM: keystatuseschange event received", session.sessionId);
146
154
 
147
- if (manualCanceller.isUsed || session.keyStatuses.size === 0) {
155
+ if (manualCanceller.isUsed() || session.keyStatuses.size === 0) {
148
156
  return ;
149
157
  }
150
158
  const { warning, blacklistedKeyIds, whitelistedKeyIds } =
151
159
  checkKeyStatuses(session, keySystemOptions, keySystem);
152
160
  if (warning !== undefined) {
153
161
  callbacks.onWarning(warning);
154
- if (manualCanceller.isUsed) {
162
+ if (manualCanceller.isUsed()) {
155
163
  return;
156
164
  }
157
165
  }
@@ -162,40 +170,38 @@ export default function SessionEventsListener(
162
170
  message : Uint8Array,
163
171
  messageType : MediaKeyMessageType
164
172
  ) : Promise<BufferSource | null> {
165
- return new Promise((res, rej) => {
166
- log.debug("DRM: Calling `getLicense`", messageType);
167
- const getLicense = keySystemOptions.getLicense(message, messageType);
168
- const getLicenseTimeout = isNullOrUndefined(getLicenseConfig.timeout) ?
169
- 10 * 1000 :
170
- getLicenseConfig.timeout;
171
-
172
- let timeoutId : number | undefined;
173
- if (getLicenseTimeout >= 0) {
174
- timeoutId = setTimeout(() => {
175
- rej(new GetLicenseTimeoutError(
176
- `"getLicense" timeout exceeded (${getLicenseTimeout} ms)`
177
- ));
178
- }, getLicenseTimeout) as unknown as number;
179
- }
180
-
173
+ let timeoutId : number | undefined;
174
+ return new Promise<BufferSource | null>((res, rej) => {
181
175
  try {
182
- Promise.resolve(getLicense).then(
183
- (val) => {
184
- clearTimeoutIfOne();
185
- res(val);
186
- },
187
- (err) => {
188
- clearTimeoutIfOne();
189
- rej(err);
190
- });
176
+ log.debug("DRM: Calling `getLicense`", messageType);
177
+ const getLicense = keySystemOptions.getLicense(message, messageType);
178
+ const getLicenseTimeout = isNullOrUndefined(getLicenseConfig.timeout) ?
179
+ 10 * 1000 :
180
+ getLicenseConfig.timeout;
181
+
182
+ if (getLicenseTimeout >= 0) {
183
+ timeoutId = setTimeout(() => {
184
+ rej(new GetLicenseTimeoutError(
185
+ `"getLicense" timeout exceeded (${getLicenseTimeout} ms)`
186
+ ));
187
+ }, getLicenseTimeout) as unknown as number;
188
+ }
189
+ Promise.resolve(getLicense)
190
+ .then(clearTimeoutAndResolve, clearTimeoutAndReject);
191
191
  } catch (err) {
192
- clearTimeoutIfOne();
193
- rej(err);
192
+ clearTimeoutAndReject(err);
193
+ }
194
+ function clearTimeoutAndResolve(data : BufferSource | null) {
195
+ if (timeoutId !== undefined) {
196
+ clearTimeout(timeoutId);
197
+ }
198
+ res(data);
194
199
  }
195
- function clearTimeoutIfOne() {
200
+ function clearTimeoutAndReject(err : unknown) {
196
201
  if (timeoutId !== undefined) {
197
202
  clearTimeout(timeoutId);
198
203
  }
204
+ rej(err);
199
205
  }
200
206
  });
201
207
  }
@@ -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,
@@ -111,6 +112,11 @@ export default function checkKeyStatuses(
111
112
  new Uint8Array(keyStatusKeyId));
112
113
 
113
114
  const keyStatusObj = { keyId: keyId.buffer, keyStatus };
115
+
116
+ if (log.hasLevel("DEBUG")) {
117
+ log.debug(`DRM: key status update (${bytesToHex(keyId)}): ${keyStatus}`);
118
+ }
119
+
114
120
  switch (keyStatus) {
115
121
  case KEY_STATUSES.EXPIRED: {
116
122
  const error = new EncryptedMediaError(
@@ -14,6 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
+ import log from "../../../log";
17
18
  import LoadedSessionsStore from "./loaded_sessions_store";
18
19
 
19
20
  /**
@@ -32,7 +33,7 @@ export default async function cleanOldLoadedSessions(
32
33
  if (limit < 0 || limit >= loadedSessionsStore.getLength()) {
33
34
  return ;
34
35
  }
35
-
36
+ log.info("DRM: LSS cache limit exceeded", limit, loadedSessionsStore.getLength());
36
37
  const proms : Array<Promise<unknown>> = [];
37
38
  const entries = loadedSessionsStore.getAll().slice(); // clone
38
39
  const toDelete = entries.length - limit;
@@ -63,6 +63,7 @@ export default class LoadedSessionsStore {
63
63
  sessionType : MediaKeySessionType
64
64
  ) : IStoredSessionEntry {
65
65
  const keySessionRecord = new KeySessionRecord(initData);
66
+ log.debug("DRM-LSS: calling `createSession`", sessionType);
66
67
  const mediaKeySession = this._mediaKeys.createSession(sessionType);
67
68
  const entry = { mediaKeySession,
68
69
  sessionType,
@@ -73,6 +74,8 @@ export default class LoadedSessionsStore {
73
74
  if (!isNullOrUndefined(mediaKeySession.closed)) {
74
75
  mediaKeySession.closed
75
76
  .then(() => {
77
+ log.info("DRM-LSS: session was closed, removing it.",
78
+ mediaKeySession.sessionId);
76
79
  const index = this.getIndex(keySessionRecord);
77
80
  if (index >= 0 &&
78
81
  this._storage[index].mediaKeySession === mediaKeySession)
@@ -86,8 +89,8 @@ export default class LoadedSessionsStore {
86
89
  });
87
90
  }
88
91
 
89
- log.debug("DRM-LSS: Add MediaKeySession", entry.sessionType);
90
92
  this._storage.push({ ...entry });
93
+ log.debug("DRM-LSS: MediaKeySession added", entry.sessionType, this._storage.length);
91
94
  return entry;
92
95
  }
93
96
 
@@ -111,6 +114,8 @@ export default class LoadedSessionsStore {
111
114
  if (stored.keySessionRecord.isCompatibleWith(initializationData)) {
112
115
  this._storage.splice(i, 1);
113
116
  this._storage.push(stored);
117
+ log.debug("DRM-LSS: Reusing session:",
118
+ stored.mediaKeySession.sessionId, stored.sessionType);
114
119
  return { ...stored };
115
120
  }
116
121
  }
@@ -332,6 +337,8 @@ export default class LoadedSessionsStore {
332
337
  for (let i = this._storage.length - 1; i >= 0; i--) {
333
338
  const stored = this._storage[i];
334
339
  if (stored.mediaKeySession === mediaKeySession) {
340
+ log.debug("DRM-LSS: Removing session without closing it",
341
+ mediaKeySession.sessionId);
335
342
  this._storage.splice(i, 1);
336
343
  return true;
337
344
  }
@@ -16,19 +16,22 @@
16
16
 
17
17
  import config from "../../config";
18
18
  import { ICdnMetadata } from "../../parsers/manifest";
19
- import { IPlayerError } from "../../public_types";
20
19
  import arrayFindIndex from "../../utils/array_find_index";
21
20
  import EventEmitter from "../../utils/event_emitter";
22
21
  import { CancellationSignal } from "../../utils/task_canceller";
23
22
 
24
23
  /**
25
- * Class signaling the priority between multiple CDN available for any given
26
- * resource.
24
+ * Class storing and signaling the priority between multiple CDN available for
25
+ * any given resource.
27
26
  *
28
- * This class might perform requests and schedule timeouts by itself to keep its
29
- * internal list of CDN priority up-to-date.
30
- * When it is not needed anymore, you should call the `dispose` method to clear
31
- * all resources.
27
+ * This class was first created to implement the complexities behind
28
+ * Content Steering features, though its handling hasn't been added yet as we
29
+ * wait for its specification to be both standardized and relied on in the wild.
30
+ * In the meantime, it acts as an abstraction for the simple concept of
31
+ * avoiding to request a CDN for any segment when an issue is encountered with
32
+ * one (e.g. HTTP 500 statuses) and several CDN exist for a given resource. It
33
+ * should be noted that this is also one of the planified features of the
34
+ * Content Steering specification.
32
35
  *
33
36
  * @class CdnPrioritizer
34
37
  */
@@ -41,7 +44,7 @@ export default class CdnPrioritizer extends EventEmitter<ICdnPrioritizerEvents>
41
44
  private _downgradedCdnList : {
42
45
  /**
43
46
  * Metadata of downgraded CDN, sorted by the time at which they have
44
- * been downgraded.
47
+ * been downgraded ascending.
45
48
  */
46
49
  metadata : ICdnMetadata[];
47
50
  /**
@@ -174,8 +177,14 @@ export default class CdnPrioritizer extends EventEmitter<ICdnPrioritizerEvents>
174
177
  }
175
178
  }
176
179
 
180
+ /** Events sent by a `CdnPrioritizer` */
177
181
  export interface ICdnPrioritizerEvents {
178
- warnings : IPlayerError[];
182
+ /**
183
+ * The priority of one or several CDN changed.
184
+ *
185
+ * You might want to re-check if a CDN should still be used when this event
186
+ * is triggered.
187
+ */
179
188
  priorityChange : null;
180
189
  }
181
190
 
@@ -154,7 +154,7 @@ export default class ManifestFetcher extends EventEmitter<IManifestFetcherEvent>
154
154
  manifestProm
155
155
  .then((val : IManifestFetcherParsedResult) => {
156
156
  this.trigger("manifestReady", val.manifest);
157
- if (!this._canceller.isUsed) {
157
+ if (!this._canceller.isUsed()) {
158
158
  this._recursivelyRefreshManifest(val.manifest, val);
159
159
  }
160
160
  })
@@ -340,7 +340,7 @@ export default class ManifestFetcher extends EventEmitter<IManifestFetcherEvent>
340
340
  */
341
341
  function onWarnings(warnings : Error[]) : void {
342
342
  for (const warning of warnings) {
343
- if (cancelSignal.isCancelled) {
343
+ if (cancelSignal.isCancelled()) {
344
344
  return;
345
345
  }
346
346
  const formattedError = formatError(warning, {
@@ -444,7 +444,8 @@ export default class ManifestFetcher extends EventEmitter<IManifestFetcherEvent>
444
444
  * be effectively considered.
445
445
  * `nextRefreshCanceller` will allow to cancel every other when one is triggered.
446
446
  */
447
- const nextRefreshCanceller = new TaskCanceller({ cancelOn: this._canceller.signal });
447
+ const nextRefreshCanceller = new TaskCanceller();
448
+ nextRefreshCanceller.linkToSignal(this._canceller.signal);
448
449
 
449
450
  /* Function to manually schedule a Manifest refresh */
450
451
  this.scheduleManualRefresh = (settings : IManifestRefreshSettings) => {
@@ -643,7 +644,7 @@ export default class ManifestFetcher extends EventEmitter<IManifestFetcherEvent>
643
644
  }
644
645
 
645
646
  private _onFatalError(err : unknown) : void {
646
- if (this._canceller.isUsed) {
647
+ if (this._canceller.isUsed()) {
647
648
  return;
648
649
  }
649
650
  this.trigger("error", err);
@@ -64,10 +64,22 @@ const generateRequestID = idGenerator();
64
64
  * An `ISegmentFetcher` also implements a retry mechanism, based on the given
65
65
  * `options` argument, which may retry a segment request when it fails.
66
66
  *
67
- * @param {string} bufferType
68
- * @param {Object} pipeline
69
- * @param {Object} lifecycleCallbacks
70
- * @param {Object} options
67
+ * @param {string} bufferType - Type of buffer concerned (e.g. `"audio"`,
68
+ * `"video"`, `"text" etc.)
69
+ * @param {Object} pipeline - The transport-specific logic allowing to load
70
+ * segments of the given buffer type and transport protocol (e.g. DASH).
71
+ * @param {Object|null} cdnPrioritizer - Abstraction allowing to synchronize,
72
+ * update and keep track of the priorization of the CDN to use to load any given
73
+ * segment, in cases where multiple ones are available.
74
+ *
75
+ * Can be set to `null` in which case a minimal priorization logic will be used
76
+ * instead.
77
+ * @param {Object} lifecycleCallbacks - Callbacks that can be registered to be
78
+ * informed when new requests are made, ended, new metrics are available etc.
79
+ * This should be mainly useful to implement an adaptive logic relying on those
80
+ * metrics and events.
81
+ * @param {Object} options - Various tweaking options allowing to configure the
82
+ * behavior of the returned `ISegmentFetcher`.
71
83
  * @returns {Function}
72
84
  */
73
85
  export default function createSegmentFetcher<TLoadedFormat, TSegmentDataType>(
@@ -197,14 +209,7 @@ export default function createSegmentFetcher<TLoadedFormat, TSegmentDataType>(
197
209
  id: requestId,
198
210
  content });
199
211
 
200
- cancellationSignal.register(() => {
201
- if (requestInfo !== undefined) {
202
- return; // Request already terminated
203
- }
204
- log.debug("SF: Segment request cancelled", segmentIdString);
205
- requestInfo = null;
206
- lifecycleCallbacks.onRequestEnd?.({ id: requestId });
207
- });
212
+ cancellationSignal.register(onCancellation);
208
213
 
209
214
  try {
210
215
  const res = await scheduleRequestWithCdns(content.representation.cdnMetadata,
@@ -233,22 +238,34 @@ export default function createSegmentFetcher<TLoadedFormat, TSegmentDataType>(
233
238
  requestInfo = null;
234
239
  }
235
240
 
236
- if (!cancellationSignal.isCancelled) {
241
+ if (!cancellationSignal.isCancelled()) {
237
242
  // The current task could have been canceled as a result of one
238
243
  // of the previous callbacks call. In that case, we don't want to send
239
244
  // a "requestEnd" again as it has already been sent on cancellation.
240
245
  lifecycleCallbacks.onRequestEnd?.({ id: requestId });
241
246
  }
247
+ cancellationSignal.deregister(onCancellation);
242
248
  } catch (err) {
249
+ cancellationSignal.deregister(onCancellation);
243
250
  requestInfo = null;
244
251
  if (err instanceof CancellationError) {
245
252
  log.debug("SF: Segment request aborted", segmentIdString);
246
253
  throw err;
247
254
  }
248
255
  log.debug("SF: Segment request failed", segmentIdString);
256
+ lifecycleCallbacks.onRequestEnd?.({ id: requestId });
249
257
  throw errorSelector(err);
250
258
  }
251
259
 
260
+ function onCancellation() {
261
+ if (requestInfo !== undefined) {
262
+ return; // Request already terminated
263
+ }
264
+ log.debug("SF: Segment request cancelled", segmentIdString);
265
+ requestInfo = null;
266
+ lifecycleCallbacks.onRequestEnd?.({ id: requestId });
267
+ }
268
+
252
269
  /**
253
270
  * Call a segment loader for the given URL with the right arguments.
254
271
  * @param {Object|null} cdnMetadata
@@ -373,11 +390,16 @@ export interface ISegmentFetcherCallbacks<TSegmentDataType> {
373
390
  /**
374
391
  * Callback called when all decodable chunks of the loaded segment have been
375
392
  * communicated through the `onChunk` callback.
393
+ *
394
+ * This callback is called before the corresponding `ISegmentFetcher`'s
395
+ * returned Promise is resolved.
376
396
  */
377
397
  onAllChunksReceived() : void;
378
398
 
379
399
  /**
380
- * Callback called when the segment request has to restart from scratch. */
400
+ * Callback called when the segment request has to restart from scratch, e.g.
401
+ * due to a request error.
402
+ */
381
403
  onRetry(error : IPlayerError) : void;
382
404
  }
383
405