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
@@ -26,7 +26,8 @@ import TaskCanceller from "../../../utils/task_canceller";
26
26
  * @returns {Object}
27
27
  */
28
28
  export default function getLoadedReference(playbackObserver, mediaElement, isDirectfile, cancelSignal) {
29
- var listenCanceller = new TaskCanceller({ cancelOn: cancelSignal });
29
+ var listenCanceller = new TaskCanceller();
30
+ listenCanceller.linkToSignal(cancelSignal);
30
31
  var isLoaded = createSharedReference(false, listenCanceller.signal);
31
32
  playbackObserver.listen(function (observation) {
32
33
  if (observation.rebuffering !== null ||
@@ -42,7 +42,7 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
42
42
  if (mediaElement.readyState >= READY_STATES.HAVE_METADATA) {
43
43
  onLoadedMetadata();
44
44
  }
45
- cancelSignal.register(function (err) {
45
+ var deregisterCancellation = cancelSignal.register(function (err) {
46
46
  mediaElement.removeEventListener("loadedmetadata", onLoadedMetadata);
47
47
  rejectAutoPlay(err);
48
48
  });
@@ -60,7 +60,7 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
60
60
  "falsely announced having loaded the content.");
61
61
  onWarning(error);
62
62
  }
63
- if (cancelSignal.isCancelled) {
63
+ if (cancelSignal.isCancelled()) {
64
64
  return;
65
65
  }
66
66
  playbackObserver.listen(function (observation, stopListening) {
@@ -82,6 +82,7 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
82
82
  }
83
83
  initialPlayPerformed.setValue(true);
84
84
  initialPlayPerformed.finish();
85
+ deregisterCancellation();
85
86
  return resolveAutoPlay({ type: "skipped" });
86
87
  }
87
88
  var playResult;
@@ -89,19 +90,22 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
89
90
  playResult = (_a = mediaElement.play()) !== null && _a !== void 0 ? _a : Promise.resolve();
90
91
  }
91
92
  catch (playError) {
93
+ deregisterCancellation();
92
94
  return rejectAutoPlay(playError);
93
95
  }
94
96
  playResult
95
97
  .then(function () {
96
- if (cancelSignal.isCancelled) {
98
+ if (cancelSignal.isCancelled()) {
97
99
  return;
98
100
  }
99
101
  initialPlayPerformed.setValue(true);
100
102
  initialPlayPerformed.finish();
103
+ deregisterCancellation();
101
104
  return resolveAutoPlay({ type: "autoplay" });
102
105
  })
103
106
  .catch(function (playError) {
104
- if (cancelSignal.isCancelled) {
107
+ deregisterCancellation();
108
+ if (cancelSignal.isCancelled()) {
105
109
  return;
106
110
  }
107
111
  if (playError instanceof Error && playError.name === "NotAllowedError") {
@@ -111,7 +115,7 @@ export default function performInitialSeekAndPlay(mediaElement, playbackObserver
111
115
  var error = new MediaError("MEDIA_ERR_BLOCKED_AUTOPLAY", "Cannot trigger auto-play automatically: " +
112
116
  "your browser does not allow it.");
113
117
  onWarning(error);
114
- if (cancelSignal.isCancelled) {
118
+ if (cancelSignal.isCancelled()) {
115
119
  return;
116
120
  }
117
121
  return resolveAutoPlay({ type: "autoplay-blocked" });
@@ -62,7 +62,8 @@ export default function initializeContentDecryption(mediaElement, keySystems, pr
62
62
  ref.finish(); // We know that no new value will be triggered
63
63
  return ref;
64
64
  }
65
- var decryptorCanceller = new TaskCanceller({ cancelOn: cancelSignal });
65
+ var decryptorCanceller = new TaskCanceller();
66
+ decryptorCanceller.linkToSignal(cancelSignal);
66
67
  var drmStatusRef = createSharedReference({
67
68
  initializationState: { type: "uninitialized", value: null },
68
69
  drmSystemId: undefined,
@@ -0,0 +1,58 @@
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
+ * Keep the MediaSource's `duration` attribute up-to-date with the duration of
18
+ * the content played on it.
19
+ * @class MediaSourceDurationUpdater
20
+ */
21
+ export default class MediaSourceDurationUpdater {
22
+ /**
23
+ * `MediaSource` on which we're going to update the `duration` attribute.
24
+ */
25
+ private _mediaSource;
26
+ /**
27
+ * Abort the current duration-setting logic.
28
+ * `null` if no such logic is pending.
29
+ */
30
+ private _currentMediaSourceDurationUpdateCanceller;
31
+ /**
32
+ * Create a new `MediaSourceDurationUpdater`,
33
+ * @param {MediaSource} mediaSource - The MediaSource on which the content is
34
+ * played.
35
+ */
36
+ constructor(mediaSource: MediaSource);
37
+ /**
38
+ * Indicate to the `MediaSourceDurationUpdater` the currently known duration
39
+ * of the content.
40
+ *
41
+ * The `MediaSourceDurationUpdater` will then use that value to determine
42
+ * which `duration` attribute should be set on the `MediaSource` associated
43
+ *
44
+ * @param {number} newDuration
45
+ * @param {boolean} isRealEndKnown - If set to `false`, the current content is
46
+ * a dynamic content (it might evolve in the future) and the `newDuration`
47
+ * communicated might be greater still. In effect the
48
+ * `MediaSourceDurationUpdater` will actually set a much higher value to the
49
+ * `MediaSource`'s duration to prevent being annoyed by the HTML-related
50
+ * side-effects of having a too low duration (such as the impossibility to
51
+ * seek over that value).
52
+ */
53
+ updateDuration(newDuration: number, isRealEndKnown: boolean): void;
54
+ /**
55
+ * Abort the last duration-setting operation and free its resources.
56
+ */
57
+ stopUpdating(): void;
58
+ }
@@ -14,94 +14,91 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { onSourceOpen, onSourceEnded, onSourceClose, } from "../../../compat/event_listeners";
17
+ /* eslint-disable-next-line max-len */
18
+ import hasIssuesWithHighMediaSourceDuration from "../../../compat/has_issues_with_high_media_source_duration";
17
19
  import log from "../../../log";
18
20
  import createSharedReference from "../../../utils/reference";
19
21
  import TaskCanceller from "../../../utils/task_canceller";
20
22
  /** Number of seconds in a regular year. */
21
23
  var YEAR_IN_SECONDS = 365 * 24 * 3600;
22
24
  /**
23
- * Keep the MediaSource's duration up-to-date with what is being played.
24
- * @class MediaDurationUpdater
25
+ * Keep the MediaSource's `duration` attribute up-to-date with the duration of
26
+ * the content played on it.
27
+ * @class MediaSourceDurationUpdater
25
28
  */
26
- var MediaDurationUpdater = /** @class */ (function () {
29
+ var MediaSourceDurationUpdater = /** @class */ (function () {
27
30
  /**
28
- * Create a new `MediaDurationUpdater` that will keep the given MediaSource's
29
- * duration as soon as possible.
30
- * This duration will be updated until the `stop` method is called.
31
- * @param {Object} manifest - The Manifest currently played.
32
- * For another content, you will have to create another `MediaDurationUpdater`.
31
+ * Create a new `MediaSourceDurationUpdater`,
33
32
  * @param {MediaSource} mediaSource - The MediaSource on which the content is
34
- * pushed.
33
+ * played.
35
34
  */
36
- function MediaDurationUpdater(manifest, mediaSource) {
37
- var canceller = new TaskCanceller();
38
- var currentKnownDuration = createSharedReference(undefined, canceller.signal);
39
- this._canceller = canceller;
40
- this._currentKnownDuration = currentKnownDuration;
41
- var isMediaSourceOpened = createMediaSourceOpenReference(mediaSource, this._canceller.signal);
42
- /** TaskCanceller triggered each time the MediaSource open status changes. */
43
- var msUpdateCanceller = new TaskCanceller({ cancelOn: this._canceller.signal });
35
+ function MediaSourceDurationUpdater(mediaSource) {
36
+ this._mediaSource = mediaSource;
37
+ this._currentMediaSourceDurationUpdateCanceller = null;
38
+ }
39
+ /**
40
+ * Indicate to the `MediaSourceDurationUpdater` the currently known duration
41
+ * of the content.
42
+ *
43
+ * The `MediaSourceDurationUpdater` will then use that value to determine
44
+ * which `duration` attribute should be set on the `MediaSource` associated
45
+ *
46
+ * @param {number} newDuration
47
+ * @param {boolean} isRealEndKnown - If set to `false`, the current content is
48
+ * a dynamic content (it might evolve in the future) and the `newDuration`
49
+ * communicated might be greater still. In effect the
50
+ * `MediaSourceDurationUpdater` will actually set a much higher value to the
51
+ * `MediaSource`'s duration to prevent being annoyed by the HTML-related
52
+ * side-effects of having a too low duration (such as the impossibility to
53
+ * seek over that value).
54
+ */
55
+ MediaSourceDurationUpdater.prototype.updateDuration = function (newDuration, isRealEndKnown) {
56
+ if (this._currentMediaSourceDurationUpdateCanceller !== null) {
57
+ this._currentMediaSourceDurationUpdateCanceller.cancel();
58
+ }
59
+ this._currentMediaSourceDurationUpdateCanceller = new TaskCanceller();
60
+ var mediaSource = this._mediaSource;
61
+ var currentSignal = this._currentMediaSourceDurationUpdateCanceller.signal;
62
+ var isMediaSourceOpened = createMediaSourceOpenReference(mediaSource, currentSignal);
63
+ /** TaskCanceller triggered each time the MediaSource switches to and from "open". */
64
+ var msOpenStatusCanceller = new TaskCanceller();
65
+ msOpenStatusCanceller.linkToSignal(currentSignal);
44
66
  isMediaSourceOpened.onUpdate(onMediaSourceOpenedStatusChanged, { emitCurrentValue: true,
45
- clearSignal: this._canceller.signal });
67
+ clearSignal: currentSignal });
46
68
  function onMediaSourceOpenedStatusChanged() {
47
- msUpdateCanceller.cancel();
69
+ msOpenStatusCanceller.cancel();
48
70
  if (!isMediaSourceOpened.getValue()) {
49
71
  return;
50
72
  }
51
- msUpdateCanceller = new TaskCanceller({ cancelOn: canceller.signal });
52
- /** TaskCanceller triggered each time the content's duration may have change */
53
- var durationChangeCanceller = new TaskCanceller({
54
- cancelOn: msUpdateCanceller.signal,
55
- });
56
- var reSetDuration = function () {
57
- durationChangeCanceller.cancel();
58
- durationChangeCanceller = new TaskCanceller({
59
- cancelOn: msUpdateCanceller.signal,
60
- });
61
- onDurationMayHaveChanged(durationChangeCanceller.signal);
62
- };
63
- currentKnownDuration.onUpdate(reSetDuration, { emitCurrentValue: false,
64
- clearSignal: msUpdateCanceller.signal });
65
- manifest.addEventListener("manifestUpdate", reSetDuration, msUpdateCanceller.signal);
66
- onDurationMayHaveChanged(durationChangeCanceller.signal);
67
- }
68
- function onDurationMayHaveChanged(cancelSignal) {
69
- var areSourceBuffersUpdating = createSourceBuffersUpdatingReference(mediaSource.sourceBuffers, cancelSignal);
73
+ msOpenStatusCanceller = new TaskCanceller();
74
+ msOpenStatusCanceller.linkToSignal(currentSignal);
75
+ var areSourceBuffersUpdating = createSourceBuffersUpdatingReference(mediaSource.sourceBuffers, msOpenStatusCanceller.signal);
70
76
  /** TaskCanceller triggered each time SourceBuffers' updating status changes */
71
- var sourceBuffersUpdatingCanceller = new TaskCanceller({ cancelOn: cancelSignal });
77
+ var sourceBuffersUpdatingCanceller = new TaskCanceller();
78
+ sourceBuffersUpdatingCanceller.linkToSignal(msOpenStatusCanceller.signal);
72
79
  return areSourceBuffersUpdating.onUpdate(function (areUpdating) {
73
80
  sourceBuffersUpdatingCanceller.cancel();
74
- sourceBuffersUpdatingCanceller = new TaskCanceller({ cancelOn: cancelSignal });
81
+ sourceBuffersUpdatingCanceller = new TaskCanceller();
82
+ sourceBuffersUpdatingCanceller.linkToSignal(msOpenStatusCanceller.signal);
75
83
  if (areUpdating) {
76
84
  return;
77
85
  }
78
- recursivelyForceDurationUpdate(mediaSource, manifest, currentKnownDuration.getValue(), cancelSignal);
79
- }, { clearSignal: cancelSignal, emitCurrentValue: true });
86
+ recursivelyForceDurationUpdate(mediaSource, newDuration, isRealEndKnown, sourceBuffersUpdatingCanceller.signal);
87
+ }, { clearSignal: msOpenStatusCanceller.signal, emitCurrentValue: true });
80
88
  }
81
- }
82
- /**
83
- * By default, the `MediaDurationUpdater` only set a safe estimate for the
84
- * MediaSource's duration.
85
- * A more precize duration can be set by communicating to it a more precize
86
- * media duration through `updateKnownDuration`.
87
- * If the duration becomes unknown, `undefined` can be given to it so the
88
- * `MediaDurationUpdater` goes back to a safe estimate.
89
- * @param {number | undefined} newDuration
90
- */
91
- MediaDurationUpdater.prototype.updateKnownDuration = function (newDuration) {
92
- this._currentKnownDuration.setValueIfChanged(newDuration);
93
89
  };
94
90
  /**
95
- * Stop the `MediaDurationUpdater` from updating and free its resources.
96
- * Once stopped, it is not possible to start it again, beside creating another
97
- * `MediaDurationUpdater`.
91
+ * Abort the last duration-setting operation and free its resources.
98
92
  */
99
- MediaDurationUpdater.prototype.stop = function () {
100
- this._canceller.cancel();
93
+ MediaSourceDurationUpdater.prototype.stopUpdating = function () {
94
+ if (this._currentMediaSourceDurationUpdateCanceller !== null) {
95
+ this._currentMediaSourceDurationUpdateCanceller.cancel();
96
+ this._currentMediaSourceDurationUpdateCanceller = null;
97
+ }
101
98
  };
102
- return MediaDurationUpdater;
99
+ return MediaSourceDurationUpdater;
103
100
  }());
104
- export default MediaDurationUpdater;
101
+ export default MediaSourceDurationUpdater;
105
102
  /**
106
103
  * Checks that duration can be updated on the MediaSource, and then
107
104
  * sets it.
@@ -111,26 +108,16 @@ export default MediaDurationUpdater;
111
108
  * - `null` if it hasn'nt been updated
112
109
  *
113
110
  * @param {MediaSource} mediaSource
114
- * @param {Object} manifest
111
+ * @param {number} duration
112
+ * @param {boolean} isRealEndKnown
115
113
  * @returns {string}
116
114
  */
117
- function setMediaSourceDuration(mediaSource, manifest, knownDuration) {
118
- var _a;
119
- var newDuration = knownDuration;
120
- if (newDuration === undefined) {
121
- if (manifest.isDynamic) {
122
- var maxPotentialPos = (_a = manifest.getLivePosition()) !== null && _a !== void 0 ? _a : manifest.getMaximumSafePosition();
123
- // Some targets poorly support setting a very high number for durations.
124
- // Yet, in dynamic contents, we would prefer setting a value as high as possible
125
- // to still be able to seek anywhere we want to (even ahead of the Manifest if
126
- // we want to). As such, we put it at a safe default value of 2^32 excepted
127
- // when the maximum position is already relatively close to that value, where
128
- // we authorize exceptionally going over it.
129
- newDuration = Math.max(Math.pow(2, 32), maxPotentialPos + YEAR_IN_SECONDS);
130
- }
131
- else {
132
- newDuration = manifest.getMaximumSafePosition();
133
- }
115
+ function setMediaSourceDuration(mediaSource, duration, isRealEndKnown) {
116
+ var newDuration = duration;
117
+ if (!isRealEndKnown) {
118
+ newDuration = hasIssuesWithHighMediaSourceDuration() ?
119
+ Infinity :
120
+ getMaximumLiveSeekablePosition(duration);
134
121
  }
135
122
  var maxBufferedEnd = 0;
136
123
  for (var i = 0; i < mediaSource.sourceBuffers.length; i++) {
@@ -149,7 +136,7 @@ function setMediaSourceDuration(mediaSource, manifest, knownDuration) {
149
136
  if (maxBufferedEnd < mediaSource.duration) {
150
137
  try {
151
138
  log.info("Init: Updating duration to what is currently buffered", maxBufferedEnd);
152
- mediaSource.duration = newDuration;
139
+ mediaSource.duration = maxBufferedEnd;
153
140
  }
154
141
  catch (err) {
155
142
  log.warn("Duration Updater: Can't update duration on the MediaSource.", err instanceof Error ? err : "");
@@ -163,6 +150,9 @@ function setMediaSourceDuration(mediaSource, manifest, knownDuration) {
163
150
  try {
164
151
  log.info("Init: Updating duration", newDuration);
165
152
  mediaSource.duration = newDuration;
153
+ if (mediaSource.readyState === "open" && !isFinite(newDuration)) {
154
+ mediaSource.setLiveSeekableRange(0, getMaximumLiveSeekablePosition(duration));
155
+ }
166
156
  }
167
157
  catch (err) {
168
158
  log.warn("Duration Updater: Can't update duration on the MediaSource.", err instanceof Error ? err : "");
@@ -238,25 +228,36 @@ function createMediaSourceOpenReference(mediaSource, cancelSignal) {
238
228
  }
239
229
  /**
240
230
  * Immediately tries to set the MediaSource's duration to the most appropriate
241
- * one according to the Manifest and duration given.
231
+ * one.
242
232
  *
243
233
  * If it fails, wait 2 seconds and retries.
244
234
  *
245
235
  * @param {MediaSource} mediaSource
246
- * @param {Object} manifest
247
- * @param {number|undefined} duration
236
+ * @param {number} duration
237
+ * @param {boolean} isRealEndKnown
248
238
  * @param {Object} cancelSignal
249
239
  */
250
- function recursivelyForceDurationUpdate(mediaSource, manifest, duration, cancelSignal) {
251
- var res = setMediaSourceDuration(mediaSource, manifest, duration);
240
+ function recursivelyForceDurationUpdate(mediaSource, duration, isRealEndKnown, cancelSignal) {
241
+ var res = setMediaSourceDuration(mediaSource, duration, isRealEndKnown);
252
242
  if (res === "success" /* MediaSourceDurationUpdateStatus.Success */) {
253
243
  return;
254
244
  }
255
245
  var timeoutId = setTimeout(function () {
256
246
  unregisterClear();
257
- recursivelyForceDurationUpdate(mediaSource, manifest, duration, cancelSignal);
247
+ recursivelyForceDurationUpdate(mediaSource, duration, isRealEndKnown, cancelSignal);
258
248
  }, 2000);
259
249
  var unregisterClear = cancelSignal.register(function () {
260
250
  clearTimeout(timeoutId);
261
251
  });
262
252
  }
253
+ function getMaximumLiveSeekablePosition(contentLastPosition) {
254
+ // Some targets poorly support setting a very high number for seekable
255
+ // ranges.
256
+ // Yet, in contents whose end is not yet known (e.g. live contents), we
257
+ // would prefer setting a value as high as possible to still be able to
258
+ // seek anywhere we want to (even ahead of the Manifest if we want to).
259
+ // As such, we put it at a safe default value of 2^32 excepted when the
260
+ // maximum position is already relatively close to that value, where we
261
+ // authorize exceptionally going over it.
262
+ return Math.max(Math.pow(2, 32), contentLastPosition + YEAR_IN_SECONDS);
263
+ }
@@ -18,7 +18,7 @@ import { IPlayerError } from "../../../public_types";
18
18
  import EventEmitter from "../../../utils/event_emitter";
19
19
  import { IReadOnlySharedReference } from "../../../utils/reference";
20
20
  import { PlaybackObserver } from "../../api";
21
- import { IBufferType } from "../../segment_buffers";
21
+ import SegmentBuffersStore, { IBufferType } from "../../segment_buffers";
22
22
  import { IStallingSituation } from "../types";
23
23
  /**
24
24
  * Monitor playback, trying to avoid stalling situation.
@@ -32,6 +32,7 @@ export default class RebufferingController extends EventEmitter<IRebufferingCont
32
32
  /** Emit the current playback conditions */
33
33
  private _playbackObserver;
34
34
  private _manifest;
35
+ private _segmentBuffersStore;
35
36
  private _speed;
36
37
  private _isStarted;
37
38
  /**
@@ -40,12 +41,23 @@ export default class RebufferingController extends EventEmitter<IRebufferingCont
40
41
  */
41
42
  private _discontinuitiesStore;
42
43
  private _canceller;
44
+ /**
45
+ * If set to something else than `null`, this is the DOMHighResTimestamp as
46
+ * outputed by `performance.now()` when playback begin to seem to not start
47
+ * despite having decipherable data in the buffer(s).
48
+ *
49
+ * If enough time in that condition is spent, special considerations are
50
+ * taken at which point `_currentFreezeTimestamp` is reset to `null`.
51
+ *
52
+ * It is also reset to `null` when and if there is no such issue anymore.
53
+ */
54
+ private _currentFreezeTimestamp;
43
55
  /**
44
56
  * @param {object} playbackObserver - emit the current playback conditions.
45
57
  * @param {Object} manifest - The Manifest of the currently-played content.
46
58
  * @param {Object} speed - The last speed set by the user
47
59
  */
48
- constructor(playbackObserver: PlaybackObserver, manifest: Manifest | null, speed: IReadOnlySharedReference<number>);
60
+ constructor(playbackObserver: PlaybackObserver, manifest: Manifest | null, segmentBuffersStore: SegmentBuffersStore | null, speed: IReadOnlySharedReference<number>);
49
61
  start(): void;
50
62
  /**
51
63
  * Update information on an upcoming discontinuity for a given buffer type and
@@ -68,10 +80,32 @@ export default class RebufferingController extends EventEmitter<IRebufferingCont
68
80
  * forever.
69
81
  */
70
82
  destroy(): void;
83
+ /**
84
+ * Support of contents with DRM on all the platforms out there is a pain in
85
+ * the *ss considering all the DRM-related bugs there are.
86
+ *
87
+ * We found out a frequent issue which is to be unable to play despite having
88
+ * all the decryption keys to play what is currently buffered.
89
+ * When this happens, re-creating the buffers from scratch, with a reload, is
90
+ * usually sufficient to unlock the situation.
91
+ *
92
+ * Although we prefer providing more targeted fixes or telling to platform
93
+ * developpers to fix their implementation, it's not always possible.
94
+ * We thus resorted to developping an heuristic which detects such situation
95
+ * and reload in that case.
96
+ *
97
+ * @param {Object} observation - The last playback observation produced, it
98
+ * has to be recent (just triggered for example).
99
+ * @returns {boolean} - Returns `true` if it seems to be such kind of
100
+ * decipherability freeze, in which case this method already performed the
101
+ * right handling steps.
102
+ */
103
+ private _checkDecipherabilityFreeze;
71
104
  }
72
105
  export interface IRebufferingControllerEvent {
73
106
  stalled: IStallingSituation;
74
107
  unstalled: null;
108
+ needsReload: null;
75
109
  warning: IPlayerError;
76
110
  }
77
111
  /**
@@ -55,14 +55,16 @@ var RebufferingController = /** @class */ (function (_super) {
55
55
  * @param {Object} manifest - The Manifest of the currently-played content.
56
56
  * @param {Object} speed - The last speed set by the user
57
57
  */
58
- function RebufferingController(playbackObserver, manifest, speed) {
58
+ function RebufferingController(playbackObserver, manifest, segmentBuffersStore, speed) {
59
59
  var _this = _super.call(this) || this;
60
60
  _this._playbackObserver = playbackObserver;
61
61
  _this._manifest = manifest;
62
+ _this._segmentBuffersStore = segmentBuffersStore;
62
63
  _this._speed = speed;
63
64
  _this._discontinuitiesStore = [];
64
65
  _this._isStarted = false;
65
66
  _this._canceller = new TaskCanceller();
67
+ _this._currentFreezeTimestamp = null;
66
68
  return _this;
67
69
  }
68
70
  RebufferingController.prototype.start = function () {
@@ -100,7 +102,7 @@ var RebufferingController = /** @class */ (function (_super) {
100
102
  this._canceller.signal.register(function () {
101
103
  playbackRateUpdater.dispose();
102
104
  });
103
- var prevFreezingState;
105
+ var prevFreezingState = null;
104
106
  this._playbackObserver.listen(function (observation) {
105
107
  var _a;
106
108
  var discontinuitiesStore = _this._discontinuitiesStore;
@@ -117,6 +119,9 @@ var RebufferingController = /** @class */ (function (_super) {
117
119
  lastSeekingPosition = observation.seeking ?
118
120
  Math.max((_a = observation.pendingInternalSeek) !== null && _a !== void 0 ? _a : 0, observation.position) :
119
121
  null;
122
+ if (_this._checkDecipherabilityFreeze(observation)) {
123
+ return;
124
+ }
120
125
  if (freezing !== null) {
121
126
  var now = performance.now();
122
127
  var referenceTimestamp = prevFreezingState === null ?
@@ -175,7 +180,7 @@ var RebufferingController = /** @class */ (function (_super) {
175
180
  return;
176
181
  }
177
182
  else {
178
- log.warn("Init: ignored stall for too long, checking discontinuity", now - ignoredStallTimeStamp);
183
+ log.warn("Init: ignored stall for too long, considering it", now - ignoredStallTimeStamp);
179
184
  }
180
185
  }
181
186
  ignoredStallTimeStamp = null;
@@ -291,6 +296,81 @@ var RebufferingController = /** @class */ (function (_super) {
291
296
  RebufferingController.prototype.destroy = function () {
292
297
  this._canceller.cancel();
293
298
  };
299
+ /**
300
+ * Support of contents with DRM on all the platforms out there is a pain in
301
+ * the *ss considering all the DRM-related bugs there are.
302
+ *
303
+ * We found out a frequent issue which is to be unable to play despite having
304
+ * all the decryption keys to play what is currently buffered.
305
+ * When this happens, re-creating the buffers from scratch, with a reload, is
306
+ * usually sufficient to unlock the situation.
307
+ *
308
+ * Although we prefer providing more targeted fixes or telling to platform
309
+ * developpers to fix their implementation, it's not always possible.
310
+ * We thus resorted to developping an heuristic which detects such situation
311
+ * and reload in that case.
312
+ *
313
+ * @param {Object} observation - The last playback observation produced, it
314
+ * has to be recent (just triggered for example).
315
+ * @returns {boolean} - Returns `true` if it seems to be such kind of
316
+ * decipherability freeze, in which case this method already performed the
317
+ * right handling steps.
318
+ */
319
+ RebufferingController.prototype._checkDecipherabilityFreeze = function (observation) {
320
+ var readyState = observation.readyState, rebuffering = observation.rebuffering, freezing = observation.freezing;
321
+ var bufferGap = observation.bufferGap !== undefined &&
322
+ isFinite(observation.bufferGap) ? observation.bufferGap :
323
+ 0;
324
+ if (this._segmentBuffersStore === null ||
325
+ bufferGap < 6 ||
326
+ (rebuffering === null && freezing === null) ||
327
+ readyState > 1) {
328
+ this._currentFreezeTimestamp = null;
329
+ return false;
330
+ }
331
+ var now = performance.now();
332
+ if (this._currentFreezeTimestamp === null) {
333
+ this._currentFreezeTimestamp = now;
334
+ }
335
+ var rebufferingForTooLong = rebuffering !== null && now - rebuffering.timestamp > 4000;
336
+ var frozenForTooLong = freezing !== null && now - freezing.timestamp > 4000;
337
+ if ((rebufferingForTooLong || frozenForTooLong) &&
338
+ performance.now() - this._currentFreezeTimestamp > 4000) {
339
+ var statusAudio = this._segmentBuffersStore.getStatus("audio");
340
+ var statusVideo = this._segmentBuffersStore.getStatus("video");
341
+ var hasOnlyDecipherableSegments = true;
342
+ var isClear = true;
343
+ for (var _i = 0, _a = [statusAudio, statusVideo]; _i < _a.length; _i++) {
344
+ var status_1 = _a[_i];
345
+ if (status_1.type === "initialized") {
346
+ for (var _b = 0, _c = status_1.value.getInventory(); _b < _c.length; _b++) {
347
+ var segment = _c[_b];
348
+ var representation = segment.infos.representation;
349
+ if (representation.decipherable === false) {
350
+ log.warn("Init: we have undecipherable segments left in the buffer, reloading");
351
+ this._currentFreezeTimestamp = null;
352
+ this.trigger("needsReload", null);
353
+ return true;
354
+ }
355
+ else if (representation.contentProtections !== undefined) {
356
+ isClear = false;
357
+ if (representation.decipherable !== true) {
358
+ hasOnlyDecipherableSegments = false;
359
+ }
360
+ }
361
+ }
362
+ }
363
+ }
364
+ if (!isClear && hasOnlyDecipherableSegments) {
365
+ log.warn("Init: we are frozen despite only having decipherable " +
366
+ "segments left in the buffer, reloading");
367
+ this._currentFreezeTimestamp = null;
368
+ this.trigger("needsReload", null);
369
+ return true;
370
+ }
371
+ }
372
+ return false;
373
+ };
294
374
  return RebufferingController;
295
375
  }(EventEmitter));
296
376
  export default RebufferingController;
@@ -35,13 +35,15 @@ export default function streamEventsEmitter(manifest, mediaElement, playbackObse
35
35
  scheduledEventsRef.setValue(refreshScheduledEventsList(prev, manifest));
36
36
  }, cancelSignal);
37
37
  var isPollingEvents = false;
38
- var cancelCurrentPolling = new TaskCanceller({ cancelOn: cancelSignal });
38
+ var cancelCurrentPolling = new TaskCanceller();
39
+ cancelCurrentPolling.linkToSignal(cancelSignal);
39
40
  scheduledEventsRef.onUpdate(function (_a) {
40
41
  var scheduledEventsLength = _a.length;
41
42
  if (scheduledEventsLength === 0) {
42
43
  if (isPollingEvents) {
43
44
  cancelCurrentPolling.cancel();
44
- cancelCurrentPolling = new TaskCanceller({ cancelOn: cancelSignal });
45
+ cancelCurrentPolling = new TaskCanceller();
46
+ cancelCurrentPolling.linkToSignal(cancelSignal);
45
47
  isPollingEvents = false;
46
48
  }
47
49
  return;
@@ -127,7 +129,7 @@ export default function streamEventsEmitter(manifest, mediaElement, playbackObse
127
129
  else {
128
130
  onEventSkip(event_2.value);
129
131
  }
130
- if (stopSignal.isCancelled) {
132
+ if (stopSignal.isCancelled()) {
131
133
  return;
132
134
  }
133
135
  }
@@ -138,7 +140,7 @@ export default function streamEventsEmitter(manifest, mediaElement, playbackObse
138
140
  if (typeof event_3.onExit === "function") {
139
141
  event_3.onExit();
140
142
  }
141
- if (stopSignal.isCancelled) {
143
+ if (stopSignal.isCancelled()) {
142
144
  return;
143
145
  }
144
146
  }
@@ -21,7 +21,7 @@ import isNullOrUndefined from "../../../utils/is_null_or_undefined";
21
21
  * @param {Object} cancelSignal
22
22
  */
23
23
  export default function listenToMediaError(mediaElement, onError, cancelSignal) {
24
- if (cancelSignal.isCancelled) {
24
+ if (cancelSignal.isCancelled()) {
25
25
  return;
26
26
  }
27
27
  mediaElement.addEventListener("error", onMediaError);