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
@@ -1,4 +1,3 @@
1
- import { MediaError } from "../../../errors";
2
1
  import Manifest, {
3
2
  Adaptation,
4
3
  Representation,
@@ -63,6 +62,15 @@ export default class TrackDispatcher extends EventEmitter<ITrackDispatcherEvent>
63
62
  /** Interface allowing to clean-up resources when they are not needed anymore. */
64
63
  private _canceller : TaskCanceller;
65
64
 
65
+ /**
66
+ * Boolean set to `true` when a track-updating method is called and to `false`
67
+ * just before it performs the actual track change to allow checking for
68
+ * re-entrancy: if the token is already reset to `false` before the
69
+ * track change is officialized, then another track update has already been
70
+ * performed in the meantime.
71
+ */
72
+ private _updateToken: boolean;
73
+
66
74
  /**
67
75
  * Create a new `TrackDispatcher` by giving its Reference and an initial track
68
76
  * setting.
@@ -70,30 +78,40 @@ export default class TrackDispatcher extends EventEmitter<ITrackDispatcherEvent>
70
78
  * synchronously.
71
79
  * @param {Object} manifest
72
80
  * @param {Object} adaptationRef
73
- * @param {Object|null} initialTrackInfo
74
81
  */
75
82
  constructor(
76
83
  manifest : Manifest,
77
- adaptationRef : ISharedReference<IAdaptationChoice | null | undefined>,
78
- initialTrackInfo : ITrackSetting | null
84
+ adaptationRef : ISharedReference<IAdaptationChoice | null | undefined>
79
85
  ) {
80
86
  super();
81
87
  this._canceller = new TaskCanceller();
82
88
  this._manifest = manifest;
83
89
  this._adaptationRef = adaptationRef;
90
+ this._updateToken = false;
91
+ }
84
92
 
93
+ /**
94
+ * @param {Object|null} initialTrackInfo
95
+ */
96
+ public start(initialTrackInfo : ITrackSetting | null) : void {
97
+ this._updateToken = true;
85
98
  if (initialTrackInfo === null) {
86
- this._lastEmitted = initialTrackInfo;
87
- adaptationRef.setValue(null);
99
+ this._lastEmitted = null;
100
+ this._updateToken = false;
101
+ this._adaptationRef.setValue(null);
88
102
  return;
89
103
  }
90
104
  const reference = this._constructLockedRepresentationsReference(initialTrackInfo);
105
+ if (!this._updateToken) {
106
+ return;
107
+ }
91
108
  this._lastEmitted = { adaptation: initialTrackInfo.adaptation,
92
109
  switchingMode: initialTrackInfo.switchingMode,
93
110
  lockedRepresentations: null };
94
- adaptationRef.setValue({ adaptation: initialTrackInfo.adaptation,
95
- switchingMode: initialTrackInfo.switchingMode,
96
- representations: reference });
111
+ this._updateToken = false;
112
+ this._adaptationRef.setValue({ adaptation: initialTrackInfo.adaptation,
113
+ switchingMode: initialTrackInfo.switchingMode,
114
+ representations: reference });
97
115
  }
98
116
 
99
117
  /**
@@ -101,10 +119,12 @@ export default class TrackDispatcher extends EventEmitter<ITrackDispatcherEvent>
101
119
  * @param {Object|null} newTrackInfo
102
120
  */
103
121
  public updateTrack(newTrackInfo : ITrackSetting | null) : void {
122
+ this._updateToken = true;
104
123
  if (newTrackInfo === null) {
105
124
  if (this._lastEmitted === null) {
106
125
  return;
107
126
  }
127
+ this._updateToken = false;
108
128
  this._canceller.cancel();
109
129
 
110
130
  // has no point but let's still create one for simplicity sake
@@ -117,7 +137,11 @@ export default class TrackDispatcher extends EventEmitter<ITrackDispatcherEvent>
117
137
  this._canceller.cancel();
118
138
  this._canceller = new TaskCanceller();
119
139
  const reference = this._constructLockedRepresentationsReference(newTrackInfo);
140
+ if (!this._updateToken) {
141
+ return;
142
+ }
120
143
  this._lastEmitted = { adaptation, switchingMode, lockedRepresentations: null };
144
+ this._updateToken = false;
121
145
  this._adaptationRef.setValue({ adaptation,
122
146
  switchingMode,
123
147
  representations: reference });
@@ -176,11 +200,9 @@ export default class TrackDispatcher extends EventEmitter<ITrackDispatcherEvent>
176
200
  }
177
201
  }
178
202
  if (playableRepresentations.length <= 0) {
179
- const adaptationType = trackInfo.adaptation.type;
180
- const noRepErr = new MediaError("NO_PLAYABLE_REPRESENTATION",
181
- "No Representation in the chosen " +
182
- adaptationType + " Adaptation can be played");
183
- throw noRepErr;
203
+ trackInfo.adaptation.isSupported = false;
204
+ self.trigger("noPlayableRepresentation", null);
205
+ return;
184
206
  }
185
207
 
186
208
  // Check if Locked Representations have changed
@@ -221,6 +243,7 @@ export interface ITrackDispatcherEvent {
221
243
  * none of them are currently "playable".
222
244
  */
223
245
  noPlayableLockedRepresentation : null;
246
+ noPlayableRepresentation: null;
224
247
  }
225
248
 
226
249
  /** Define a new Track preference given to the `TrackDispatcher`. */
@@ -20,6 +20,7 @@
20
20
  */
21
21
 
22
22
  import config from "../../../config";
23
+ import { MediaError } from "../../../errors";
23
24
  import log from "../../../log";
24
25
  import Manifest, {
25
26
  Adaptation,
@@ -27,7 +28,6 @@ import Manifest, {
27
28
  Representation,
28
29
  } from "../../../manifest";
29
30
  import {
30
- IAudioRepresentation,
31
31
  IAudioRepresentationsSwitchingMode,
32
32
  IAudioTrack,
33
33
  IAudioTrackSwitchingMode,
@@ -38,18 +38,19 @@ import {
38
38
  IBrokenRepresentationsLockContext,
39
39
  IPeriod,
40
40
  ITextTrack,
41
- IVideoRepresentation,
42
41
  IVideoRepresentationsSwitchingMode,
43
42
  IVideoTrack,
44
43
  IVideoTrackSwitchingMode,
44
+ IPlayerError,
45
45
  } from "../../../public_types";
46
46
  import arrayFind from "../../../utils/array_find";
47
47
  import assert from "../../../utils/assert";
48
48
  import EventEmitter from "../../../utils/event_emitter";
49
+ import isNullOrUndefined from "../../../utils/is_null_or_undefined";
50
+ import objectAssign from "../../../utils/object_assign";
49
51
  import createSharedReference, {
50
52
  ISharedReference,
51
53
  } from "../../../utils/reference";
52
- import takeFirstSet from "../../../utils/take_first_set";
53
54
  import {
54
55
  IAdaptationChoice,
55
56
  IRepresentationsChoice,
@@ -156,7 +157,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
156
157
  const stillHere = textAdaptations
157
158
  .some(a => a.id === curWantedTextTrack.adaptation.id);
158
159
  if (!stillHere) {
159
- log.warn("TracksStore: Chosen text Adaptation not available anymore");
160
+ log.warn("TS: Chosen text Adaptation not available anymore");
160
161
  const periodInfo = this._storedPeriodInfo[i];
161
162
  periodInfo.text.storedSettings = null;
162
163
  this.trigger("trackUpdate", { period: toExposedPeriod(newPeriod),
@@ -182,7 +183,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
182
183
  const stillHere = videoAdaptations
183
184
  .some(a => a.id === curWantedVideoTrack.adaptation.id);
184
185
  if (!stillHere) {
185
- log.warn("TracksStore: Chosen video Adaptation not available anymore");
186
+ log.warn("TS: Chosen video Adaptation not available anymore");
186
187
  const periodItem = this._storedPeriodInfo[i];
187
188
  let storedSettings : IVideoStoredSettings;
188
189
  if (videoAdaptations.length === 0) {
@@ -224,7 +225,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
224
225
  const stillHere = audioAdaptations
225
226
  .some(a => a.id === curWantedAudioTrack.adaptation.id);
226
227
  if (!stillHere) {
227
- log.warn("TracksStore: Chosen audio Adaptation not available anymore");
228
+ log.warn("TS: Chosen audio Adaptation not available anymore");
228
229
  const periodItem = this._storedPeriodInfo[i];
229
230
  const storedSettings = audioAdaptations.length === 0 ?
230
231
  null :
@@ -323,20 +324,62 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
323
324
  }
324
325
 
325
326
  if (periodObj[bufferType].dispatcher !== null) {
326
- log.error(`TracksStore: Subject already added for ${bufferType} ` +
327
+ log.error(`TS: Subject already added for ${bufferType} ` +
327
328
  `and Period ${period.start}`);
328
329
  return;
329
330
  }
330
331
  const trackSetting = periodObj[bufferType].storedSettings;
331
- const dispatcher = new TrackDispatcher(manifest, adaptationRef, trackSetting);
332
+ const dispatcher = new TrackDispatcher(manifest, adaptationRef);
332
333
  periodObj[bufferType].dispatcher = dispatcher;
334
+ dispatcher.addEventListener("noPlayableRepresentation", () => {
335
+ const nextAdaptation = arrayFind(period.getAdaptationsForType(bufferType), (a) => {
336
+ const playableRepresentations = a.getPlayableRepresentations();
337
+ return playableRepresentations.length > 0;
338
+ });
339
+ if (nextAdaptation === undefined) {
340
+ const noRepErr = new MediaError("NO_PLAYABLE_REPRESENTATION",
341
+ `No ${bufferType} Representation can be played`,
342
+ { adaptation: undefined });
343
+ this.trigger("error", noRepErr);
344
+ this.dispose();
345
+ return;
346
+ }
347
+ let typeInfo = getPeriodItem(this._storedPeriodInfo, period.id)?.[bufferType];
348
+ if (isNullOrUndefined(typeInfo)) {
349
+ return;
350
+ }
351
+ const switchingMode = bufferType === "audio" ?
352
+ this._defaultAudioTrackSwitchingMode :
353
+ "reload";
354
+ const storedSettings = { adaptation: nextAdaptation,
355
+ switchingMode,
356
+ lockedRepresentations: createSharedReference(null) };
357
+ typeInfo.storedSettings = storedSettings;
358
+ this.trigger("trackUpdate", { period: toExposedPeriod(period),
359
+ trackType: bufferType,
360
+ reason: "no-playable-representation" });
361
+
362
+ // The previous event trigger could have had side-effects, so we
363
+ // re-check if we're still mostly in the same state
364
+ if (this._isDisposed) {
365
+ return; // Someone disposed the `TracksStore` on the previous side-effect
366
+ }
367
+ typeInfo = getPeriodItem(this._storedPeriodInfo, period.id)?.[bufferType];
368
+ if (isNullOrUndefined(typeInfo) || typeInfo.storedSettings !== storedSettings) {
369
+ return;
370
+ }
371
+ typeInfo.dispatcher?.updateTrack(storedSettings);
372
+ });
333
373
  dispatcher.addEventListener("noPlayableLockedRepresentation", () => {
374
+ // TODO check that it doesn't already lead to segment loading or MediaSource
375
+ // reloading
334
376
  trackSetting?.lockedRepresentations.setValue(null);
335
377
  this.trigger("brokenRepresentationsLock", { period: { id: period.id,
336
378
  start: period.start,
337
379
  end: period.end },
338
380
  trackType: bufferType });
339
381
  });
382
+ dispatcher.start(trackSetting);
340
383
  }
341
384
 
342
385
  /**
@@ -351,7 +394,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
351
394
  ) : void {
352
395
  const periodIndex = findPeriodIndex(this._storedPeriodInfo, period);
353
396
  if (periodIndex === undefined) {
354
- log.warn(`TracksStore: ${bufferType} not found for period`,
397
+ log.warn(`TS: ${bufferType} not found for period`,
355
398
  period.start);
356
399
  return;
357
400
  }
@@ -359,7 +402,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
359
402
  const periodObj = this._storedPeriodInfo[periodIndex];
360
403
  const choiceItem = periodObj[bufferType];
361
404
  if (choiceItem?.dispatcher === null) {
362
- log.warn(`TracksStore: TrackDispatcher already removed for ${bufferType} ` +
405
+ log.warn(`TS: TrackDispatcher already removed for ${bufferType} ` +
363
406
  `and Period ${period.start}`);
364
407
  return;
365
408
  }
@@ -684,10 +727,12 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
684
727
  * `null` if audio tracks were disabled and `undefined` if the Period is not
685
728
  * known.
686
729
  */
687
- public getChosenAudioTrack(periodObj : ITMPeriodObject) : IAudioTrack | null {
730
+ public getChosenAudioTrack(
731
+ periodObj : ITMPeriodObject
732
+ ) : IAudioTrack | null {
688
733
  return periodObj.audio.storedSettings === null ?
689
734
  null :
690
- toAudioTrack(periodObj.audio.storedSettings.adaptation);
735
+ periodObj.audio.storedSettings.adaptation.toAudioTrack(true);
691
736
  }
692
737
 
693
738
  /**
@@ -705,7 +750,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
705
750
  ) : ITextTrack | null {
706
751
  return periodObj.text.storedSettings === null ?
707
752
  null :
708
- toTextTrack(periodObj.text.storedSettings.adaptation);
753
+ periodObj.text.storedSettings.adaptation.toTextTrack();
709
754
  }
710
755
 
711
756
  /**
@@ -725,7 +770,7 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
725
770
  return null;
726
771
  }
727
772
 
728
- return toVideoTrack(periodObj.video.storedSettings.adaptation);
773
+ return periodObj.video.storedSettings.adaptation.toVideoTrack(true);
729
774
  }
730
775
 
731
776
  /**
@@ -746,21 +791,9 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
746
791
  null;
747
792
  return periodObj.period.getSupportedAdaptations("audio")
748
793
  .map((adaptation) => {
749
- const formatted : IAvailableAudioTrack = {
750
- language: takeFirstSet<string>(adaptation.language, ""),
751
- normalized: takeFirstSet<string>(adaptation.normalizedLanguage, ""),
752
- audioDescription: adaptation.isAudioDescription === true,
753
- id: adaptation.id,
754
- active: currentId === null ? false :
755
- currentId === adaptation.id,
756
- representations: adaptation.getPlayableRepresentations()
757
- .map(parseAudioRepresentation),
758
- label: adaptation.label,
759
- };
760
- if (adaptation.isDub === true) {
761
- formatted.dub = true;
762
- }
763
- return formatted;
794
+ const active = currentId === null ? false :
795
+ currentId === adaptation.id;
796
+ return objectAssign(adaptation.toAudioTrack(true), { active });
764
797
  });
765
798
  }
766
799
 
@@ -783,19 +816,9 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
783
816
 
784
817
  return periodObj.period.getSupportedAdaptations("text")
785
818
  .map((adaptation) => {
786
- const formatted : IAvailableTextTrack = {
787
- language: takeFirstSet<string>(adaptation.language, ""),
788
- normalized: takeFirstSet<string>(adaptation.normalizedLanguage, ""),
789
- closedCaption: adaptation.isClosedCaption === true,
790
- id: adaptation.id,
791
- active: currentId === null ? false :
792
- currentId === adaptation.id,
793
- label: adaptation.label,
794
- };
795
- if (adaptation.isForcedSubtitles !== undefined) {
796
- formatted.forced = adaptation.isForcedSubtitles;
797
- }
798
- return formatted;
819
+ const active = currentId === null ? false :
820
+ currentId === adaptation.id;
821
+ return objectAssign(adaptation.toTextTrack(), { active });
799
822
  });
800
823
  }
801
824
 
@@ -818,38 +841,21 @@ export default class TracksStore extends EventEmitter<ITracksStoreEvents> {
818
841
 
819
842
  return periodObj.period.getSupportedAdaptations("video")
820
843
  .map((adaptation) => {
821
- const trickModeTracks = adaptation.trickModeTracks !== undefined ?
822
- adaptation.trickModeTracks.map((trickModeAdaptation) => {
844
+ const active = currentId === null ? false :
845
+ currentId === adaptation.id;
846
+ const track = adaptation.toVideoTrack(true);
847
+ const trickModeTracks = track.trickModeTracks !== undefined ?
848
+ track.trickModeTracks.map((trickModeAdaptation) => {
823
849
  const isActive = currentId === null ? false :
824
850
  currentId === trickModeAdaptation.id;
825
- const representations = trickModeAdaptation.getPlayableRepresentations()
826
- .map(parseVideoRepresentation);
827
- const trickMode : IAvailableVideoTrack = { id: trickModeAdaptation.id,
828
- representations,
829
- isTrickModeTrack: true,
830
- active: isActive };
831
- if (trickModeAdaptation.isSignInterpreted === true) {
832
- trickMode.signInterpreted = true;
833
- }
834
- return trickMode;
851
+ return objectAssign(trickModeAdaptation, { active: isActive });
835
852
  }) :
836
- undefined;
837
-
838
- const formatted: IAvailableVideoTrack = {
839
- id: adaptation.id,
840
- active: currentId === null ? false :
841
- currentId === adaptation.id,
842
- representations: adaptation.getPlayableRepresentations()
843
- .map(parseVideoRepresentation),
844
- label: adaptation.label,
845
- };
846
- if (adaptation.isSignInterpreted === true) {
847
- formatted.signInterpreted = true;
848
- }
853
+ [];
854
+ const availableTrack = objectAssign(track, { active });
849
855
  if (trickModeTracks !== undefined) {
850
- formatted.trickModeTracks = trickModeTracks;
856
+ availableTrack.trickModeTracks = trickModeTracks;
851
857
  }
852
- return formatted;
858
+ return availableTrack;
853
859
  });
854
860
  }
855
861
 
@@ -1082,17 +1088,6 @@ function getPeriodItem(
1082
1088
  }
1083
1089
  }
1084
1090
 
1085
- /**
1086
- * Parse video Representation into a IVideoRepresentation.
1087
- * @param {Object} representation
1088
- * @returns {Object}
1089
- */
1090
- function parseVideoRepresentation(
1091
- { id, bitrate, frameRate, width, height, codec, hdrInfo } : Representation
1092
- ) : IVideoRepresentation {
1093
- return { id, bitrate, frameRate, width, height, codec, hdrInfo };
1094
- }
1095
-
1096
1091
  /**
1097
1092
  * A `ITMPeriodObject` should only be removed once all References linked to it
1098
1093
  * do not exist anymore, to keep the possibility of making track choices.
@@ -1108,17 +1103,6 @@ function isPeriodItemRemovable(
1108
1103
  periodObj.video?.dispatcher === null;
1109
1104
  }
1110
1105
 
1111
- /**
1112
- * Parse audio Representation into a ITMAudioRepresentation.
1113
- * @param {Object} representation
1114
- * @returns {Object}
1115
- */
1116
- function parseAudioRepresentation(
1117
- { id, bitrate, codec } : Representation
1118
- ) : IAudioRepresentation {
1119
- return { id, bitrate, codec };
1120
- }
1121
-
1122
1106
  function getRightVideoTrack(
1123
1107
  adaptation : Adaptation,
1124
1108
  isTrickModeEnabled : boolean
@@ -1197,82 +1181,6 @@ function generatePeriodInfo(
1197
1181
  dispatcher: null } };
1198
1182
  }
1199
1183
 
1200
- /**
1201
- * Format Adaptation structure into the format awaited by the API.
1202
- * @param {Object} a
1203
- * @returns {Object}
1204
- */
1205
- function toTextTrack(a : Adaptation) : ITextTrack {
1206
- const formatted : ITextTrack = {
1207
- language: a.language ?? "",
1208
- normalized: a.normalizedLanguage ?? "",
1209
- closedCaption: a.isClosedCaption === true,
1210
- id: a.id,
1211
- label: a.label,
1212
- };
1213
- if (a.isForcedSubtitles !== undefined) {
1214
- formatted.forced = a.isForcedSubtitles;
1215
- }
1216
- return formatted;
1217
- }
1218
-
1219
- /**
1220
- * Format Adaptation structure into the format awaited by the API.
1221
- * @param {Object} a
1222
- * @returns {Object}
1223
- */
1224
- function toVideoTrack(a : Adaptation) : IVideoTrack {
1225
- const trickModeTracks = a.trickModeTracks !== undefined ?
1226
- a.trickModeTracks.map((trickModeAdaptation) => {
1227
- const representations = trickModeAdaptation.getPlayableRepresentations()
1228
- .map(parseVideoRepresentation);
1229
- const trickMode : IVideoTrack = { id: trickModeAdaptation.id,
1230
- representations,
1231
- isTrickModeTrack: true };
1232
- if (trickModeAdaptation.isSignInterpreted === true) {
1233
- trickMode.signInterpreted = true;
1234
- }
1235
- return trickMode;
1236
- }) :
1237
- undefined;
1238
-
1239
- const videoTrack: IVideoTrack = {
1240
- id: a.id,
1241
- representations: a.getPlayableRepresentations().map(parseVideoRepresentation),
1242
- label: a.label,
1243
- };
1244
- if (a.isSignInterpreted === true) {
1245
- videoTrack.signInterpreted = true;
1246
- }
1247
- if (a.isTrickModeTrack === true) {
1248
- videoTrack.isTrickModeTrack = true;
1249
- }
1250
- if (trickModeTracks !== undefined) {
1251
- videoTrack.trickModeTracks = trickModeTracks;
1252
- }
1253
- return videoTrack;
1254
- }
1255
-
1256
- /**
1257
- * Convert an audio Adaptation into an audio track.
1258
- * @param {object|null} adaptation - Audio adaptation
1259
- * @returns {object|null} - corresponding audio track object.
1260
- */
1261
- function toAudioTrack(adaptation : Adaptation) : IAudioTrack {
1262
- const audioTrack : IAudioTrack = {
1263
- language: takeFirstSet<string>(adaptation.language, ""),
1264
- normalized: takeFirstSet<string>(adaptation.normalizedLanguage, ""),
1265
- audioDescription: adaptation.isAudioDescription === true,
1266
- id: adaptation.id,
1267
- representations: adaptation.representations.map(parseAudioRepresentation),
1268
- label: adaptation.label,
1269
- };
1270
- if (adaptation.isDub === true) {
1271
- audioTrack.dub = true;
1272
- }
1273
- return audioTrack;
1274
- }
1275
-
1276
1184
  function toExposedPeriod(p: Period) : IPeriod {
1277
1185
  return { start: p.start, end: p.end, id: p.id };
1278
1186
  }
@@ -1435,6 +1343,8 @@ interface ITracksStoreEvents {
1435
1343
  newAvailablePeriods : IPeriod[];
1436
1344
  brokenRepresentationsLock : IBrokenRepresentationsLockContext;
1437
1345
  trackUpdate : ITrackUpdateEventPayload;
1346
+ error : unknown;
1347
+ warning : IPlayerError;
1438
1348
  }
1439
1349
 
1440
1350
  export interface IAudioRepresentationsLockSettings {
@@ -48,14 +48,14 @@ export function emitSeekEvents(
48
48
  onSeeked: () => void,
49
49
  cancelSignal : CancellationSignal
50
50
  ) : void {
51
- if (cancelSignal.isCancelled || mediaElement === null) {
51
+ if (cancelSignal.isCancelled() || mediaElement === null) {
52
52
  return ;
53
53
  }
54
54
 
55
55
  let wasSeeking = playbackObserver.getReference().getValue().seeking;
56
56
  if (wasSeeking) {
57
57
  onSeeking();
58
- if (cancelSignal.isCancelled) {
58
+ if (cancelSignal.isCancelled()) {
59
59
  return;
60
60
  }
61
61
  }
@@ -70,6 +70,32 @@ export function emitSeekEvents(
70
70
  }, { includeLastObservation: true, clearSignal: cancelSignal });
71
71
  }
72
72
 
73
+ /**
74
+ * @param {HTMLMediaElement} mediaElement
75
+ * @param {function} onPlay - Callback called when a play operation has started
76
+ * on `mediaElement`.
77
+ * @param {function} onPause - Callback called when a pause operation has
78
+ * started on `mediaElement`.
79
+ * @param {Object} cancelSignal - When triggered, stop calling callbacks and
80
+ * remove all listeners this function has registered.
81
+ */
82
+ export function emitPlayPauseEvents(
83
+ mediaElement : HTMLMediaElement | null,
84
+ onPlay: () => void,
85
+ onPause: () => void,
86
+ cancelSignal : CancellationSignal
87
+ ) : void {
88
+ if (cancelSignal.isCancelled() || mediaElement === null) {
89
+ return ;
90
+ }
91
+ mediaElement.addEventListener("play", onPlay);
92
+ mediaElement.addEventListener("pause", onPause);
93
+ cancelSignal.register(() => {
94
+ mediaElement.removeEventListener("play", onPlay);
95
+ mediaElement.removeEventListener("pause", onPause);
96
+ });
97
+ }
98
+
73
99
  /** Player state dictionnary. */
74
100
  export const enum PLAYER_STATES {
75
101
  STOPPED = "STOPPED",
@@ -95,7 +121,7 @@ export function constructPlayerStateReference(
95
121
  initializer.addEventListener("loaded", () => {
96
122
  if (playerStateRef.getValue() === PLAYER_STATES.LOADING) {
97
123
  playerStateRef.setValue(PLAYER_STATES.LOADED);
98
- if (!cancelSignal.isCancelled) {
124
+ if (!cancelSignal.isCancelled()) {
99
125
  const newState = getLoadedContentState(mediaElement, null);
100
126
  if (newState !== PLAYER_STATES.PAUSED) {
101
127
  playerStateRef.setValue(newState);