rx-player 4.4.0 → 4.4.1-dev.2025101500

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 (341) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +52 -113
  3. package/VERSION +1 -1
  4. package/dist/commonjs/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
  5. package/dist/commonjs/__GENERATED_CODE/embedded_worker.js +1 -1
  6. package/dist/commonjs/core/{main/common → entry}/FreezeResolver.d.ts +3 -3
  7. package/dist/commonjs/core/entry/FreezeResolver.d.ts.map +1 -0
  8. package/dist/commonjs/core/{main/common → entry}/FreezeResolver.js +3 -3
  9. package/dist/{es2017/core/main/worker → commonjs/core/entry}/content_preparer.d.ts +22 -15
  10. package/dist/commonjs/core/entry/content_preparer.d.ts.map +1 -0
  11. package/dist/commonjs/core/{main/worker → entry}/content_preparer.js +62 -64
  12. package/dist/{es2017/core/main/common → commonjs/core/entry}/content_time_boundaries_observer.d.ts +5 -5
  13. package/dist/commonjs/core/entry/content_time_boundaries_observer.d.ts.map +1 -0
  14. package/dist/commonjs/core/{main/common → entry}/content_time_boundaries_observer.js +6 -6
  15. package/dist/commonjs/core/entry/core_entry.d.ts +36 -0
  16. package/dist/commonjs/core/entry/core_entry.d.ts.map +1 -0
  17. package/dist/commonjs/core/{main/worker/worker_main.js → entry/core_entry.js} +192 -153
  18. package/dist/commonjs/core/{main/worker/worker_text_displayer_interface.d.ts → entry/core_text_displayer_interface.d.ts} +11 -11
  19. package/dist/commonjs/core/entry/core_text_displayer_interface.d.ts.map +1 -0
  20. package/dist/commonjs/core/{main/worker/worker_text_displayer_interface.js → entry/core_text_displayer_interface.js} +22 -22
  21. package/dist/commonjs/core/{main/common → entry}/create_content_time_boundaries_observer.d.ts +6 -6
  22. package/dist/commonjs/core/entry/create_content_time_boundaries_observer.d.ts.map +1 -0
  23. package/dist/commonjs/core/{main/common → entry}/create_content_time_boundaries_observer.js +1 -1
  24. package/dist/commonjs/core/{main/common → entry}/get_buffered_data_per_media_buffer.d.ts +4 -4
  25. package/dist/commonjs/core/entry/get_buffered_data_per_media_buffer.d.ts.map +1 -0
  26. package/dist/commonjs/core/{main/common → entry}/get_buffered_data_per_media_buffer.js +1 -1
  27. package/dist/{es2017/core/main/common → commonjs/core/entry}/get_thumbnail_data.d.ts +3 -3
  28. package/dist/commonjs/core/entry/get_thumbnail_data.d.ts.map +1 -0
  29. package/dist/commonjs/core/{main/common → entry}/get_thumbnail_data.js +2 -2
  30. package/dist/commonjs/core/entry/index.d.ts +5 -0
  31. package/dist/commonjs/core/entry/index.d.ts.map +1 -0
  32. package/dist/commonjs/core/entry/index.js +4 -0
  33. package/dist/{es2017/core/main/common → commonjs/core/entry}/synchronize_sinks_on_observation.d.ts +2 -2
  34. package/dist/commonjs/core/entry/synchronize_sinks_on_observation.d.ts.map +1 -0
  35. package/dist/commonjs/core/{main/worker → entry}/track_choice_setter.d.ts +4 -4
  36. package/dist/commonjs/core/entry/track_choice_setter.d.ts.map +1 -0
  37. package/dist/commonjs/core/{main/worker → entry}/track_choice_setter.js +4 -4
  38. package/dist/commonjs/core/entry/utils.d.ts +3 -0
  39. package/dist/commonjs/core/entry/utils.d.ts.map +1 -0
  40. package/dist/commonjs/core/entry/utils.js +11 -0
  41. package/dist/commonjs/core/stream/orchestrator/stream_orchestrator.d.ts.map +1 -1
  42. package/dist/commonjs/core/stream/orchestrator/stream_orchestrator.js +17 -0
  43. package/dist/commonjs/core/types.d.ts +519 -1
  44. package/dist/commonjs/core/types.d.ts.map +1 -1
  45. package/dist/commonjs/core/types.js +1 -0
  46. package/dist/commonjs/experimental/features/local.d.ts.map +1 -1
  47. package/dist/commonjs/experimental/features/local.js +7 -1
  48. package/dist/commonjs/experimental/features/metaplaylist.d.ts.map +1 -1
  49. package/dist/commonjs/experimental/features/metaplaylist.js +7 -1
  50. package/dist/commonjs/experimental/features/multi_thread.d.ts.map +1 -1
  51. package/dist/commonjs/experimental/features/multi_thread.js +6 -2
  52. package/dist/commonjs/features/features_object.js +1 -1
  53. package/dist/commonjs/features/list/dash.d.ts.map +1 -1
  54. package/dist/commonjs/features/list/dash.js +7 -1
  55. package/dist/commonjs/features/list/dash_wasm.d.ts.map +1 -1
  56. package/dist/commonjs/features/list/dash_wasm.js +7 -1
  57. package/dist/commonjs/features/list/media_source_main.d.ts.map +1 -1
  58. package/dist/commonjs/features/list/media_source_main.js +7 -1
  59. package/dist/commonjs/features/list/smooth.d.ts.map +1 -1
  60. package/dist/commonjs/features/list/smooth.js +7 -1
  61. package/dist/commonjs/features/types.d.ts +20 -4
  62. package/dist/commonjs/features/types.d.ts.map +1 -1
  63. package/dist/commonjs/main_thread/api/public_api.d.ts.map +1 -1
  64. package/dist/commonjs/main_thread/api/public_api.js +39 -42
  65. package/dist/commonjs/main_thread/core_interface/base.d.ts +13 -0
  66. package/dist/commonjs/main_thread/core_interface/base.d.ts.map +1 -0
  67. package/dist/commonjs/main_thread/core_interface/base.js +32 -0
  68. package/dist/commonjs/main_thread/core_interface/monothread.d.ts +13 -0
  69. package/dist/commonjs/main_thread/core_interface/monothread.d.ts.map +1 -0
  70. package/dist/commonjs/main_thread/core_interface/monothread.js +56 -0
  71. package/dist/commonjs/main_thread/core_interface/multithread.d.ts +25 -0
  72. package/dist/commonjs/main_thread/core_interface/multithread.d.ts.map +1 -0
  73. package/dist/commonjs/main_thread/core_interface/multithread.js +67 -0
  74. package/dist/commonjs/main_thread/core_interface/types.d.ts +6 -0
  75. package/dist/commonjs/main_thread/core_interface/types.d.ts.map +1 -0
  76. package/dist/commonjs/main_thread/core_interface/types.js +2 -0
  77. package/dist/commonjs/main_thread/init/media_source_content_initializer.d.ts +166 -108
  78. package/dist/commonjs/main_thread/init/media_source_content_initializer.d.ts.map +1 -1
  79. package/dist/commonjs/main_thread/init/media_source_content_initializer.js +1492 -919
  80. package/dist/commonjs/main_thread/init/utils/create_core_playback_observer.d.ts.map +1 -1
  81. package/dist/commonjs/main_thread/init/utils/create_core_playback_observer.js +2 -1
  82. package/dist/commonjs/main_thread/init/utils/update_manifest_codec_support.d.ts +1 -1
  83. package/dist/commonjs/main_thread/init/utils/update_manifest_codec_support.d.ts.map +1 -1
  84. package/dist/commonjs/main_thread/types.d.ts +537 -0
  85. package/dist/commonjs/main_thread/types.d.ts.map +1 -1
  86. package/dist/commonjs/manifest/utils.d.ts.map +1 -1
  87. package/dist/commonjs/manifest/utils.js +18 -4
  88. package/dist/commonjs/mse/worker_media_source_interface.d.ts +2 -2
  89. package/dist/commonjs/mse/worker_media_source_interface.d.ts.map +1 -1
  90. package/dist/commonjs/mse/worker_media_source_interface.js +12 -12
  91. package/dist/commonjs/parsers/manifest/smooth/create_parser.d.ts +1 -1
  92. package/dist/commonjs/parsers/manifest/smooth/create_parser.d.ts.map +1 -1
  93. package/dist/commonjs/parsers/manifest/smooth/create_parser.js +31 -27
  94. package/dist/commonjs/parsers/manifest/smooth/parse_C_nodes.d.ts +3 -2
  95. package/dist/commonjs/parsers/manifest/smooth/parse_C_nodes.d.ts.map +1 -1
  96. package/dist/commonjs/parsers/manifest/smooth/parse_C_nodes.js +16 -7
  97. package/dist/commonjs/parsers/manifest/smooth/parse_protection_node.d.ts +3 -2
  98. package/dist/commonjs/parsers/manifest/smooth/parse_protection_node.d.ts.map +1 -1
  99. package/dist/commonjs/parsers/manifest/smooth/parse_protection_node.js +37 -6
  100. package/dist/commonjs/parsers/manifest/smooth/utils/parseBoolean.d.ts +1 -1
  101. package/dist/commonjs/parsers/manifest/smooth/utils/parseBoolean.d.ts.map +1 -1
  102. package/dist/commonjs/parsers/manifest/smooth/utils/reduceChildren.d.ts +3 -2
  103. package/dist/commonjs/parsers/manifest/smooth/utils/reduceChildren.d.ts.map +1 -1
  104. package/dist/commonjs/parsers/manifest/smooth/utils/reduceChildren.js +28 -5
  105. package/dist/{es2017/playback_observer/worker_playback_observer.d.ts → commonjs/playback_observer/core_playback_observer.d.ts} +8 -8
  106. package/dist/commonjs/playback_observer/core_playback_observer.d.ts.map +1 -0
  107. package/dist/commonjs/playback_observer/{worker_playback_observer.js → core_playback_observer.js} +13 -13
  108. package/dist/commonjs/transports/smooth/pipelines.d.ts.map +1 -1
  109. package/dist/commonjs/transports/smooth/pipelines.js +25 -3
  110. package/dist/commonjs/worker_entry_point.js +62 -2
  111. package/dist/es2017/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
  112. package/dist/es2017/__GENERATED_CODE/embedded_worker.js +1 -1
  113. package/dist/es2017/core/{main/common → entry}/FreezeResolver.d.ts +3 -3
  114. package/dist/es2017/core/entry/FreezeResolver.d.ts.map +1 -0
  115. package/dist/es2017/core/{main/common → entry}/FreezeResolver.js +3 -3
  116. package/dist/{commonjs/core/main/worker → es2017/core/entry}/content_preparer.d.ts +22 -15
  117. package/dist/es2017/core/entry/content_preparer.d.ts.map +1 -0
  118. package/dist/es2017/core/{main/worker → entry}/content_preparer.js +53 -55
  119. package/dist/{commonjs/core/main/common → es2017/core/entry}/content_time_boundaries_observer.d.ts +5 -5
  120. package/dist/es2017/core/entry/content_time_boundaries_observer.d.ts.map +1 -0
  121. package/dist/es2017/core/{main/common → entry}/content_time_boundaries_observer.js +6 -6
  122. package/dist/es2017/core/entry/core_entry.d.ts +36 -0
  123. package/dist/es2017/core/entry/core_entry.d.ts.map +1 -0
  124. package/dist/es2017/core/{main/worker/worker_main.js → entry/core_entry.js} +153 -114
  125. package/dist/es2017/core/{main/worker/worker_text_displayer_interface.d.ts → entry/core_text_displayer_interface.d.ts} +11 -11
  126. package/dist/es2017/core/entry/core_text_displayer_interface.d.ts.map +1 -0
  127. package/dist/es2017/core/{main/worker/worker_text_displayer_interface.js → entry/core_text_displayer_interface.js} +10 -10
  128. package/dist/es2017/core/{main/common → entry}/create_content_time_boundaries_observer.d.ts +6 -6
  129. package/dist/es2017/core/entry/create_content_time_boundaries_observer.d.ts.map +1 -0
  130. package/dist/es2017/core/{main/common → entry}/create_content_time_boundaries_observer.js +1 -1
  131. package/dist/es2017/core/{main/common → entry}/get_buffered_data_per_media_buffer.d.ts +4 -4
  132. package/dist/es2017/core/entry/get_buffered_data_per_media_buffer.d.ts.map +1 -0
  133. package/dist/es2017/core/{main/common → entry}/get_buffered_data_per_media_buffer.js +1 -1
  134. package/dist/{commonjs/core/main/common → es2017/core/entry}/get_thumbnail_data.d.ts +3 -3
  135. package/dist/es2017/core/entry/get_thumbnail_data.d.ts.map +1 -0
  136. package/dist/es2017/core/{main/common → entry}/get_thumbnail_data.js +2 -2
  137. package/dist/es2017/core/entry/index.d.ts +5 -0
  138. package/dist/es2017/core/entry/index.d.ts.map +1 -0
  139. package/dist/es2017/core/entry/index.js +2 -0
  140. package/dist/{commonjs/core/main/common → es2017/core/entry}/synchronize_sinks_on_observation.d.ts +2 -2
  141. package/dist/es2017/core/entry/synchronize_sinks_on_observation.d.ts.map +1 -0
  142. package/dist/es2017/core/{main/worker → entry}/track_choice_setter.d.ts +4 -4
  143. package/dist/es2017/core/entry/track_choice_setter.d.ts.map +1 -0
  144. package/dist/es2017/core/{main/worker → entry}/track_choice_setter.js +4 -4
  145. package/dist/es2017/core/entry/utils.d.ts +3 -0
  146. package/dist/es2017/core/entry/utils.d.ts.map +1 -0
  147. package/dist/es2017/core/entry/utils.js +8 -0
  148. package/dist/es2017/core/stream/orchestrator/stream_orchestrator.d.ts.map +1 -1
  149. package/dist/es2017/core/stream/orchestrator/stream_orchestrator.js +18 -1
  150. package/dist/es2017/core/types.d.ts +519 -1
  151. package/dist/es2017/core/types.d.ts.map +1 -1
  152. package/dist/es2017/core/types.js +1 -0
  153. package/dist/es2017/experimental/features/local.d.ts.map +1 -1
  154. package/dist/es2017/experimental/features/local.js +7 -1
  155. package/dist/es2017/experimental/features/metaplaylist.d.ts.map +1 -1
  156. package/dist/es2017/experimental/features/metaplaylist.js +7 -1
  157. package/dist/es2017/experimental/features/multi_thread.d.ts.map +1 -1
  158. package/dist/es2017/experimental/features/multi_thread.js +6 -2
  159. package/dist/es2017/features/features_object.js +1 -1
  160. package/dist/es2017/features/list/dash.d.ts.map +1 -1
  161. package/dist/es2017/features/list/dash.js +7 -1
  162. package/dist/es2017/features/list/dash_wasm.d.ts.map +1 -1
  163. package/dist/es2017/features/list/dash_wasm.js +7 -1
  164. package/dist/es2017/features/list/media_source_main.d.ts.map +1 -1
  165. package/dist/es2017/features/list/media_source_main.js +7 -1
  166. package/dist/es2017/features/list/smooth.d.ts.map +1 -1
  167. package/dist/es2017/features/list/smooth.js +7 -1
  168. package/dist/es2017/features/types.d.ts +20 -4
  169. package/dist/es2017/features/types.d.ts.map +1 -1
  170. package/dist/es2017/main_thread/api/public_api.d.ts.map +1 -1
  171. package/dist/es2017/main_thread/api/public_api.js +40 -43
  172. package/dist/es2017/main_thread/core_interface/base.d.ts +13 -0
  173. package/dist/es2017/main_thread/core_interface/base.d.ts.map +1 -0
  174. package/dist/es2017/main_thread/core_interface/base.js +28 -0
  175. package/dist/es2017/main_thread/core_interface/monothread.d.ts +13 -0
  176. package/dist/es2017/main_thread/core_interface/monothread.d.ts.map +1 -0
  177. package/dist/es2017/main_thread/core_interface/monothread.js +32 -0
  178. package/dist/es2017/main_thread/core_interface/multithread.d.ts +25 -0
  179. package/dist/es2017/main_thread/core_interface/multithread.d.ts.map +1 -0
  180. package/dist/es2017/main_thread/core_interface/multithread.js +45 -0
  181. package/dist/es2017/main_thread/core_interface/types.d.ts +6 -0
  182. package/dist/es2017/main_thread/core_interface/types.d.ts.map +1 -0
  183. package/dist/es2017/main_thread/core_interface/types.js +1 -0
  184. package/dist/es2017/main_thread/init/media_source_content_initializer.d.ts +166 -108
  185. package/dist/es2017/main_thread/init/media_source_content_initializer.d.ts.map +1 -1
  186. package/dist/es2017/main_thread/init/media_source_content_initializer.js +1405 -760
  187. package/dist/es2017/main_thread/init/utils/create_core_playback_observer.d.ts.map +1 -1
  188. package/dist/es2017/main_thread/init/utils/create_core_playback_observer.js +2 -1
  189. package/dist/es2017/main_thread/init/utils/update_manifest_codec_support.d.ts +1 -1
  190. package/dist/es2017/main_thread/init/utils/update_manifest_codec_support.d.ts.map +1 -1
  191. package/dist/es2017/main_thread/types.d.ts +537 -0
  192. package/dist/es2017/main_thread/types.d.ts.map +1 -1
  193. package/dist/es2017/manifest/utils.d.ts.map +1 -1
  194. package/dist/es2017/manifest/utils.js +16 -4
  195. package/dist/es2017/mse/worker_media_source_interface.d.ts +2 -2
  196. package/dist/es2017/mse/worker_media_source_interface.d.ts.map +1 -1
  197. package/dist/es2017/mse/worker_media_source_interface.js +12 -12
  198. package/dist/es2017/parsers/manifest/smooth/create_parser.d.ts +1 -1
  199. package/dist/es2017/parsers/manifest/smooth/create_parser.d.ts.map +1 -1
  200. package/dist/es2017/parsers/manifest/smooth/create_parser.js +31 -27
  201. package/dist/es2017/parsers/manifest/smooth/parse_C_nodes.d.ts +3 -2
  202. package/dist/es2017/parsers/manifest/smooth/parse_C_nodes.d.ts.map +1 -1
  203. package/dist/es2017/parsers/manifest/smooth/parse_C_nodes.js +16 -7
  204. package/dist/es2017/parsers/manifest/smooth/parse_protection_node.d.ts +3 -2
  205. package/dist/es2017/parsers/manifest/smooth/parse_protection_node.d.ts.map +1 -1
  206. package/dist/es2017/parsers/manifest/smooth/parse_protection_node.js +15 -6
  207. package/dist/es2017/parsers/manifest/smooth/utils/parseBoolean.d.ts +1 -1
  208. package/dist/es2017/parsers/manifest/smooth/utils/parseBoolean.d.ts.map +1 -1
  209. package/dist/es2017/parsers/manifest/smooth/utils/reduceChildren.d.ts +3 -2
  210. package/dist/es2017/parsers/manifest/smooth/utils/reduceChildren.d.ts.map +1 -1
  211. package/dist/es2017/parsers/manifest/smooth/utils/reduceChildren.js +6 -5
  212. package/dist/{commonjs/playback_observer/worker_playback_observer.d.ts → es2017/playback_observer/core_playback_observer.d.ts} +8 -8
  213. package/dist/es2017/playback_observer/core_playback_observer.d.ts.map +1 -0
  214. package/dist/es2017/playback_observer/{worker_playback_observer.js → core_playback_observer.js} +2 -2
  215. package/dist/es2017/transports/smooth/pipelines.d.ts.map +1 -1
  216. package/dist/es2017/transports/smooth/pipelines.js +25 -3
  217. package/dist/es2017/worker_entry_point.js +62 -2
  218. package/dist/rx-player.js +21882 -19021
  219. package/dist/rx-player.min.js +20 -20
  220. package/dist/worker.js +8 -8
  221. package/package.json +1 -1
  222. package/src/README.md +88 -198
  223. package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
  224. package/src/core/{main/common → entry}/FreezeResolver.ts +7 -7
  225. package/src/core/{main → entry}/README.md +1 -1
  226. package/src/core/{main/worker → entry}/content_preparer.ts +77 -76
  227. package/src/core/{main/common → entry}/content_time_boundaries_observer.ts +10 -10
  228. package/src/core/{main/worker/worker_main.ts → entry/core_entry.ts} +223 -149
  229. package/src/core/{main/worker/worker_text_displayer_interface.ts → entry/core_text_displayer_interface.ts} +26 -26
  230. package/src/core/{main/common → entry}/create_content_time_boundaries_observer.ts +7 -7
  231. package/src/core/{main/common → entry}/get_buffered_data_per_media_buffer.ts +6 -6
  232. package/src/core/{main/common → entry}/get_thumbnail_data.ts +5 -5
  233. package/src/core/entry/index.ts +4 -0
  234. package/src/core/{main/common → entry}/synchronize_sinks_on_observation.ts +2 -2
  235. package/src/core/{main/worker → entry}/track_choice_setter.ts +7 -7
  236. package/src/core/entry/utils.ts +11 -0
  237. package/src/core/stream/orchestrator/stream_orchestrator.ts +26 -1
  238. package/src/core/types.ts +631 -3
  239. package/src/experimental/features/__tests__/local.test.ts +11 -2
  240. package/src/experimental/features/__tests__/metaplaylist.test.ts +11 -2
  241. package/src/experimental/features/__tests__/multi_thread.test.ts +8 -3
  242. package/src/experimental/features/local.ts +7 -1
  243. package/src/experimental/features/metaplaylist.ts +7 -1
  244. package/src/experimental/features/multi_thread.ts +6 -2
  245. package/src/features/features_object.ts +1 -1
  246. package/src/features/list/__tests__/dash.test.ts +12 -3
  247. package/src/features/list/__tests__/smooth.test.ts +11 -2
  248. package/src/features/list/dash.ts +7 -1
  249. package/src/features/list/dash_wasm.ts +7 -1
  250. package/src/features/list/media_source_main.ts +7 -1
  251. package/src/features/list/smooth.ts +7 -1
  252. package/src/features/types.ts +23 -4
  253. package/src/main_thread/README.md +8 -0
  254. package/src/main_thread/api/public_api.ts +46 -48
  255. package/src/main_thread/core_interface/README.md +22 -0
  256. package/src/main_thread/core_interface/base.ts +36 -0
  257. package/src/main_thread/core_interface/monothread.ts +46 -0
  258. package/src/main_thread/core_interface/multithread.ts +49 -0
  259. package/src/main_thread/core_interface/types.ts +5 -0
  260. package/src/main_thread/init/media_source_content_initializer.ts +2034 -1152
  261. package/src/main_thread/init/utils/create_core_playback_observer.ts +2 -1
  262. package/src/main_thread/init/utils/update_manifest_codec_support.ts +1 -1
  263. package/src/main_thread/types.ts +610 -0
  264. package/src/manifest/utils.ts +20 -4
  265. package/src/mse/worker_media_source_interface.ts +35 -35
  266. package/src/parsers/manifest/smooth/create_parser.ts +40 -34
  267. package/src/parsers/manifest/smooth/parse_C_nodes.ts +19 -8
  268. package/src/parsers/manifest/smooth/parse_protection_node.ts +17 -9
  269. package/src/parsers/manifest/smooth/utils/parseBoolean.ts +1 -1
  270. package/src/parsers/manifest/smooth/utils/reduceChildren.ts +10 -7
  271. package/src/playback_observer/{worker_playback_observer.ts → core_playback_observer.ts} +13 -13
  272. package/src/transports/smooth/pipelines.ts +25 -5
  273. package/src/worker_entry_point.ts +71 -2
  274. package/dist/commonjs/core/main/common/FreezeResolver.d.ts.map +0 -1
  275. package/dist/commonjs/core/main/common/content_time_boundaries_observer.d.ts.map +0 -1
  276. package/dist/commonjs/core/main/common/create_content_time_boundaries_observer.d.ts.map +0 -1
  277. package/dist/commonjs/core/main/common/get_buffered_data_per_media_buffer.d.ts.map +0 -1
  278. package/dist/commonjs/core/main/common/get_thumbnail_data.d.ts.map +0 -1
  279. package/dist/commonjs/core/main/common/synchronize_sinks_on_observation.d.ts.map +0 -1
  280. package/dist/commonjs/core/main/worker/content_preparer.d.ts.map +0 -1
  281. package/dist/commonjs/core/main/worker/globals.d.ts +0 -14
  282. package/dist/commonjs/core/main/worker/globals.d.ts.map +0 -1
  283. package/dist/commonjs/core/main/worker/globals.js +0 -26
  284. package/dist/commonjs/core/main/worker/index.d.ts +0 -3
  285. package/dist/commonjs/core/main/worker/index.d.ts.map +0 -1
  286. package/dist/commonjs/core/main/worker/index.js +0 -4
  287. package/dist/commonjs/core/main/worker/send_message.d.ts +0 -4
  288. package/dist/commonjs/core/main/worker/send_message.d.ts.map +0 -1
  289. package/dist/commonjs/core/main/worker/send_message.js +0 -23
  290. package/dist/commonjs/core/main/worker/track_choice_setter.d.ts.map +0 -1
  291. package/dist/commonjs/core/main/worker/worker_main.d.ts +0 -2
  292. package/dist/commonjs/core/main/worker/worker_main.d.ts.map +0 -1
  293. package/dist/commonjs/core/main/worker/worker_text_displayer_interface.d.ts.map +0 -1
  294. package/dist/commonjs/main_thread/init/multi_thread_content_initializer.d.ts +0 -308
  295. package/dist/commonjs/main_thread/init/multi_thread_content_initializer.d.ts.map +0 -1
  296. package/dist/commonjs/main_thread/init/multi_thread_content_initializer.js +0 -1713
  297. package/dist/commonjs/main_thread/init/send_message.d.ts +0 -3
  298. package/dist/commonjs/main_thread/init/send_message.d.ts.map +0 -1
  299. package/dist/commonjs/main_thread/init/send_message.js +0 -13
  300. package/dist/commonjs/multithread_types.d.ts +0 -915
  301. package/dist/commonjs/multithread_types.d.ts.map +0 -1
  302. package/dist/commonjs/multithread_types.js +0 -7
  303. package/dist/commonjs/playback_observer/worker_playback_observer.d.ts.map +0 -1
  304. package/dist/es2017/core/main/common/FreezeResolver.d.ts.map +0 -1
  305. package/dist/es2017/core/main/common/content_time_boundaries_observer.d.ts.map +0 -1
  306. package/dist/es2017/core/main/common/create_content_time_boundaries_observer.d.ts.map +0 -1
  307. package/dist/es2017/core/main/common/get_buffered_data_per_media_buffer.d.ts.map +0 -1
  308. package/dist/es2017/core/main/common/get_thumbnail_data.d.ts.map +0 -1
  309. package/dist/es2017/core/main/common/synchronize_sinks_on_observation.d.ts.map +0 -1
  310. package/dist/es2017/core/main/worker/content_preparer.d.ts.map +0 -1
  311. package/dist/es2017/core/main/worker/globals.d.ts +0 -14
  312. package/dist/es2017/core/main/worker/globals.d.ts.map +0 -1
  313. package/dist/es2017/core/main/worker/globals.js +0 -18
  314. package/dist/es2017/core/main/worker/index.d.ts +0 -3
  315. package/dist/es2017/core/main/worker/index.d.ts.map +0 -1
  316. package/dist/es2017/core/main/worker/index.js +0 -2
  317. package/dist/es2017/core/main/worker/send_message.d.ts +0 -4
  318. package/dist/es2017/core/main/worker/send_message.d.ts.map +0 -1
  319. package/dist/es2017/core/main/worker/send_message.js +0 -19
  320. package/dist/es2017/core/main/worker/track_choice_setter.d.ts.map +0 -1
  321. package/dist/es2017/core/main/worker/worker_main.d.ts +0 -2
  322. package/dist/es2017/core/main/worker/worker_main.d.ts.map +0 -1
  323. package/dist/es2017/core/main/worker/worker_text_displayer_interface.d.ts.map +0 -1
  324. package/dist/es2017/main_thread/init/multi_thread_content_initializer.d.ts +0 -308
  325. package/dist/es2017/main_thread/init/multi_thread_content_initializer.d.ts.map +0 -1
  326. package/dist/es2017/main_thread/init/multi_thread_content_initializer.js +0 -1559
  327. package/dist/es2017/main_thread/init/send_message.d.ts +0 -3
  328. package/dist/es2017/main_thread/init/send_message.d.ts.map +0 -1
  329. package/dist/es2017/main_thread/init/send_message.js +0 -10
  330. package/dist/es2017/multithread_types.d.ts +0 -915
  331. package/dist/es2017/multithread_types.d.ts.map +0 -1
  332. package/dist/es2017/multithread_types.js +0 -6
  333. package/dist/es2017/playback_observer/worker_playback_observer.d.ts.map +0 -1
  334. package/src/core/main/worker/globals.ts +0 -38
  335. package/src/core/main/worker/index.ts +0 -2
  336. package/src/core/main/worker/send_message.ts +0 -28
  337. package/src/main_thread/init/multi_thread_content_initializer.ts +0 -2330
  338. package/src/main_thread/init/send_message.ts +0 -15
  339. package/src/multithread_types.ts +0 -1095
  340. /package/dist/commonjs/core/{main/common → entry}/synchronize_sinks_on_observation.js +0 -0
  341. /package/dist/es2017/core/{main/common → entry}/synchronize_sinks_on_observation.js +0 -0
@@ -1,63 +1,32 @@
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
- import isCodecSupported from "../../compat/is_codec_supported";
1
+ import getEmeApiImplementation from "../../compat/eme";
17
2
  import mayMediaElementFailOnUndecipherableData from "../../compat/may_media_element_fail_on_undecipherable_data";
18
3
  import shouldReloadMediaSourceOnDecipherabilityUpdate from "../../compat/should_reload_media_source_on_decipherability_update";
19
- import config from "../../config";
20
- import AdaptiveRepresentationSelector from "../../core/adaptive";
21
- import CmcdDataBuilder from "../../core/cmcd";
22
- import { CdnPrioritizer, createThumbnailFetcher, ManifestFetcher, SegmentQueueCreator, } from "../../core/fetchers";
23
- import createContentTimeBoundariesObserver from "../../core/main/common/create_content_time_boundaries_observer";
24
- import FreezeResolver from "../../core/main/common/FreezeResolver";
25
- import getThumbnailData from "../../core/main/common/get_thumbnail_data";
26
- import synchronizeSegmentSinksOnObservation from "../../core/main/common/synchronize_sinks_on_observation";
27
- import SegmentSinksStore from "../../core/segment_sinks";
28
- import StreamOrchestrator from "../../core/stream";
29
- import { MediaError } from "../../errors";
4
+ import { EncryptedMediaError, MediaError, NetworkError, OtherError, SourceBufferError, } from "../../errors";
30
5
  import features from "../../features";
31
6
  import log from "../../log";
32
- import areArraysOfNumbersEqual from "../../utils/are_arrays_of_numbers_equal";
7
+ import { replicateUpdatesOnManifestMetadata, updateDecipherabilityFromKeyIds, updateDecipherabilityFromProtectionData, } from "../../manifest";
8
+ import MainMediaSourceInterface from "../../mse/main_media_source_interface";
9
+ import arrayFind from "../../utils/array_find";
33
10
  import assert, { assertUnreachable } from "../../utils/assert";
34
- import createCancellablePromise from "../../utils/create_cancellable_promise";
11
+ import idGenerator from "../../utils/id_generator";
35
12
  import isNullOrUndefined from "../../utils/is_null_or_undefined";
36
- import noop from "../../utils/noop";
37
13
  import objectAssign from "../../utils/object_assign";
38
- import SyncOrAsync from "../../utils/sync_or_async";
39
- import TaskCanceller from "../../utils/task_canceller";
14
+ import SharedReference from "../../utils/reference";
15
+ import { RequestError } from "../../utils/request";
16
+ import TaskCanceller, { CancellationError } from "../../utils/task_canceller";
40
17
  import { ContentDecryptorState, getKeySystemConfiguration } from "../decrypt";
41
18
  import { ContentInitializer } from "./types";
42
19
  import createCorePlaybackObserver from "./utils/create_core_playback_observer";
43
- import createMediaSource from "./utils/create_media_source";
20
+ import { resetMediaElement, disableRemotePlaybackOnManagedMediaSource, } from "./utils/create_media_source";
44
21
  import getInitialTime from "./utils/get_initial_time";
45
22
  import getLoadedReference from "./utils/get_loaded_reference";
46
23
  import performInitialSeekAndPlay from "./utils/initial_seek_and_play";
47
- import initializeContentDecryption from "./utils/initialize_content_decryption";
48
- import MainThreadTextDisplayerInterface from "./utils/main_thread_text_displayer_interface";
49
24
  import RebufferingController from "./utils/rebuffering_controller";
50
- import StreamEventsEmitter from "./utils/stream_events_emitter";
25
+ import StreamEventsEmitter from "./utils/stream_events_emitter/stream_events_emitter";
51
26
  import listenToMediaError from "./utils/throw_on_media_error";
27
+ import { updateManifestCodecSupport } from "./utils/update_manifest_codec_support";
28
+ const generateContentId = idGenerator();
52
29
  /**
53
- * Allows to load a new content thanks to the MediaSource Extensions (a.k.a. MSE)
54
- * Web APIs.
55
- *
56
- * Through this `ContentInitializer`, a Manifest will be fetched (and depending
57
- * on the situation, refreshed), a `MediaSource` instance will be linked to the
58
- * wanted `HTMLMediaElement` and chunks of media data, called segments, will be
59
- * pushed on buffers associated to this `MediaSource` instance.
60
- *
61
30
  * @class MediaSourceContentInitializer
62
31
  */
63
32
  export default class MediaSourceContentInitializer extends ContentInitializer {
@@ -68,51 +37,146 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
68
37
  */
69
38
  constructor(settings) {
70
39
  super();
71
- this._initSettings = settings;
40
+ this._settings = settings;
72
41
  this._initCanceller = new TaskCanceller();
73
- this._manifest = null;
74
- this._decryptionCapabilities = { status: "uninitialized", value: null };
75
- const urls = settings.url === undefined ? undefined : [settings.url];
76
- this._cmcdDataBuilder =
77
- settings.cmcd === undefined ? null : new CmcdDataBuilder(settings.cmcd);
78
- this._manifestFetcher = new ManifestFetcher(urls, settings.transport, Object.assign(Object.assign({}, settings.manifestRequestSettings), { lowLatencyMode: settings.lowLatencyMode, cmcdDataBuilder: this._cmcdDataBuilder }));
42
+ this._currentMediaSourceCanceller = new TaskCanceller();
43
+ this._currentMediaSourceCanceller.linkToSignal(this._initCanceller.signal);
44
+ this._currentContentInfo = null;
45
+ this._awaitingRequests = {
46
+ nextRequestId: 0,
47
+ pendingSinkMetrics: new Map(),
48
+ pendingThumbnailFetching: new Map(),
49
+ };
50
+ this._queuedCoreMessages = null;
79
51
  }
80
52
  /**
81
53
  * Perform non-destructive preparation steps, to prepare a future content.
82
- * For now, this mainly mean loading the Manifest document.
83
54
  */
84
55
  prepare() {
85
- if (this._manifest !== null) {
56
+ var _a, _b;
57
+ if (this._currentContentInfo !== null || this._initCanceller.isUsed()) {
86
58
  return;
87
59
  }
88
- this._manifest = SyncOrAsync.createAsync(createCancellablePromise(this._initCanceller.signal, (res, rej) => {
89
- this._manifestFetcher.addEventListener("warning", (err) => this.trigger("warning", err));
90
- this._manifestFetcher.addEventListener("error", (err) => {
91
- this.trigger("error", err);
92
- rej(err);
93
- });
94
- this._manifestFetcher.addEventListener("manifestReady", (manifest) => {
95
- res(manifest);
60
+ const contentId = generateContentId();
61
+ const { adaptiveOptions, transport, transportOptions, useMseInWorker, coreInterface, } = this._settings;
62
+ const { wantedBufferAhead, maxVideoBufferSize, maxBufferAhead, maxBufferBehind } = this._settings.bufferOptions;
63
+ const initialVideoBitrate = adaptiveOptions.initialBitrates.video;
64
+ const initialAudioBitrate = adaptiveOptions.initialBitrates.audio;
65
+ this._currentContentInfo = {
66
+ contentId,
67
+ contentDecryptor: null,
68
+ manifest: null,
69
+ mediaSourceInfo: null,
70
+ rebufferingController: null,
71
+ streamEventsEmitter: null,
72
+ initialTime: undefined,
73
+ autoPlay: undefined,
74
+ initialPlayPerformed: null,
75
+ useMseInWorker,
76
+ };
77
+ coreInterface.sendMessage({
78
+ type: "prepare" /* MainThreadMessageType.PrepareContent */,
79
+ value: {
80
+ contentId,
81
+ cmcd: this._settings.cmcd,
82
+ enableRepresentationAvoidance: this._settings.enableRepresentationAvoidance,
83
+ url: this._settings.url,
84
+ hasText: this._hasTextBufferFeature(),
85
+ transport,
86
+ transportOptions,
87
+ initialVideoBitrate,
88
+ initialAudioBitrate,
89
+ manifestRetryOptions: Object.assign(Object.assign({}, this._settings.manifestRequestSettings), { lowLatencyMode: this._settings.lowLatencyMode }),
90
+ segmentRetryOptions: this._settings.segmentRequestOptions,
91
+ useMseInWorker,
92
+ },
93
+ });
94
+ this._initCanceller.signal.register(() => {
95
+ coreInterface.sendMessage({
96
+ type: "stop" /* MainThreadMessageType.StopContent */,
97
+ contentId,
98
+ value: null,
96
99
  });
97
- }));
98
- this._manifestFetcher.start();
100
+ });
101
+ if (this._initCanceller.isUsed()) {
102
+ return;
103
+ }
104
+ this._queuedCoreMessages = [];
105
+ log.debug("Init", "addEventListener prepare buffering core messages");
106
+ const onmessage = (msgData) => {
107
+ if (msgData.type !== "log" /* CoreMessageType.LogMessage */) {
108
+ log.debug("Init", "Core message received", msgData.type);
109
+ }
110
+ const type = msgData.type;
111
+ switch (type) {
112
+ case "log" /* CoreMessageType.LogMessage */: {
113
+ const formatted = msgData.value.logs.map((l) => {
114
+ switch (typeof l) {
115
+ case "string":
116
+ case "number":
117
+ case "boolean":
118
+ case "undefined":
119
+ return l;
120
+ case "object":
121
+ if (l === null) {
122
+ return null;
123
+ }
124
+ return formatSentLogObject(l);
125
+ default:
126
+ assertUnreachable(l);
127
+ }
128
+ });
129
+ switch (msgData.value.logLevel) {
130
+ case "NONE":
131
+ break;
132
+ case "ERROR":
133
+ log.error(msgData.value.namespace, ...formatted);
134
+ break;
135
+ case "WARNING":
136
+ log.warn(msgData.value.namespace, ...formatted);
137
+ break;
138
+ case "INFO":
139
+ log.info(msgData.value.namespace, ...formatted);
140
+ break;
141
+ case "DEBUG":
142
+ log.debug(msgData.value.namespace, ...formatted);
143
+ break;
144
+ default:
145
+ assertUnreachable(msgData.value.logLevel);
146
+ }
147
+ break;
148
+ }
149
+ default:
150
+ if (this._queuedCoreMessages !== null) {
151
+ this._queuedCoreMessages.push(msgData);
152
+ }
153
+ break;
154
+ }
155
+ };
156
+ this._settings.coreInterface.addMessageListener(onmessage);
157
+ const onmessageerror = () => {
158
+ log.error("Init", "Error when receiving message from core.");
159
+ };
160
+ this._settings.coreInterface.addErrorListener(onmessageerror);
99
161
  this._initCanceller.signal.register(() => {
100
- this._manifestFetcher.dispose();
162
+ log.debug("Init", "removeEventListener prepare for core message");
163
+ this._settings.coreInterface.removeMessageListener(onmessage);
164
+ this._settings.coreInterface.removeErrorListener(onmessageerror);
101
165
  });
102
- }
103
- /**
104
- * @param {HTMLMediaElement} mediaElement
105
- * @param {Object} playbackObserver
106
- */
107
- start(mediaElement, playbackObserver) {
108
- this.prepare(); // Load Manifest if not already done
109
- /** Translate errors coming from the media element into RxPlayer errors. */
110
- listenToMediaError(mediaElement, (error) => this._onFatalError(error), this._initCanceller.signal);
111
- this._setupInitialMediaSourceAndDecryption(mediaElement)
112
- .then((initResult) => this._onInitialMediaSourceReady(mediaElement, initResult.mediaSource, playbackObserver, initResult.drmSystemId, initResult.unlinkMediaSource))
113
- .catch((err) => {
114
- this._onFatalError(err);
166
+ // Also bind all `SharedReference` objects:
167
+ const throttleVideoBitrate = (_a = adaptiveOptions.throttlers.throttleBitrate.video) !== null && _a !== void 0 ? _a : new SharedReference(Infinity);
168
+ bindNumberReferencesToCore(coreInterface, this._initCanceller.signal, [wantedBufferAhead, "wantedBufferAhead"], [maxVideoBufferSize, "maxVideoBufferSize"], [maxBufferAhead, "maxBufferAhead"], [maxBufferBehind, "maxBufferBehind"], [throttleVideoBitrate, "throttleVideoBitrate"]);
169
+ const limitVideoResolution = (_b = adaptiveOptions.throttlers.limitResolution.video) !== null && _b !== void 0 ? _b : new SharedReference({
170
+ height: undefined,
171
+ width: undefined,
172
+ pixelRatio: 1,
115
173
  });
174
+ limitVideoResolution.onUpdate((newVal) => {
175
+ coreInterface.sendMessage({
176
+ type: "ref-update" /* MainThreadMessageType.ReferenceUpdate */,
177
+ value: { name: "limitVideoResolution", newVal },
178
+ });
179
+ }, { clearSignal: this._initCanceller.signal, emitCurrentValue: true });
116
180
  }
117
181
  /**
118
182
  * Update URL of the Manifest.
@@ -122,275 +186,1068 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
122
186
  * DASH's MPD) will be refreshed immediately.
123
187
  */
124
188
  updateContentUrls(urls, refreshNow) {
125
- this._manifestFetcher.updateContentUrls(urls, refreshNow);
126
- }
127
- /**
128
- * Stop content and free all resources linked to this
129
- * `MediaSourceContentInitializer`.
130
- */
131
- dispose() {
132
- this._initCanceller.cancel();
189
+ if (this._currentContentInfo === null) {
190
+ return;
191
+ }
192
+ this._settings.coreInterface.sendMessage({
193
+ type: "urls-update" /* MainThreadMessageType.ContentUrlsUpdate */,
194
+ contentId: this._currentContentInfo.contentId,
195
+ value: { urls, refreshNow },
196
+ });
133
197
  }
134
198
  /**
135
- * Callback called when an error interrupting playback arised.
136
- * @param {*} err
199
+ * @param {HTMLMediaElement} mediaElement
200
+ * @param {Object} playbackObserver
137
201
  */
138
- _onFatalError(err) {
202
+ start(mediaElement, playbackObserver) {
203
+ this.prepare(); // Load Manifest if not already done
139
204
  if (this._initCanceller.isUsed()) {
140
205
  return;
141
206
  }
142
- this._initCanceller.cancel();
143
- this.trigger("error", err);
144
- }
145
- /**
146
- * Initialize decryption mechanisms if needed and begin creating and relying
147
- * on the initial `MediaSourceInterface` for this content.
148
- * @param {HTMLMediaElement|null} mediaElement
149
- * @returns {Promise.<Object>}
150
- */
151
- _setupInitialMediaSourceAndDecryption(mediaElement) {
152
- const initCanceller = this._initCanceller;
153
- return createCancellablePromise(initCanceller.signal, (resolve) => {
154
- const { keySystems } = this._initSettings;
155
- /** Initialize decryption capabilities. */
156
- const { statusRef: drmInitRef, contentDecryptor } = initializeContentDecryption(mediaElement, keySystems, {
157
- onWarning: (err) => this.trigger("warning", err),
158
- onError: (err) => this._onFatalError(err),
159
- onBlackListProtectionData: (val) => {
160
- // Ugly IIFE workaround to allow async event listener
161
- (async () => {
162
- var _a;
163
- if (this._manifest === null) {
207
+ let textDisplayer = null;
208
+ if (this._settings.textTrackOptions.textTrackMode === "html" &&
209
+ features.htmlTextDisplayer !== null) {
210
+ assert(this._hasTextBufferFeature());
211
+ textDisplayer = new features.htmlTextDisplayer(mediaElement, this._settings.textTrackOptions.textTrackElement);
212
+ }
213
+ else if (features.nativeTextDisplayer !== null) {
214
+ assert(this._hasTextBufferFeature());
215
+ textDisplayer = new features.nativeTextDisplayer(mediaElement);
216
+ }
217
+ else {
218
+ assert(!this._hasTextBufferFeature());
219
+ }
220
+ this._initCanceller.signal.register(() => {
221
+ textDisplayer === null || textDisplayer === void 0 ? void 0 : textDisplayer.stop();
222
+ });
223
+ /** Translate errors coming from the media element into RxPlayer errors. */
224
+ listenToMediaError(mediaElement, (error) => this._onFatalError(error), this._initCanceller.signal);
225
+ /**
226
+ * Send content protection initialization data.
227
+ * TODO remove and use ContentDecryptor directly when possible.
228
+ */
229
+ const lastContentProtection = new SharedReference(null);
230
+ const mediaSourceStatus = new SharedReference(0 /* MediaSourceInitializationStatus.Nothing */);
231
+ const { statusRef: drmInitializationStatus, contentDecryptor } = this._initializeContentDecryption(mediaElement, lastContentProtection, mediaSourceStatus, () => notifyAndStartMediaSourceReload(0, undefined, undefined), this._initCanceller.signal);
232
+ const contentInfo = this._currentContentInfo;
233
+ if (contentInfo !== null) {
234
+ contentInfo.contentDecryptor = contentDecryptor;
235
+ }
236
+ const playbackStartParams = {
237
+ mediaElement,
238
+ textDisplayer,
239
+ playbackObserver,
240
+ drmInitializationStatus,
241
+ mediaSourceStatus,
242
+ };
243
+ mediaSourceStatus.onUpdate((msInitStatus, stopListeningMSStatus) => {
244
+ if (msInitStatus === 2 /* MediaSourceInitializationStatus.Attached */) {
245
+ stopListeningMSStatus();
246
+ this._startPlaybackIfReady(playbackStartParams);
247
+ }
248
+ }, { clearSignal: this._initCanceller.signal, emitCurrentValue: true });
249
+ drmInitializationStatus.onUpdate((initializationStatus, stopListeningDrm) => {
250
+ if (initializationStatus.initializationState.type === "initialized") {
251
+ stopListeningDrm();
252
+ this._startPlaybackIfReady(playbackStartParams);
253
+ }
254
+ }, { emitCurrentValue: true, clearSignal: this._initCanceller.signal });
255
+ /**
256
+ * Reset directly (synchronously) the current `MediaSource` and signal to
257
+ * the core that we did so.
258
+ * @param {number} deltaPosition - Position you want to seek to after
259
+ * reloading, as a delta in seconds from the last polled playing position.
260
+ * @param {number|undefined} minimumPosition - If set, minimum time bound
261
+ * in seconds after `deltaPosition` has been applied.
262
+ * @param {number|undefined} maximumPosition - If set, minimum time bound
263
+ * in seconds after `deltaPosition` has been applied.
264
+ */
265
+ const notifyAndStartMediaSourceReload = (deltaPosition, minimumPosition, maximumPosition) => {
266
+ const reloadingContentInfo = this._currentContentInfo;
267
+ if (reloadingContentInfo === null) {
268
+ log.warn("Init", "Asked to reload when no content is loaded.");
269
+ return;
270
+ }
271
+ if (reloadingContentInfo === null ||
272
+ reloadingContentInfo.mediaSourceInfo === null) {
273
+ log.warn("Init", "Asked to reload when no MediaSource is active.");
274
+ return;
275
+ }
276
+ const mediaSourceId = reloadingContentInfo.mediaSourceInfo.type === "main"
277
+ ? reloadingContentInfo.mediaSourceInfo.mediaSource.id
278
+ : reloadingContentInfo.mediaSourceInfo.mediaSourceId;
279
+ this._settings.coreInterface.sendMessage({
280
+ type: "ms-reload" /* MainThreadMessageType.MediaSourceReload */,
281
+ mediaSourceId,
282
+ value: null,
283
+ });
284
+ reloadMediaSource(deltaPosition, minimumPosition, maximumPosition);
285
+ };
286
+ /**
287
+ * Reset directly (synchronously) the current `MediaSource`.
288
+ *
289
+ * It is assumed that `core` already knows about this action. If not, call
290
+ * `notifyAndStartMediaSourceReload` instead.
291
+ * @param {number} deltaPosition - Position you want to seek to after
292
+ * reloading, as a delta in seconds from the last polled playing position.
293
+ * @param {number|undefined} minimumPosition - If set, minimum time bound
294
+ * in seconds after `deltaPosition` has been applied.
295
+ * @param {number|undefined} maximumPosition - If set, minimum time bound
296
+ * in seconds after `deltaPosition` has been applied.
297
+ */
298
+ const reloadMediaSource = (deltaPosition, minimumPosition, maximumPosition) => {
299
+ var _a;
300
+ const reloadingContentInfo = this._currentContentInfo;
301
+ if (reloadingContentInfo === null) {
302
+ log.warn("Init", "Asked to reload when no content is loaded.");
303
+ return;
304
+ }
305
+ const lastObservation = playbackObserver.getReference().getValue();
306
+ const currentPosition = lastObservation.position.getWanted();
307
+ const isPaused = ((_a = reloadingContentInfo.initialPlayPerformed) === null || _a === void 0 ? void 0 : _a.getValue()) === true ||
308
+ reloadingContentInfo.autoPlay === undefined
309
+ ? lastObservation.paused
310
+ : !reloadingContentInfo.autoPlay;
311
+ let position = currentPosition + deltaPosition;
312
+ if (minimumPosition !== undefined) {
313
+ position = Math.max(minimumPosition, position);
314
+ }
315
+ if (maximumPosition !== undefined) {
316
+ position = Math.min(maximumPosition, position);
317
+ }
318
+ this._reload(mediaElement, textDisplayer, playbackObserver, mediaSourceStatus, position, !isPaused);
319
+ };
320
+ const onmessage = (msgData) => {
321
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28;
322
+ switch (msgData.type) {
323
+ case "attach-media-source" /* CoreMessageType.AttachMediaSource */: {
324
+ if (((_a = this._currentContentInfo) === null || _a === void 0 ? void 0 : _a.contentId) !== msgData.contentId) {
325
+ return;
326
+ }
327
+ if (this._currentContentInfo !== null) {
328
+ if (((_b = this._currentContentInfo.mediaSourceInfo) === null || _b === void 0 ? void 0 : _b.type) === "main") {
329
+ this._currentContentInfo.mediaSourceInfo.mediaSource.dispose();
330
+ }
331
+ this._currentContentInfo.mediaSourceInfo = {
332
+ type: "core",
333
+ mediaSourceId: msgData.mediaSourceId,
334
+ };
335
+ }
336
+ const mediaSourceLink = msgData.value;
337
+ mediaSourceStatus.onUpdate((currStatus, stopListening) => {
338
+ if (currStatus === 1 /* MediaSourceInitializationStatus.AttachNow */) {
339
+ stopListening();
340
+ log.info("media", "Attaching MediaSource URL to the media element");
341
+ if (mediaSourceLink.type === "handle") {
342
+ mediaElement.srcObject = mediaSourceLink.value;
343
+ this._currentMediaSourceCanceller.signal.register(() => {
344
+ mediaElement.srcObject = null;
345
+ });
346
+ }
347
+ else {
348
+ mediaElement.src = mediaSourceLink.value;
349
+ this._currentMediaSourceCanceller.signal.register(() => {
350
+ resetMediaElement(mediaElement, mediaSourceLink.value);
351
+ });
352
+ }
353
+ disableRemotePlaybackOnManagedMediaSource(mediaElement, this._currentMediaSourceCanceller.signal);
354
+ mediaSourceStatus.setValue(2 /* MediaSourceInitializationStatus.Attached */);
355
+ }
356
+ }, { emitCurrentValue: true, clearSignal: this._initCanceller.signal });
357
+ break;
358
+ }
359
+ case "warning" /* CoreMessageType.Warning */:
360
+ if (((_c = this._currentContentInfo) === null || _c === void 0 ? void 0 : _c.contentId) !== msgData.contentId) {
361
+ return;
362
+ }
363
+ this.trigger("warning", formatCoreError(msgData.value));
364
+ break;
365
+ case "error" /* CoreMessageType.Error */:
366
+ if (((_d = this._currentContentInfo) === null || _d === void 0 ? void 0 : _d.contentId) !== msgData.contentId) {
367
+ return;
368
+ }
369
+ this._onFatalError(formatCoreError(msgData.value));
370
+ break;
371
+ case "create-media-source" /* CoreMessageType.CreateMediaSource */:
372
+ this._onCreateMediaSourceMessage(msgData, mediaElement, mediaSourceStatus, this._settings.coreInterface);
373
+ break;
374
+ case "add-source-buffer" /* CoreMessageType.AddSourceBuffer */:
375
+ {
376
+ if (((_f = (_e = this._currentContentInfo) === null || _e === void 0 ? void 0 : _e.mediaSourceInfo) === null || _f === void 0 ? void 0 : _f.type) !== "main" ||
377
+ this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
378
+ msgData.mediaSourceId) {
164
379
  return;
165
380
  }
166
- const manifest = (_a = this._manifest.syncValue) !== null && _a !== void 0 ? _a : (await this._manifest.getValueAsAsync());
167
- blackListProtectionDataOnManifest(manifest, val);
168
- })().catch(noop);
169
- },
170
- onKeyIdsCompatibilityUpdate: (updates) => {
171
- // Ugly IIFE workaround to allow async event listener
172
- (async () => {
173
- var _a;
174
- if (this._manifest === null) {
381
+ const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
382
+ mediaSource.addSourceBuffer(msgData.value.sourceBufferType, msgData.value.codec);
383
+ }
384
+ break;
385
+ case "source-buffer-append" /* CoreMessageType.SourceBufferAppend */:
386
+ {
387
+ if (((_h = (_g = this._currentContentInfo) === null || _g === void 0 ? void 0 : _g.mediaSourceInfo) === null || _h === void 0 ? void 0 : _h.type) !== "main" ||
388
+ this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
389
+ msgData.mediaSourceId) {
175
390
  return;
176
391
  }
177
- const manifest = (_a = this._manifest.syncValue) !== null && _a !== void 0 ? _a : (await this._manifest.getValueAsAsync());
178
- updateKeyIdsDecipherabilityOnManifest(manifest, updates.whitelistedKeyIds, updates.blacklistedKeyIds, updates.delistedKeyIds);
179
- })().catch(noop);
180
- },
181
- onCodecSupportUpdate: () => {
182
- var _a, _b;
183
- const syncManifest = (_a = this._manifest) === null || _a === void 0 ? void 0 : _a.syncValue;
184
- if (isNullOrUndefined(syncManifest)) {
185
- // The Manifest is not yet fetched, but we will be able to check
186
- // the codecs once it is the case
187
- (_b = this._manifest) === null || _b === void 0 ? void 0 : _b.getValueAsAsync().then((loadedManifest) => {
188
- if (this._initCanceller.isUsed()) {
189
- return;
190
- }
191
- this._refreshManifestCodecSupport(loadedManifest, mediaElement);
192
- }, noop);
392
+ const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
393
+ const sourceBuffer = arrayFind(mediaSource.sourceBuffers, (s) => s.type === msgData.sourceBufferType);
394
+ if (sourceBuffer === undefined) {
395
+ return;
396
+ }
397
+ sourceBuffer
398
+ .appendBuffer(msgData.value.data, msgData.value.params)
399
+ .then((buffered) => {
400
+ this._settings.coreInterface.sendMessage({
401
+ type: "sb-success" /* MainThreadMessageType.SourceBufferSuccess */,
402
+ mediaSourceId: mediaSource.id,
403
+ sourceBufferType: sourceBuffer.type,
404
+ operationId: msgData.operationId,
405
+ value: { buffered },
406
+ });
407
+ })
408
+ .catch((error) => {
409
+ this._settings.coreInterface.sendMessage({
410
+ type: "sb-error" /* MainThreadMessageType.SourceBufferError */,
411
+ mediaSourceId: mediaSource.id,
412
+ sourceBufferType: sourceBuffer.type,
413
+ operationId: msgData.operationId,
414
+ value: error instanceof CancellationError
415
+ ? { errorName: "CancellationError" }
416
+ : formatSourceBufferError(error).serialize(),
417
+ });
418
+ });
419
+ }
420
+ break;
421
+ case "source-buffer-remove" /* CoreMessageType.SourceBufferRemove */:
422
+ {
423
+ if (((_k = (_j = this._currentContentInfo) === null || _j === void 0 ? void 0 : _j.mediaSourceInfo) === null || _k === void 0 ? void 0 : _k.type) !== "main" ||
424
+ this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
425
+ msgData.mediaSourceId) {
426
+ return;
427
+ }
428
+ const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
429
+ const sourceBuffer = arrayFind(mediaSource.sourceBuffers, (s) => s.type === msgData.sourceBufferType);
430
+ if (sourceBuffer === undefined) {
431
+ return;
432
+ }
433
+ sourceBuffer
434
+ .remove(msgData.value.start, msgData.value.end)
435
+ .then((buffered) => {
436
+ this._settings.coreInterface.sendMessage({
437
+ type: "sb-success" /* MainThreadMessageType.SourceBufferSuccess */,
438
+ mediaSourceId: mediaSource.id,
439
+ sourceBufferType: sourceBuffer.type,
440
+ operationId: msgData.operationId,
441
+ value: { buffered },
442
+ });
443
+ })
444
+ .catch((error) => {
445
+ this._settings.coreInterface.sendMessage({
446
+ type: "sb-error" /* MainThreadMessageType.SourceBufferError */,
447
+ mediaSourceId: mediaSource.id,
448
+ sourceBufferType: sourceBuffer.type,
449
+ operationId: msgData.operationId,
450
+ value: error instanceof CancellationError
451
+ ? { errorName: "CancellationError" }
452
+ : formatSourceBufferError(error).serialize(),
453
+ });
454
+ });
455
+ }
456
+ break;
457
+ case "abort-source-buffer" /* CoreMessageType.AbortSourceBuffer */:
458
+ {
459
+ if (((_m = (_l = this._currentContentInfo) === null || _l === void 0 ? void 0 : _l.mediaSourceInfo) === null || _m === void 0 ? void 0 : _m.type) !== "main" ||
460
+ this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
461
+ msgData.mediaSourceId) {
462
+ return;
463
+ }
464
+ const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
465
+ const sourceBuffer = arrayFind(mediaSource.sourceBuffers, (s) => s.type === msgData.sourceBufferType);
466
+ if (sourceBuffer === undefined) {
467
+ return;
468
+ }
469
+ sourceBuffer.abort();
470
+ }
471
+ break;
472
+ case "update-media-source-duration" /* CoreMessageType.UpdateMediaSourceDuration */:
473
+ {
474
+ if (((_p = (_o = this._currentContentInfo) === null || _o === void 0 ? void 0 : _o.mediaSourceInfo) === null || _p === void 0 ? void 0 : _p.type) !== "main" ||
475
+ this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
476
+ msgData.mediaSourceId) {
477
+ return;
478
+ }
479
+ const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
480
+ if ((mediaSource === null || mediaSource === void 0 ? void 0 : mediaSource.id) !== msgData.mediaSourceId) {
481
+ return;
482
+ }
483
+ mediaSource.setDuration(msgData.value.duration, msgData.value.isRealEndKnown);
484
+ }
485
+ break;
486
+ case "stop-media-source-duration" /* CoreMessageType.InterruptMediaSourceDurationUpdate */:
487
+ {
488
+ if (((_r = (_q = this._currentContentInfo) === null || _q === void 0 ? void 0 : _q.mediaSourceInfo) === null || _r === void 0 ? void 0 : _r.type) !== "main" ||
489
+ this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
490
+ msgData.mediaSourceId) {
491
+ return;
492
+ }
493
+ const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
494
+ if ((mediaSource === null || mediaSource === void 0 ? void 0 : mediaSource.id) !== msgData.mediaSourceId) {
495
+ return;
496
+ }
497
+ mediaSource.interruptDurationSetting();
498
+ }
499
+ break;
500
+ case "end-of-stream" /* CoreMessageType.EndOfStream */:
501
+ {
502
+ if (((_t = (_s = this._currentContentInfo) === null || _s === void 0 ? void 0 : _s.mediaSourceInfo) === null || _t === void 0 ? void 0 : _t.type) !== "main" ||
503
+ this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
504
+ msgData.mediaSourceId) {
505
+ return;
506
+ }
507
+ const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
508
+ mediaSource.maintainEndOfStream();
509
+ }
510
+ break;
511
+ case "stop-end-of-stream" /* CoreMessageType.InterruptEndOfStream */:
512
+ {
513
+ if (((_v = (_u = this._currentContentInfo) === null || _u === void 0 ? void 0 : _u.mediaSourceInfo) === null || _v === void 0 ? void 0 : _v.type) !== "main" ||
514
+ this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
515
+ msgData.mediaSourceId) {
516
+ return;
517
+ }
518
+ const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
519
+ mediaSource.stopEndOfStream();
520
+ }
521
+ break;
522
+ case "dispose-media-source" /* CoreMessageType.DisposeMediaSource */:
523
+ {
524
+ if (((_x = (_w = this._currentContentInfo) === null || _w === void 0 ? void 0 : _w.mediaSourceInfo) === null || _x === void 0 ? void 0 : _x.type) !== "main" ||
525
+ this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
526
+ msgData.mediaSourceId) {
527
+ return;
528
+ }
529
+ const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
530
+ mediaSource.dispose();
531
+ }
532
+ break;
533
+ case "needs-buffer-flush" /* CoreMessageType.NeedsBufferFlush */: {
534
+ if (((_y = this._currentContentInfo) === null || _y === void 0 ? void 0 : _y.contentId) !== msgData.contentId) {
535
+ return;
536
+ }
537
+ const lastObservation = playbackObserver.getReference().getValue();
538
+ const currentTime = lastObservation.position.isAwaitingFuturePosition()
539
+ ? lastObservation.position.getWanted()
540
+ : mediaElement.currentTime;
541
+ const relativeResumingPosition = (_0 = (_z = msgData.value) === null || _z === void 0 ? void 0 : _z.relativeResumingPosition) !== null && _0 !== void 0 ? _0 : 0;
542
+ const canBeApproximateSeek = Boolean((_1 = msgData.value) === null || _1 === void 0 ? void 0 : _1.relativePosHasBeenDefaulted);
543
+ let wantedSeekingTime;
544
+ if (relativeResumingPosition === 0 && canBeApproximateSeek) {
545
+ // in case relativeResumingPosition is 0, we still perform
546
+ // a tiny seek to be sure that the browser will correclty reload the video.
547
+ wantedSeekingTime = currentTime + 0.001;
193
548
  }
194
549
  else {
195
- this._refreshManifestCodecSupport(syncManifest, mediaElement);
550
+ wantedSeekingTime = currentTime + relativeResumingPosition;
196
551
  }
197
- },
198
- }, initCanceller.signal);
199
- if (contentDecryptor.enabled) {
200
- this._decryptionCapabilities = {
201
- status: "enabled",
202
- value: contentDecryptor.value,
203
- };
204
- }
205
- else {
206
- this._decryptionCapabilities = {
207
- status: "disabled",
208
- value: contentDecryptor.value,
209
- };
210
- }
211
- drmInitRef.onUpdate((drmStatus, stopListeningToDrmUpdates) => {
212
- if (drmStatus.initializationState.type === "uninitialized") {
213
- return;
552
+ playbackObserver.setCurrentTime(wantedSeekingTime);
553
+ break;
554
+ }
555
+ case "active-period-changed" /* CoreMessageType.ActivePeriodChanged */: {
556
+ if (((_2 = this._currentContentInfo) === null || _2 === void 0 ? void 0 : _2.contentId) !== msgData.contentId ||
557
+ this._currentContentInfo.manifest === null) {
558
+ return;
559
+ }
560
+ const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
561
+ if (period !== undefined) {
562
+ this.trigger("activePeriodChanged", { period });
563
+ }
564
+ break;
214
565
  }
215
- stopListeningToDrmUpdates();
216
- const mediaSourceCanceller = new TaskCanceller();
217
- mediaSourceCanceller.linkToSignal(initCanceller.signal);
218
- createMediaSource(mediaElement, mediaSourceCanceller.signal)
219
- .then((mediaSource) => {
220
- const lastDrmStatus = drmInitRef.getValue();
221
- if (lastDrmStatus.initializationState.type === "awaiting-media-link") {
222
- lastDrmStatus.initializationState.value.isMediaLinked.setValue(true);
223
- drmInitRef.onUpdate((newDrmStatus, stopListeningToDrmUpdatesAgain) => {
224
- if (newDrmStatus.initializationState.type === "initialized") {
225
- stopListeningToDrmUpdatesAgain();
226
- resolve({
227
- mediaSource,
228
- drmSystemId: newDrmStatus.drmSystemId,
229
- unlinkMediaSource: mediaSourceCanceller,
566
+ case "adaptation-changed" /* CoreMessageType.AdaptationChanged */: {
567
+ if (((_3 = this._currentContentInfo) === null || _3 === void 0 ? void 0 : _3.contentId) !== msgData.contentId ||
568
+ this._currentContentInfo.manifest === null) {
569
+ return;
570
+ }
571
+ const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
572
+ if (period === undefined) {
573
+ return;
574
+ }
575
+ if (msgData.value.adaptationId === null) {
576
+ this.trigger("adaptationChange", {
577
+ period,
578
+ adaptation: null,
579
+ type: msgData.value.type,
580
+ });
581
+ return;
582
+ }
583
+ const adaptations = (_4 = period.adaptations[msgData.value.type]) !== null && _4 !== void 0 ? _4 : [];
584
+ const adaptation = arrayFind(adaptations, (a) => a.id === msgData.value.adaptationId);
585
+ if (adaptation !== undefined) {
586
+ this.trigger("adaptationChange", {
587
+ period,
588
+ adaptation,
589
+ type: msgData.value.type,
590
+ });
591
+ }
592
+ break;
593
+ }
594
+ case "representation-changed" /* CoreMessageType.RepresentationChanged */: {
595
+ if (((_5 = this._currentContentInfo) === null || _5 === void 0 ? void 0 : _5.contentId) !== msgData.contentId ||
596
+ this._currentContentInfo.manifest === null) {
597
+ return;
598
+ }
599
+ const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
600
+ if (period === undefined) {
601
+ return;
602
+ }
603
+ if (msgData.value.representationId === null) {
604
+ this.trigger("representationChange", {
605
+ period,
606
+ type: msgData.value.type,
607
+ representation: null,
608
+ });
609
+ return;
610
+ }
611
+ const adaptations = (_6 = period.adaptations[msgData.value.type]) !== null && _6 !== void 0 ? _6 : [];
612
+ const adaptation = arrayFind(adaptations, (a) => a.id === msgData.value.adaptationId);
613
+ if (adaptation === undefined) {
614
+ return;
615
+ }
616
+ const representation = arrayFind(adaptation.representations, (r) => r.id === msgData.value.representationId);
617
+ if (representation !== undefined) {
618
+ this.trigger("representationChange", {
619
+ period,
620
+ type: msgData.value.type,
621
+ representation,
622
+ });
623
+ }
624
+ break;
625
+ }
626
+ case "encryption-data-encountered" /* CoreMessageType.EncryptionDataEncountered */:
627
+ if (((_7 = this._currentContentInfo) === null || _7 === void 0 ? void 0 : _7.contentId) !== msgData.contentId) {
628
+ return;
629
+ }
630
+ lastContentProtection.setValue(msgData.value);
631
+ break;
632
+ case "manifest-ready" /* CoreMessageType.ManifestReady */: {
633
+ if (((_8 = this._currentContentInfo) === null || _8 === void 0 ? void 0 : _8.contentId) !== msgData.contentId) {
634
+ return;
635
+ }
636
+ const manifest = msgData.value.manifest;
637
+ this._currentContentInfo.manifest = manifest;
638
+ this._updateCodecSupport(manifest, mediaElement);
639
+ this._startPlaybackIfReady(playbackStartParams);
640
+ break;
641
+ }
642
+ case "manifest-update" /* CoreMessageType.ManifestUpdate */: {
643
+ if (((_9 = this._currentContentInfo) === null || _9 === void 0 ? void 0 : _9.contentId) !== msgData.contentId) {
644
+ return;
645
+ }
646
+ const manifest = (_10 = this._currentContentInfo) === null || _10 === void 0 ? void 0 : _10.manifest;
647
+ if (isNullOrUndefined(manifest)) {
648
+ log.error("Init", "Manifest update but no Manifest loaded");
649
+ return;
650
+ }
651
+ replicateUpdatesOnManifestMetadata(manifest, msgData.value.manifest, msgData.value.updates);
652
+ (_12 = (_11 = this._currentContentInfo) === null || _11 === void 0 ? void 0 : _11.streamEventsEmitter) === null || _12 === void 0 ? void 0 : _12.onManifestUpdate(manifest);
653
+ this._updateCodecSupport(manifest, mediaElement);
654
+ this.trigger("manifestUpdate", msgData.value.updates);
655
+ break;
656
+ }
657
+ case "update-playback-rate" /* CoreMessageType.UpdatePlaybackRate */:
658
+ if (((_13 = this._currentContentInfo) === null || _13 === void 0 ? void 0 : _13.contentId) !== msgData.contentId) {
659
+ return;
660
+ }
661
+ playbackObserver.setPlaybackRate(msgData.value);
662
+ break;
663
+ case "bitrate-estimate-change" /* CoreMessageType.BitrateEstimateChange */:
664
+ if (((_14 = this._currentContentInfo) === null || _14 === void 0 ? void 0 : _14.contentId) !== msgData.contentId) {
665
+ return;
666
+ }
667
+ this.trigger("bitrateEstimateChange", {
668
+ type: msgData.value.bufferType,
669
+ bitrate: msgData.value.bitrate,
670
+ });
671
+ break;
672
+ case "inband-event" /* CoreMessageType.InbandEvent */:
673
+ if (((_15 = this._currentContentInfo) === null || _15 === void 0 ? void 0 : _15.contentId) !== msgData.contentId) {
674
+ return;
675
+ }
676
+ this.trigger("inbandEvents", msgData.value);
677
+ break;
678
+ case "locked-stream" /* CoreMessageType.LockedStream */: {
679
+ if (((_16 = this._currentContentInfo) === null || _16 === void 0 ? void 0 : _16.contentId) !== msgData.contentId ||
680
+ this._currentContentInfo.manifest === null) {
681
+ return;
682
+ }
683
+ const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
684
+ if (period === undefined) {
685
+ return;
686
+ }
687
+ (_17 = this._currentContentInfo.rebufferingController) === null || _17 === void 0 ? void 0 : _17.onLockedStream(msgData.value.bufferType, period);
688
+ break;
689
+ }
690
+ case "period-stream-ready" /* CoreMessageType.PeriodStreamReady */: {
691
+ if (((_18 = this._currentContentInfo) === null || _18 === void 0 ? void 0 : _18.contentId) !== msgData.contentId ||
692
+ this._currentContentInfo.manifest === null) {
693
+ return;
694
+ }
695
+ const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
696
+ if (period === undefined) {
697
+ return;
698
+ }
699
+ const ref = new SharedReference(undefined);
700
+ ref.onUpdate((adapChoice) => {
701
+ if (this._currentContentInfo === null) {
702
+ ref.finish();
703
+ return;
704
+ }
705
+ if (!isNullOrUndefined(adapChoice)) {
706
+ adapChoice.representations.onUpdate((repChoice, stopListening) => {
707
+ if (this._currentContentInfo === null) {
708
+ stopListening();
709
+ return;
710
+ }
711
+ this._settings.coreInterface.sendMessage({
712
+ type: "rep-update" /* MainThreadMessageType.RepresentationUpdate */,
713
+ contentId: this._currentContentInfo.contentId,
714
+ value: {
715
+ periodId: msgData.value.periodId,
716
+ adaptationId: adapChoice.adaptationId,
717
+ bufferType: msgData.value.bufferType,
718
+ choice: repChoice,
719
+ },
230
720
  });
231
- return;
232
- }
233
- }, { emitCurrentValue: true, clearSignal: initCanceller.signal });
721
+ }, { clearSignal: this._initCanceller.signal });
722
+ }
723
+ this._settings.coreInterface.sendMessage({
724
+ type: "track-update" /* MainThreadMessageType.TrackUpdate */,
725
+ contentId: this._currentContentInfo.contentId,
726
+ value: {
727
+ periodId: msgData.value.periodId,
728
+ bufferType: msgData.value.bufferType,
729
+ choice: isNullOrUndefined(adapChoice)
730
+ ? adapChoice
731
+ : {
732
+ adaptationId: adapChoice.adaptationId,
733
+ switchingMode: adapChoice.switchingMode,
734
+ initialRepresentations: adapChoice.representations.getValue(),
735
+ relativeResumingPosition: adapChoice.relativeResumingPosition,
736
+ },
737
+ },
738
+ });
739
+ }, { clearSignal: this._initCanceller.signal });
740
+ this.trigger("periodStreamReady", {
741
+ period,
742
+ type: msgData.value.bufferType,
743
+ adaptationRef: ref,
744
+ });
745
+ break;
746
+ }
747
+ case "period-stream-cleared" /* CoreMessageType.PeriodStreamCleared */: {
748
+ if (((_19 = this._currentContentInfo) === null || _19 === void 0 ? void 0 : _19.contentId) !== msgData.contentId ||
749
+ this._currentContentInfo.manifest === null) {
750
+ return;
234
751
  }
235
- else if (drmStatus.initializationState.type === "initialized") {
236
- resolve({
237
- mediaSource,
238
- drmSystemId: drmStatus.drmSystemId,
239
- unlinkMediaSource: mediaSourceCanceller,
752
+ this.trigger("periodStreamCleared", {
753
+ periodId: msgData.value.periodId,
754
+ type: msgData.value.bufferType,
755
+ });
756
+ break;
757
+ }
758
+ case "discontinuity-update" /* CoreMessageType.DiscontinuityUpdate */: {
759
+ if (((_20 = this._currentContentInfo) === null || _20 === void 0 ? void 0 : _20.contentId) !== msgData.contentId ||
760
+ this._currentContentInfo.manifest === null) {
761
+ return;
762
+ }
763
+ const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
764
+ if (period === undefined) {
765
+ log.warn("Init", "Discontinuity's Period not found", {
766
+ periodId: msgData.value.periodId,
240
767
  });
241
768
  return;
242
769
  }
243
- })
244
- .catch((err) => {
245
- if (mediaSourceCanceller.isUsed()) {
246
- return;
770
+ (_21 = this._currentContentInfo.rebufferingController) === null || _21 === void 0 ? void 0 : _21.updateDiscontinuityInfo({
771
+ period,
772
+ bufferType: msgData.value.bufferType,
773
+ discontinuity: msgData.value.discontinuity,
774
+ position: msgData.value.position,
775
+ });
776
+ break;
777
+ }
778
+ case "push-text-data" /* CoreMessageType.PushTextData */: {
779
+ if (((_22 = this._currentContentInfo) === null || _22 === void 0 ? void 0 : _22.contentId) !== msgData.contentId) {
780
+ return;
781
+ }
782
+ if (textDisplayer === null) {
783
+ log.warn("text", "Received AddTextData message but no text displayer exists");
784
+ }
785
+ else {
786
+ try {
787
+ const ranges = textDisplayer.pushTextData(msgData.value);
788
+ this._settings.coreInterface.sendMessage({
789
+ type: "add-text-success" /* MainThreadMessageType.PushTextDataSuccess */,
790
+ contentId: msgData.contentId,
791
+ value: { ranges },
792
+ });
793
+ }
794
+ catch (err) {
795
+ const message = err instanceof Error ? err.message : "Unknown error";
796
+ this._settings.coreInterface.sendMessage({
797
+ type: "push-text-error" /* MainThreadMessageType.PushTextDataError */,
798
+ contentId: msgData.contentId,
799
+ value: { message },
800
+ });
801
+ }
802
+ }
803
+ break;
804
+ }
805
+ case "remove-text-data" /* CoreMessageType.RemoveTextData */: {
806
+ if (((_23 = this._currentContentInfo) === null || _23 === void 0 ? void 0 : _23.contentId) !== msgData.contentId) {
807
+ return;
808
+ }
809
+ if (textDisplayer === null) {
810
+ log.warn("text", "Received RemoveTextData message but no text displayer exists");
811
+ }
812
+ else {
813
+ try {
814
+ const ranges = textDisplayer.removeBuffer(msgData.value.start, msgData.value.end);
815
+ this._settings.coreInterface.sendMessage({
816
+ type: "remove-text-success" /* MainThreadMessageType.RemoveTextDataSuccess */,
817
+ contentId: msgData.contentId,
818
+ value: { ranges },
819
+ });
820
+ }
821
+ catch (err) {
822
+ const message = err instanceof Error ? err.message : "Unknown error";
823
+ this._settings.coreInterface.sendMessage({
824
+ type: "remove-text-error" /* MainThreadMessageType.RemoveTextDataError */,
825
+ contentId: msgData.contentId,
826
+ value: { message },
827
+ });
828
+ }
829
+ }
830
+ break;
831
+ }
832
+ case "reset-text-displayer" /* CoreMessageType.ResetTextDisplayer */: {
833
+ if (((_24 = this._currentContentInfo) === null || _24 === void 0 ? void 0 : _24.contentId) !== msgData.contentId) {
834
+ return;
835
+ }
836
+ if (textDisplayer === null) {
837
+ log.warn("text", "Received ResetTextDisplayer message but no text displayer exists");
838
+ }
839
+ else {
840
+ textDisplayer.reset();
841
+ }
842
+ break;
843
+ }
844
+ case "stop-text-displayer" /* CoreMessageType.StopTextDisplayer */: {
845
+ if (((_25 = this._currentContentInfo) === null || _25 === void 0 ? void 0 : _25.contentId) !== msgData.contentId) {
846
+ return;
847
+ }
848
+ if (textDisplayer === null) {
849
+ log.warn("text", "Received StopTextDisplayer message but no text displayer exists");
850
+ }
851
+ else {
852
+ textDisplayer.stop();
853
+ }
854
+ break;
855
+ }
856
+ case "reloading-media-source" /* CoreMessageType.ReloadingMediaSource */:
857
+ {
858
+ if (this._currentContentInfo === null ||
859
+ this._currentContentInfo.mediaSourceInfo === null) {
860
+ return;
861
+ }
862
+ const mediaSourceId = this._currentContentInfo.mediaSourceInfo.type === "main"
863
+ ? this._currentContentInfo.mediaSourceInfo.mediaSource.id
864
+ : this._currentContentInfo.mediaSourceInfo.mediaSourceId;
865
+ if (mediaSourceId !== msgData.mediaSourceId) {
866
+ return;
867
+ }
868
+ reloadMediaSource(msgData.value.timeOffset, msgData.value.minimumPosition, msgData.value.maximumPosition);
869
+ }
870
+ break;
871
+ case "needs-decipherability-flush" /* CoreMessageType.NeedsDecipherabilityFlush */:
872
+ {
873
+ if (((_26 = this._currentContentInfo) === null || _26 === void 0 ? void 0 : _26.contentId) !== msgData.contentId) {
874
+ return;
875
+ }
876
+ const keySystem = getKeySystemConfiguration(mediaElement);
877
+ if (shouldReloadMediaSourceOnDecipherabilityUpdate(keySystem === null || keySystem === void 0 ? void 0 : keySystem[0])) {
878
+ notifyAndStartMediaSourceReload(0, undefined, undefined);
879
+ }
880
+ else {
881
+ const lastObservation = playbackObserver.getReference().getValue();
882
+ const currentPosition = lastObservation.position.getWanted();
883
+ // simple seek close to the current position
884
+ // to flush the buffers
885
+ if (currentPosition + 0.001 < lastObservation.duration) {
886
+ playbackObserver.setCurrentTime(mediaElement.currentTime + 0.001);
887
+ }
888
+ else {
889
+ playbackObserver.setCurrentTime(currentPosition);
890
+ }
891
+ }
892
+ }
893
+ break;
894
+ case "segment-sink-store-update" /* CoreMessageType.SegmentSinkStoreUpdate */: {
895
+ if (((_27 = this._currentContentInfo) === null || _27 === void 0 ? void 0 : _27.contentId) !== msgData.contentId) {
896
+ return;
897
+ }
898
+ const sinkObj = this._awaitingRequests.pendingSinkMetrics.get(msgData.value.requestId);
899
+ if (sinkObj !== undefined) {
900
+ sinkObj.resolve(msgData.value.segmentSinkMetrics);
901
+ }
902
+ else {
903
+ log.error("Init", "Failed to send segment sink store update");
904
+ }
905
+ break;
906
+ }
907
+ case "init-success" /* CoreMessageType.InitSuccess */:
908
+ case "init-error" /* CoreMessageType.InitError */:
909
+ // Should already be handled by the API
910
+ break;
911
+ case "log" /* CoreMessageType.LogMessage */:
912
+ // Already handled by prepare's handler
913
+ break;
914
+ case "thumbnail-response" /* CoreMessageType.ThumbnailDataResponse */: {
915
+ if (((_28 = this._currentContentInfo) === null || _28 === void 0 ? void 0 : _28.contentId) !== msgData.contentId) {
916
+ return;
917
+ }
918
+ const tObj = this._awaitingRequests.pendingThumbnailFetching.get(msgData.value.requestId);
919
+ if (tObj !== undefined) {
920
+ if (msgData.value.status === "error") {
921
+ tObj.reject(formatCoreError(msgData.value.error));
922
+ }
923
+ else {
924
+ tObj.resolve(msgData.value.data);
925
+ }
926
+ }
927
+ else {
928
+ log.error("Init", "Failed to send segment sink store update");
929
+ }
930
+ break;
931
+ }
932
+ default:
933
+ assertUnreachable(msgData);
934
+ }
935
+ };
936
+ log.debug("Init", "addEventListener for core message");
937
+ if (this._queuedCoreMessages !== null) {
938
+ const bufferedMessages = this._queuedCoreMessages.slice();
939
+ log.debug("Init", "Processing buffered messages", {
940
+ ammount: bufferedMessages.length,
941
+ });
942
+ for (const message of bufferedMessages) {
943
+ onmessage(message);
944
+ }
945
+ this._queuedCoreMessages = null;
946
+ }
947
+ this._settings.coreInterface.addMessageListener(onmessage);
948
+ this._initCanceller.signal.register(() => {
949
+ log.debug("Init", "removeEventListener for core message");
950
+ this._settings.coreInterface.removeMessageListener(onmessage);
951
+ });
952
+ }
953
+ dispose() {
954
+ var _a;
955
+ this._initCanceller.cancel();
956
+ if (this._currentContentInfo !== null) {
957
+ if (((_a = this._currentContentInfo.mediaSourceInfo) === null || _a === void 0 ? void 0 : _a.type) === "main") {
958
+ this._currentContentInfo.mediaSourceInfo.mediaSource.dispose();
959
+ }
960
+ this._currentContentInfo = null;
961
+ }
962
+ }
963
+ _onFatalError(err) {
964
+ if (this._initCanceller.isUsed()) {
965
+ return;
966
+ }
967
+ this._initCanceller.cancel();
968
+ this.trigger("error", err);
969
+ }
970
+ _initializeContentDecryption(mediaElement, lastContentProtection, mediaSourceStatus, reloadMediaSource, cancelSignal) {
971
+ var _a;
972
+ const { keySystems } = this._settings;
973
+ // TODO private?
974
+ const createEmeDisabledReference = (errMsg) => {
975
+ mediaSourceStatus.setValue(1 /* MediaSourceInitializationStatus.AttachNow */);
976
+ lastContentProtection.onUpdate((data, stopListening) => {
977
+ if (data === null) {
978
+ // initial value
979
+ return;
980
+ }
981
+ stopListening();
982
+ const err = new EncryptedMediaError("MEDIA_IS_ENCRYPTED_ERROR", errMsg, {
983
+ keyStatuses: undefined,
984
+ keySystemConfiguration: undefined,
985
+ keySystem: undefined,
986
+ });
987
+ this._onFatalError(err);
988
+ }, { clearSignal: cancelSignal });
989
+ const ref = new SharedReference({
990
+ initializationState: {
991
+ type: "initialized",
992
+ value: null,
993
+ },
994
+ contentDecryptor: null,
995
+ drmSystemId: undefined,
996
+ });
997
+ ref.finish(); // We know that no new value will be triggered
998
+ return { statusRef: ref, contentDecryptor: null };
999
+ };
1000
+ if (keySystems.length === 0) {
1001
+ return createEmeDisabledReference("No `keySystems` option given.");
1002
+ }
1003
+ else if (features.decrypt === null) {
1004
+ return createEmeDisabledReference("EME feature not activated.");
1005
+ }
1006
+ const emeApi = (_a = mediaElement.FORCED_EME_API) !== null && _a !== void 0 ? _a : getEmeApiImplementation("auto");
1007
+ if (emeApi === null) {
1008
+ return createEmeDisabledReference("EME API not available on the current page.");
1009
+ }
1010
+ log.debug("Init", "Creating ContentDecryptor");
1011
+ const ContentDecryptor = features.decrypt;
1012
+ const contentDecryptor = new ContentDecryptor(emeApi, mediaElement, keySystems);
1013
+ const drmStatusRef = new SharedReference({
1014
+ initializationState: { type: "uninitialized", value: null },
1015
+ drmSystemId: undefined,
1016
+ }, cancelSignal);
1017
+ const updateCodecSupportOnStateChange = (state) => {
1018
+ var _a;
1019
+ if (state > ContentDecryptorState.Initializing) {
1020
+ const manifest = (_a = this._currentContentInfo) === null || _a === void 0 ? void 0 : _a.manifest;
1021
+ if (isNullOrUndefined(manifest)) {
1022
+ return;
1023
+ }
1024
+ this._updateCodecSupport(manifest, mediaElement);
1025
+ contentDecryptor.removeEventListener("stateChange", updateCodecSupportOnStateChange);
1026
+ }
1027
+ };
1028
+ contentDecryptor.addEventListener("stateChange", updateCodecSupportOnStateChange);
1029
+ contentDecryptor.addEventListener("keyIdsCompatibilityUpdate", (updates) => {
1030
+ if (this._currentContentInfo === null ||
1031
+ this._currentContentInfo.manifest === null) {
1032
+ return;
1033
+ }
1034
+ const manUpdates = updateDecipherabilityFromKeyIds(this._currentContentInfo.manifest, updates);
1035
+ if (mayMediaElementFailOnUndecipherableData() &&
1036
+ manUpdates.some((e) => e.representation.decipherable !== true)) {
1037
+ reloadMediaSource();
1038
+ }
1039
+ else {
1040
+ this._settings.coreInterface.sendMessage({
1041
+ type: "decipherability-update" /* MainThreadMessageType.DecipherabilityStatusUpdate */,
1042
+ contentId: this._currentContentInfo.contentId,
1043
+ value: manUpdates.map((s) => ({
1044
+ representationUniqueId: s.representation.uniqueId,
1045
+ decipherable: s.representation.decipherable,
1046
+ })),
1047
+ });
1048
+ }
1049
+ this.trigger("decipherabilityUpdate", manUpdates);
1050
+ });
1051
+ contentDecryptor.addEventListener("blackListProtectionData", (protData) => {
1052
+ if (this._currentContentInfo === null ||
1053
+ this._currentContentInfo.manifest === null) {
1054
+ return;
1055
+ }
1056
+ const manUpdates = updateDecipherabilityFromProtectionData(this._currentContentInfo.manifest, protData);
1057
+ if (mayMediaElementFailOnUndecipherableData() &&
1058
+ manUpdates.some((e) => e.representation.decipherable !== true)) {
1059
+ reloadMediaSource();
1060
+ }
1061
+ else {
1062
+ this._settings.coreInterface.sendMessage({
1063
+ type: "decipherability-update" /* MainThreadMessageType.DecipherabilityStatusUpdate */,
1064
+ contentId: this._currentContentInfo.contentId,
1065
+ value: manUpdates.map((s) => ({
1066
+ representationUniqueId: s.representation.uniqueId,
1067
+ decipherable: s.representation.decipherable,
1068
+ })),
1069
+ });
1070
+ }
1071
+ this.trigger("decipherabilityUpdate", manUpdates);
1072
+ });
1073
+ contentDecryptor.addEventListener("stateChange", (state) => {
1074
+ if (state === ContentDecryptorState.WaitingForAttachment) {
1075
+ mediaSourceStatus.onUpdate((currStatus, stopListening) => {
1076
+ if (currStatus === 0 /* MediaSourceInitializationStatus.Nothing */) {
1077
+ mediaSourceStatus.setValue(1 /* MediaSourceInitializationStatus.AttachNow */);
1078
+ }
1079
+ else if (currStatus === 2 /* MediaSourceInitializationStatus.Attached */) {
1080
+ stopListening();
1081
+ if (state === ContentDecryptorState.WaitingForAttachment) {
1082
+ contentDecryptor.attach();
1083
+ }
247
1084
  }
248
- this._onFatalError(err);
1085
+ }, { clearSignal: cancelSignal, emitCurrentValue: true });
1086
+ }
1087
+ else if (state === ContentDecryptorState.ReadyForContent) {
1088
+ drmStatusRef.setValue({
1089
+ initializationState: { type: "initialized", value: null },
1090
+ drmSystemId: contentDecryptor.systemId,
249
1091
  });
250
- }, { emitCurrentValue: true, clearSignal: initCanceller.signal });
1092
+ contentDecryptor.removeEventListener("stateChange");
1093
+ }
1094
+ });
1095
+ contentDecryptor.addEventListener("error", (error) => {
1096
+ this._onFatalError(error);
1097
+ });
1098
+ contentDecryptor.addEventListener("warning", (error) => {
1099
+ this.trigger("warning", error);
251
1100
  });
1101
+ lastContentProtection.onUpdate((data) => {
1102
+ if (data === null) {
1103
+ return;
1104
+ }
1105
+ contentDecryptor.onInitializationData(data);
1106
+ }, { clearSignal: cancelSignal });
1107
+ cancelSignal.register(() => {
1108
+ contentDecryptor.dispose();
1109
+ });
1110
+ return { statusRef: drmStatusRef, contentDecryptor };
252
1111
  }
253
- async _onInitialMediaSourceReady(mediaElement, initialMediaSource, playbackObserver, drmSystemId, initialMediaSourceCanceller) {
254
- var _a;
255
- const { adaptiveOptions, autoPlay, bufferOptions, lowLatencyMode, segmentRequestOptions, speed, startAt, textTrackOptions, transport, } = this._initSettings;
256
- const initCanceller = this._initCanceller;
257
- assert(this._manifest !== null);
258
- let manifest;
1112
+ /**
1113
+ * Retrieves all unknown codecs from the current manifest, checks these unknown codecs
1114
+ * to determine if they are supported, updates the manifest with the support
1115
+ * status of these codecs, and forwards the list of supported codecs to core.
1116
+ * @param manifest
1117
+ */
1118
+ _updateCodecSupport(manifest, mediaElement) {
1119
+ var _a, _b, _c, _d;
259
1120
  try {
260
- manifest = (_a = this._manifest.syncValue) !== null && _a !== void 0 ? _a : (await this._manifest.getValueAsAsync());
261
- }
262
- catch (_e) {
263
- return; // The error should already have been processed through an event listener
1121
+ const updatedCodecs = updateManifestCodecSupport(manifest, (_b = (_a = this._currentContentInfo) === null || _a === void 0 ? void 0 : _a.contentDecryptor) !== null && _b !== void 0 ? _b : null, mediaElement, (_d = (_c = this._currentContentInfo) === null || _c === void 0 ? void 0 : _c.useMseInWorker) !== null && _d !== void 0 ? _d : false);
1122
+ if (updatedCodecs.length > 0) {
1123
+ this._settings.coreInterface.sendMessage({
1124
+ type: "codec-support-update" /* MainThreadMessageType.CodecSupportUpdate */,
1125
+ value: updatedCodecs,
1126
+ });
1127
+ // TODO what if one day the core updates codec support by itself?
1128
+ // We wouldn't know...
1129
+ this.trigger("codecSupportUpdate", null);
1130
+ }
264
1131
  }
265
- manifest.addEventListener("manifestUpdate", (updates) => {
266
- this.trigger("manifestUpdate", updates);
267
- this._refreshManifestCodecSupport(manifest, mediaElement);
268
- }, initCanceller.signal);
269
- manifest.addEventListener("decipherabilityUpdate", (elts) => {
270
- this.trigger("decipherabilityUpdate", elts);
271
- }, initCanceller.signal);
272
- manifest.addEventListener("supportUpdate", () => {
273
- this.trigger("codecSupportUpdate", null);
274
- }, initCanceller.signal);
275
- log.debug("Init", "Calculating initial time");
276
- const initialTime = getInitialTime(manifest, lowLatencyMode, startAt);
277
- log.debug("Init", "Initial time calculated", { initialTime });
278
- /** Choose the right "Representation" for a given "Adaptation". */
279
- const representationEstimator = AdaptiveRepresentationSelector(adaptiveOptions);
280
- const subBufferOptions = objectAssign({ textTrackOptions, drmSystemId }, bufferOptions);
281
- const cdnPrioritizer = new CdnPrioritizer(initCanceller.signal);
282
- const segmentQueueCreator = new SegmentQueueCreator(transport, cdnPrioritizer, this._cmcdDataBuilder, segmentRequestOptions);
283
- this._refreshManifestCodecSupport(manifest, mediaElement);
284
- this.trigger("manifestReady", manifest);
285
- if (initCanceller.isUsed()) {
286
- return;
1132
+ catch (err) {
1133
+ this._onFatalError(err);
287
1134
  }
288
- // handle initial load and reloads
289
- this._setupContentWithNewMediaSource({
290
- mediaElement,
291
- playbackObserver,
292
- mediaSource: initialMediaSource,
293
- initialTime,
294
- autoPlay,
295
- manifest,
296
- representationEstimator,
297
- cdnPrioritizer,
298
- segmentQueueCreator,
299
- speed,
300
- bufferOptions: subBufferOptions,
301
- }, initialMediaSourceCanceller);
302
1135
  }
303
- /**
304
- * Load the content defined by the Manifest in the mediaSource given at the
305
- * given position and playing status.
306
- * This function recursively re-call itself when a MediaSource reload is
307
- * wanted.
308
- * @param {Object} args
309
- * @param {Object} currentCanceller
310
- */
311
- _setupContentWithNewMediaSource(args, currentCanceller) {
312
- this._startLoadingContentOnMediaSource(args, this._createReloadMediaSourceCallback(args, currentCanceller), currentCanceller.signal);
1136
+ _hasTextBufferFeature() {
1137
+ return ((this._settings.textTrackOptions.textTrackMode === "html" &&
1138
+ features.htmlTextDisplayer !== null) ||
1139
+ features.nativeTextDisplayer !== null);
313
1140
  }
314
- /**
315
- * Create `IReloadMediaSourceCallback` allowing to handle reload orders.
316
- * @param {Object} args
317
- * @param {Object} currentCanceller
318
- */
319
- _createReloadMediaSourceCallback(args, currentCanceller) {
320
- const initCanceller = this._initCanceller;
321
- return (reloadOrder) => {
322
- currentCanceller.cancel();
323
- if (initCanceller.isUsed()) {
1141
+ _reload(mediaElement, textDisplayer, playbackObserver, mediaSourceStatus, position, autoPlay) {
1142
+ this._currentMediaSourceCanceller.cancel();
1143
+ this._currentMediaSourceCanceller = new TaskCanceller();
1144
+ this._currentMediaSourceCanceller.linkToSignal(this._initCanceller.signal);
1145
+ mediaSourceStatus.setValue(1 /* MediaSourceInitializationStatus.AttachNow */);
1146
+ this.trigger("reloadingMediaSource", { position, autoPlay });
1147
+ mediaSourceStatus.onUpdate((status, stopListeningMSStatusUpdates) => {
1148
+ if (status !== 2 /* MediaSourceInitializationStatus.Attached */) {
324
1149
  return;
325
1150
  }
326
- this.trigger("reloadingMediaSource", reloadOrder);
327
- if (initCanceller.isUsed()) {
328
- return;
1151
+ stopListeningMSStatusUpdates();
1152
+ const corePlaybackObserver = this._setUpModulesOnNewMediaSource({
1153
+ initialTime: position,
1154
+ autoPlay,
1155
+ mediaElement,
1156
+ textDisplayer,
1157
+ playbackObserver,
1158
+ }, this._currentMediaSourceCanceller.signal);
1159
+ if (!this._currentMediaSourceCanceller.isUsed() &&
1160
+ corePlaybackObserver !== null &&
1161
+ this._currentContentInfo !== null) {
1162
+ const contentId = this._currentContentInfo.contentId;
1163
+ corePlaybackObserver.listen((obs) => {
1164
+ this._settings.coreInterface.sendMessage({
1165
+ type: "observation" /* MainThreadMessageType.PlaybackObservation */,
1166
+ contentId,
1167
+ value: objectAssign(obs, {
1168
+ position: obs.position.serialize(),
1169
+ }),
1170
+ });
1171
+ }, {
1172
+ includeLastObservation: true,
1173
+ clearSignal: this._currentMediaSourceCanceller.signal,
1174
+ });
329
1175
  }
330
- const newCanceller = new TaskCanceller();
331
- newCanceller.linkToSignal(initCanceller.signal);
332
- createMediaSource(args.mediaElement, newCanceller.signal)
333
- .then((newMediaSource) => {
334
- this._setupContentWithNewMediaSource(Object.assign(Object.assign({}, args), { mediaSource: newMediaSource, initialTime: reloadOrder.position, autoPlay: reloadOrder.autoPlay }), newCanceller);
335
- })
336
- .catch((err) => {
337
- if (newCanceller.isUsed()) {
338
- return;
339
- }
340
- this._onFatalError(err);
341
- });
342
- };
1176
+ }, {
1177
+ clearSignal: this._currentMediaSourceCanceller.signal,
1178
+ emitCurrentValue: true,
1179
+ });
343
1180
  }
344
1181
  /**
345
- * Buffer the content on the given MediaSource.
346
- * @param {Object} args
347
- * @param {function} onReloadOrder
1182
+ * Start-up modules and mechanisms (initial seek, auto-play etc.) needed each
1183
+ * time a content is loaded AND re-loaded on a `HTMLMediaElement`, when the
1184
+ * manifest is known.
1185
+ *
1186
+ * Note that this does not include reacting to incoming core messages nor
1187
+ * sending them, those actions have to be handled separately.
1188
+ *
1189
+ * @param {Object} parameters
348
1190
  * @param {Object} cancelSignal
1191
+ * @returns {Object|null} - Playback Observer created for this content. `null`
1192
+ * only if playback initialization failed (most likely because it has been
1193
+ * cancelled).
349
1194
  */
350
- _startLoadingContentOnMediaSource(args, onReloadOrder, cancelSignal) {
351
- var _a, _b;
352
- const { autoPlay, bufferOptions, initialTime, manifest, mediaElement, mediaSource, playbackObserver, representationEstimator, cdnPrioritizer, segmentQueueCreator, speed, } = args;
353
- const { transport } = this._initSettings;
354
- const initialPeriod = (_a = manifest.getPeriodForTime(initialTime)) !== null && _a !== void 0 ? _a : manifest.getNextPeriod(initialTime);
355
- if (initialPeriod === undefined) {
356
- const error = new MediaError("MEDIA_STARTING_TIME_NOT_FOUND", "Wanted starting time not found in the Manifest.");
357
- return this._onFatalError(error);
1195
+ _setUpModulesOnNewMediaSource(parameters, cancelSignal) {
1196
+ if (cancelSignal.isCancelled()) {
1197
+ return null;
358
1198
  }
359
- let textDisplayerInterface = null;
360
- const textDisplayer = createTextDisplayer(mediaElement, this._initSettings.textTrackOptions);
361
- if (textDisplayer !== null) {
362
- const sender = new MainThreadTextDisplayerInterface(textDisplayer);
363
- textDisplayerInterface = sender;
364
- cancelSignal.register(() => {
365
- sender.stop();
366
- textDisplayer === null || textDisplayer === void 0 ? void 0 : textDisplayer.stop();
367
- });
1199
+ if (this._currentContentInfo === null) {
1200
+ log.error("Init", "Setting up modules without a contentId");
1201
+ return null;
368
1202
  }
369
- /** Interface to create media buffers. */
370
- const segmentSinksStore = new SegmentSinksStore(mediaSource, mediaElement.nodeName === "VIDEO", textDisplayerInterface);
371
- cancelSignal.register(() => {
372
- segmentSinksStore.disposeAll();
373
- });
1203
+ if (this._currentContentInfo.manifest === null) {
1204
+ log.error("Init", "Setting up modules without a loaded Manifest");
1205
+ return null;
1206
+ }
1207
+ const { manifest, mediaSourceInfo } = this._currentContentInfo;
1208
+ const { speed } = this._settings;
1209
+ const { initialTime, autoPlay, mediaElement, textDisplayer, playbackObserver } = parameters;
1210
+ this._currentContentInfo.initialTime = initialTime;
1211
+ this._currentContentInfo.autoPlay = autoPlay;
374
1212
  const { autoPlayResult, initialPlayPerformed } = performInitialSeekAndPlay({
375
1213
  mediaElement,
376
1214
  playbackObserver,
377
1215
  startTime: initialTime,
378
1216
  mustAutoPlay: autoPlay,
379
- onWarning: (err) => {
380
- this.trigger("warning", err);
381
- },
1217
+ onWarning: (err) => this.trigger("warning", err),
382
1218
  isDirectfile: false,
383
1219
  }, cancelSignal);
1220
+ this._currentContentInfo.initialPlayPerformed = initialPlayPerformed;
1221
+ const corePlaybackObserver = createCorePlaybackObserver(playbackObserver, {
1222
+ autoPlay,
1223
+ initialPlayPerformed,
1224
+ manifest,
1225
+ mediaSource: (mediaSourceInfo === null || mediaSourceInfo === void 0 ? void 0 : mediaSourceInfo.type) === "main" ? mediaSourceInfo.mediaSource : null,
1226
+ speed,
1227
+ textDisplayer,
1228
+ }, cancelSignal);
384
1229
  if (cancelSignal.isCancelled()) {
385
- return;
1230
+ return null;
386
1231
  }
1232
+ /**
1233
+ * Class trying to avoid various stalling situations, emitting "stalled"
1234
+ * events when it cannot, as well as "unstalled" events when it get out of one.
1235
+ */
1236
+ const rebufferingController = new RebufferingController(playbackObserver, manifest, speed);
1237
+ rebufferingController.addEventListener("stalled", (evt) => this.trigger("stalled", evt));
1238
+ rebufferingController.addEventListener("unstalled", () => this.trigger("unstalled", null));
1239
+ rebufferingController.addEventListener("warning", (err) => this.trigger("warning", err));
1240
+ cancelSignal.register(() => {
1241
+ rebufferingController.destroy();
1242
+ });
1243
+ rebufferingController.start();
1244
+ this._currentContentInfo.rebufferingController = rebufferingController;
1245
+ const currentContentInfo = this._currentContentInfo;
387
1246
  initialPlayPerformed.onUpdate((isPerformed, stopListening) => {
388
1247
  if (isPerformed) {
389
1248
  stopListening();
390
1249
  const streamEventsEmitter = new StreamEventsEmitter(manifest, playbackObserver);
391
- manifest.addEventListener("manifestUpdate", () => {
392
- streamEventsEmitter.onManifestUpdate(manifest);
393
- }, cancelSignal);
1250
+ currentContentInfo.streamEventsEmitter = streamEventsEmitter;
394
1251
  streamEventsEmitter.addEventListener("event", (payload) => {
395
1252
  this.trigger("streamEvent", payload);
396
1253
  }, cancelSignal);
@@ -403,59 +1260,62 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
403
1260
  });
404
1261
  }
405
1262
  }, { clearSignal: cancelSignal, emitCurrentValue: true });
406
- const coreObserver = createCorePlaybackObserver(playbackObserver, {
407
- autoPlay,
408
- manifest,
409
- mediaSource,
410
- textDisplayer,
411
- initialPlayPerformed,
412
- speed,
413
- }, cancelSignal);
414
- (_b = this._cmcdDataBuilder) === null || _b === void 0 ? void 0 : _b.startMonitoringPlayback(coreObserver);
415
- cancelSignal.register(() => {
416
- var _a;
417
- (_a = this._cmcdDataBuilder) === null || _a === void 0 ? void 0 : _a.stopMonitoringPlayback();
418
- });
419
- const rebufferingController = this._createRebufferingController(playbackObserver, manifest, speed, cancelSignal);
420
- const freezeResolver = new FreezeResolver(segmentSinksStore);
421
- if (mayMediaElementFailOnUndecipherableData()) {
422
- // On some devices, just reload immediately when data become undecipherable
423
- manifest.addEventListener("decipherabilityUpdate", (elts) => {
424
- if (elts.some((e) => e.representation.decipherable !== true)) {
425
- reloadMediaSource(0, undefined, undefined);
426
- }
427
- }, cancelSignal);
428
- }
429
- coreObserver.listen((observation) => {
430
- synchronizeSegmentSinksOnObservation(observation, segmentSinksStore);
431
- const freezeResolution = freezeResolver.onNewObservation(observation);
432
- if (freezeResolution === null) {
433
- return;
1263
+ const _getSegmentSinkMetrics = async () => {
1264
+ this._awaitingRequests.nextRequestId++;
1265
+ const requestId = this._awaitingRequests.nextRequestId;
1266
+ this._settings.coreInterface.sendMessage({
1267
+ type: "pull-segment-sink-store-infos" /* MainThreadMessageType.PullSegmentSinkStoreInfos */,
1268
+ value: { requestId },
1269
+ });
1270
+ return new Promise((resolve, reject) => {
1271
+ const rejectFn = (err) => {
1272
+ cancelSignal.deregister(rejectFn);
1273
+ this._awaitingRequests.pendingSinkMetrics.delete(requestId);
1274
+ return reject(err);
1275
+ };
1276
+ this._awaitingRequests.pendingSinkMetrics.set(requestId, {
1277
+ resolve: (value) => {
1278
+ cancelSignal.deregister(rejectFn);
1279
+ this._awaitingRequests.pendingSinkMetrics.delete(requestId);
1280
+ resolve(value);
1281
+ },
1282
+ });
1283
+ cancelSignal.register(rejectFn);
1284
+ });
1285
+ };
1286
+ const _getThumbnailsData = async (periodId, thumbnailTrackId, time) => {
1287
+ if (this._currentContentInfo === null) {
1288
+ return Promise.reject(new Error("Cannot fetch thumbnails: No content loaded."));
434
1289
  }
435
- // TODO: The following method looks generic, we may be able to factorize
436
- // it with other reload handlers after some work.
437
- const triggerReload = () => {
438
- var _a;
439
- const lastObservation = playbackObserver.getReference().getValue();
440
- const position = lastObservation.position.isAwaitingFuturePosition()
441
- ? lastObservation.position.getWanted()
442
- : ((_a = coreObserver.getCurrentTime()) !== null && _a !== void 0 ? _a : lastObservation.position.getPolled());
443
- const autoplay = initialPlayPerformed.getValue()
444
- ? !playbackObserver.getIsPaused()
445
- : autoPlay;
446
- onReloadOrder({ position, autoPlay: autoplay });
447
- };
448
- handleFreezeResolution(freezeResolution, {
449
- enableRepresentationAvoidance: this._initSettings.enableRepresentationAvoidance,
450
- manifest,
451
- triggerReload,
452
- playbackObserver,
1290
+ this._awaitingRequests.nextRequestId++;
1291
+ const requestId = this._awaitingRequests.nextRequestId;
1292
+ this._settings.coreInterface.sendMessage({
1293
+ type: "thumbnail-request" /* MainThreadMessageType.ThumbnailDataRequest */,
1294
+ contentId: this._currentContentInfo.contentId,
1295
+ value: { requestId, periodId, thumbnailTrackId, time },
453
1296
  });
454
- }, { clearSignal: cancelSignal });
455
- const contentTimeBoundariesObserver = createContentTimeBoundariesObserver(manifest, mediaSource, coreObserver, segmentSinksStore, {
456
- onWarning: (err) => this.trigger("warning", err),
457
- onPeriodChanged: (period) => this.trigger("activePeriodChanged", { period }),
458
- }, cancelSignal);
1297
+ return new Promise((resolve, reject) => {
1298
+ const rejectFn = (err) => {
1299
+ cleanUp();
1300
+ reject(err);
1301
+ };
1302
+ const cleanUp = () => {
1303
+ cancelSignal.deregister(rejectFn);
1304
+ this._awaitingRequests.pendingThumbnailFetching.delete(requestId);
1305
+ };
1306
+ this._awaitingRequests.pendingThumbnailFetching.set(requestId, {
1307
+ resolve: (value) => {
1308
+ cleanUp();
1309
+ resolve(value);
1310
+ },
1311
+ reject: (value) => {
1312
+ cleanUp();
1313
+ reject(value);
1314
+ },
1315
+ });
1316
+ cancelSignal.register(rejectFn);
1317
+ });
1318
+ };
459
1319
  /**
460
1320
  * Emit a "loaded" events once the initial play has been performed and the
461
1321
  * media can begin playback.
@@ -465,452 +1325,237 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
465
1325
  .then(() => {
466
1326
  getLoadedReference(playbackObserver, false, cancelSignal).onUpdate((isLoaded, stopListening) => {
467
1327
  if (isLoaded) {
468
- const fetchThumbnails = createThumbnailFetcher(transport.thumbnails, cdnPrioritizer);
469
1328
  stopListening();
470
1329
  this.trigger("loaded", {
471
- getSegmentSinkMetrics: async () => {
472
- return new Promise((resolve) => resolve(segmentSinksStore.getSegmentSinksMetrics()));
473
- },
474
- getThumbnailData: async (periodId, thumbnailTrackId, time) => {
475
- return getThumbnailData(fetchThumbnails, manifest, periodId, thumbnailTrackId, time);
476
- },
1330
+ getSegmentSinkMetrics: _getSegmentSinkMetrics,
1331
+ getThumbnailData: _getThumbnailsData,
477
1332
  });
478
1333
  }
479
1334
  }, { emitCurrentValue: true, clearSignal: cancelSignal });
480
1335
  })
481
1336
  .catch((err) => {
482
1337
  if (cancelSignal.isCancelled()) {
483
- return; // Current loading cancelled, no need to trigger the error
1338
+ return;
484
1339
  }
485
1340
  this._onFatalError(err);
486
1341
  });
487
- // eslint-disable-next-line @typescript-eslint/no-this-alias
488
- const self = this;
489
- StreamOrchestrator({ manifest, initialPeriod }, coreObserver, representationEstimator, segmentSinksStore, segmentQueueCreator, bufferOptions, handleStreamOrchestratorCallbacks(), cancelSignal);
490
- /**
491
- * Returns Object handling the callbacks from a `StreamOrchestrator`, which
492
- * are basically how it communicates about events.
493
- * @returns {Object}
494
- */
495
- function handleStreamOrchestratorCallbacks() {
496
- return {
497
- needsBufferFlush: (payload) => {
498
- var _a;
499
- let wantedSeekingTime;
500
- const lastObservation = playbackObserver.getReference().getValue();
501
- const currentTime = lastObservation.position.isAwaitingFuturePosition()
502
- ? lastObservation.position.getWanted()
503
- : mediaElement.currentTime;
504
- const relativeResumingPosition = (_a = payload === null || payload === void 0 ? void 0 : payload.relativeResumingPosition) !== null && _a !== void 0 ? _a : 0;
505
- const canBeApproximateSeek = Boolean(payload === null || payload === void 0 ? void 0 : payload.relativePosHasBeenDefaulted);
506
- if (relativeResumingPosition === 0 && canBeApproximateSeek) {
507
- // in case relativeResumingPosition is 0, we still perform
508
- // a tiny seek to be sure that the browser will correclty reload the video.
509
- wantedSeekingTime = currentTime + 0.001;
510
- }
511
- else {
512
- wantedSeekingTime = currentTime + relativeResumingPosition;
513
- }
514
- playbackObserver.setCurrentTime(wantedSeekingTime);
515
- // Seek again once data begins to be buffered.
516
- // This is sadly necessary on some browsers to avoid decoding
517
- // issues after a flush.
518
- //
519
- // NOTE: there's in theory a potential race condition in the following
520
- // logic as the callback could be called when media data is still
521
- // being removed by the browser - which is an asynchronous process.
522
- // The following condition checking for buffered data could thus lead
523
- // to a false positive where we're actually checking previous data.
524
- // For now, such scenario is avoided by setting the
525
- // `includeLastObservation` option to `false` and calling
526
- // `needsBufferFlush` once MSE media removal operations have been
527
- // explicitely validated by the browser, but that's a complex and easy
528
- // to break system.
529
- playbackObserver.listen((obs, stopListening) => {
530
- if (
531
- // Data is buffered around the current position
532
- obs.currentRange !== null ||
533
- // Or, for whatever reason, we have no buffer but we're already advancing
534
- obs.position.getPolled() > wantedSeekingTime + 0.1) {
535
- stopListening();
536
- playbackObserver.setCurrentTime(obs.position.getWanted() + 0.001);
537
- }
538
- }, { includeLastObservation: false, clearSignal: cancelSignal });
539
- },
540
- streamStatusUpdate(value) {
541
- // Announce discontinuities if found
542
- const { period, bufferType, imminentDiscontinuity, position } = value;
543
- rebufferingController.updateDiscontinuityInfo({
544
- period,
545
- bufferType,
546
- discontinuity: imminentDiscontinuity,
547
- position,
548
- });
549
- if (cancelSignal.isCancelled()) {
550
- return; // Previous call has stopped streams due to a side-effect
551
- }
552
- // If the status for the last Period indicates that segments are all loaded
553
- // or on the contrary that the loading resumed, announce it to the
554
- // ContentTimeBoundariesObserver.
555
- if (manifest.isLastPeriodKnown &&
556
- value.period.id === manifest.periods[manifest.periods.length - 1].id) {
557
- const hasFinishedLoadingLastPeriod = value.hasFinishedLoading || value.isEmptyStream;
558
- if (hasFinishedLoadingLastPeriod) {
559
- contentTimeBoundariesObserver.onLastSegmentFinishedLoading(value.bufferType);
560
- }
561
- else {
562
- contentTimeBoundariesObserver.onLastSegmentLoadingResume(value.bufferType);
563
- }
564
- }
565
- },
566
- needsManifestRefresh: () => self._manifestFetcher.scheduleManualRefresh({
567
- enablePartialRefresh: true,
568
- canUseUnsafeMode: true,
569
- }),
570
- manifestMightBeOufOfSync: () => {
571
- const { OUT_OF_SYNC_MANIFEST_REFRESH_DELAY } = config.getCurrent();
572
- self._manifestFetcher.scheduleManualRefresh({
573
- enablePartialRefresh: false,
574
- canUseUnsafeMode: false,
575
- delay: OUT_OF_SYNC_MANIFEST_REFRESH_DELAY,
576
- });
577
- },
578
- lockedStream: (value) => rebufferingController.onLockedStream(value.bufferType, value.period),
579
- adaptationChange: (value) => {
580
- self.trigger("adaptationChange", value);
581
- if (cancelSignal.isCancelled()) {
582
- return; // Previous call has stopped streams due to a side-effect
583
- }
584
- contentTimeBoundariesObserver.onAdaptationChange(value.type, value.period, value.adaptation);
585
- },
586
- representationChange: (value) => {
587
- self.trigger("representationChange", value);
588
- if (cancelSignal.isCancelled()) {
589
- return; // Previous call has stopped streams due to a side-effect
590
- }
591
- contentTimeBoundariesObserver.onRepresentationChange(value.type, value.period);
592
- },
593
- inbandEvent: (value) => self.trigger("inbandEvents", value),
594
- warning: (value) => self.trigger("warning", value),
595
- periodStreamReady: (value) => self.trigger("periodStreamReady", value),
596
- periodStreamCleared: (value) => {
597
- contentTimeBoundariesObserver.onPeriodCleared(value.type, value.period);
598
- if (cancelSignal.isCancelled()) {
599
- return; // Previous call has stopped streams due to a side-effect
600
- }
601
- self.trigger("periodStreamCleared", {
602
- type: value.type,
603
- periodId: value.period.id,
604
- });
605
- },
606
- bitrateEstimateChange: (value) => {
607
- var _a;
608
- (_a = self._cmcdDataBuilder) === null || _a === void 0 ? void 0 : _a.updateThroughput(value.type, value.bitrate);
609
- self.trigger("bitrateEstimateChange", value);
610
- },
611
- needsMediaSourceReload: (payload) => {
612
- reloadMediaSource(payload.timeOffset, payload.minimumPosition, payload.maximumPosition);
613
- },
614
- needsDecipherabilityFlush() {
615
- var _a, _b, _c, _d;
616
- const keySystem = getKeySystemConfiguration(mediaElement);
617
- if (shouldReloadMediaSourceOnDecipherabilityUpdate(keySystem === null || keySystem === void 0 ? void 0 : keySystem[0])) {
618
- const lastObservation = coreObserver.getReference().getValue();
619
- const position = lastObservation.position.isAwaitingFuturePosition()
620
- ? lastObservation.position.getWanted()
621
- : ((_a = coreObserver.getCurrentTime()) !== null && _a !== void 0 ? _a : lastObservation.position.getPolled());
622
- const isPaused = (_c = (_b = lastObservation.paused.pending) !== null && _b !== void 0 ? _b : coreObserver.getIsPaused()) !== null && _c !== void 0 ? _c : lastObservation.paused.last;
623
- onReloadOrder({ position, autoPlay: !isPaused });
624
- }
625
- else {
626
- const lastObservation = coreObserver.getReference().getValue();
627
- const position = lastObservation.position.isAwaitingFuturePosition()
628
- ? lastObservation.position.getWanted()
629
- : ((_d = coreObserver.getCurrentTime()) !== null && _d !== void 0 ? _d : lastObservation.position.getPolled());
630
- // simple seek close to the current position
631
- // to flush the buffers
632
- if (position + 0.001 < lastObservation.duration) {
633
- playbackObserver.setCurrentTime(mediaElement.currentTime + 0.001);
634
- }
635
- else {
636
- playbackObserver.setCurrentTime(position);
637
- }
638
- }
639
- },
640
- encryptionDataEncountered: (value) => {
641
- if (self._decryptionCapabilities.status === "disabled") {
642
- self._onFatalError(self._decryptionCapabilities.value);
643
- return;
644
- }
645
- else if (self._decryptionCapabilities.status === "uninitialized") {
646
- // Should never happen
647
- log.error("Init", "received encryption data without known decryption capabilities");
648
- return;
649
- }
650
- for (const protectionData of value) {
651
- self._decryptionCapabilities.value.onInitializationData(protectionData);
652
- if (cancelSignal.isCancelled()) {
653
- return; // Previous call has stopped streams due to a side-effect
654
- }
655
- }
656
- },
657
- error: (err) => self._onFatalError(err),
658
- };
659
- }
660
- /**
661
- * Callback allowing to reload the current content.
662
- * @param {number} deltaPosition - Position you want to seek to after
663
- * reloading, as a delta in seconds from the last polled playing position.
664
- * @param {number|undefined} minimumPosition - If set, minimum time bound
665
- * in seconds after `deltaPosition` has been applied.
666
- * @param {number|undefined} maximumPosition - If set, minimum time bound
667
- * in seconds after `deltaPosition` has been applied.
668
- */
669
- function reloadMediaSource(deltaPosition, minimumPosition, maximumPosition) {
670
- var _a, _b, _c;
671
- const lastObservation = coreObserver.getReference().getValue();
672
- const currentPosition = lastObservation.position.isAwaitingFuturePosition()
673
- ? lastObservation.position.getWanted()
674
- : ((_a = coreObserver.getCurrentTime()) !== null && _a !== void 0 ? _a : lastObservation.position.getPolled());
675
- const isPaused = (_c = (_b = lastObservation.paused.pending) !== null && _b !== void 0 ? _b : coreObserver.getIsPaused()) !== null && _c !== void 0 ? _c : lastObservation.paused.last;
676
- let position = currentPosition + deltaPosition;
677
- if (minimumPosition !== undefined) {
678
- position = Math.max(minimumPosition, position);
679
- }
680
- if (maximumPosition !== undefined) {
681
- position = Math.min(maximumPosition, position);
682
- }
683
- onReloadOrder({ position, autoPlay: !isPaused });
684
- }
1342
+ return corePlaybackObserver;
685
1343
  }
686
1344
  /**
687
- * Creates a `RebufferingController`, a class trying to avoid various stalling
688
- * situations (such as rebuffering periods), and returns it.
1345
+ * Initialize content playback if and only if those conditions are filled:
1346
+ * - The Manifest is fetched and stored in `this._currentContentInfo`.
1347
+ * - `drmInitializationStatus` indicates that DRM matters are initialized.
1348
+ * - `mediaSourceStatus` indicates that the MediaSource is attached to the
1349
+ * `mediaElement`.
689
1350
  *
690
- * Various methods from that class need then to be called at various events
691
- * (see `RebufferingController` definition).
1351
+ * In other cases, this method will do nothing.
692
1352
  *
693
- * This function also handles the `RebufferingController`'s events:
694
- * - emit "stalled" events when stalling situations cannot be prevented,
695
- * - emit "unstalled" events when we could get out of one,
696
- * - emit "warning" on various rebuffering-related minor issues
697
- * like discontinuity skipping.
698
- * @param {Object} playbackObserver
699
- * @param {Object} manifest
700
- * @param {Object} speed
701
- * @param {Object} cancelSignal
702
- * @returns {Object}
703
- */
704
- _createRebufferingController(playbackObserver, manifest, speed, cancelSignal) {
705
- const rebufferingController = new RebufferingController(playbackObserver, manifest, speed);
706
- // Bubble-up events
707
- rebufferingController.addEventListener("stalled", (evt) => this.trigger("stalled", evt));
708
- rebufferingController.addEventListener("unstalled", () => this.trigger("unstalled", null));
709
- rebufferingController.addEventListener("warning", (err) => this.trigger("warning", err));
710
- cancelSignal.register(() => rebufferingController.destroy());
711
- rebufferingController.start();
712
- return rebufferingController;
713
- }
714
- /**
715
- * Evaluates a list of codecs to determine their support status.
1353
+ * To call when any of those conditions might become `true`, to start-up
1354
+ * playback.
716
1355
  *
717
- * @param {Array} codecsToCheck - The list of codecs to check.
718
- * @returns {Array} - The list of evaluated codecs with their support status updated.
1356
+ * @param {Object} parameters
1357
+ * @returns {boolean} - Returns `true` if all conditions where met for
1358
+ * playback start.
719
1359
  */
720
- getCodecsSupportInfo(codecsToCheck, mediaElement) {
721
- const codecsSupportInfo = codecsToCheck.map((codecToCheck) => {
722
- var _a;
723
- const inputCodec = `${codecToCheck.mimeType};codecs="${codecToCheck.codec}"`;
724
- const isSupported = isCodecSupported(mediaElement, inputCodec);
725
- if (!isSupported) {
726
- return {
727
- mimeType: codecToCheck.mimeType,
728
- codec: codecToCheck.codec,
729
- supported: false,
730
- supportedIfEncrypted: false,
731
- };
732
- }
733
- /**
734
- * `true` if the codec is supported when encrypted, `false` if it is not
735
- * supported, or `undefined` if we cannot obtain that information.
736
- */
737
- let supportedIfEncrypted;
738
- if (this._decryptionCapabilities.status === "uninitialized") {
739
- supportedIfEncrypted = undefined;
740
- }
741
- else if (this._decryptionCapabilities.status === "disabled") {
742
- // It's ambiguous here, but let's say that no ContentDecryptor means that
743
- // the codec is supported by it.
744
- supportedIfEncrypted = true;
745
- }
746
- else {
747
- const contentDecryptor = this._decryptionCapabilities.value;
748
- if (contentDecryptor.getState() !== ContentDecryptorState.Initializing) {
749
- // No information is available regarding the support status.
750
- // Defaulting to assume the codec is supported.
751
- supportedIfEncrypted =
752
- (_a = contentDecryptor.isCodecSupported(codecToCheck.mimeType, codecToCheck.codec)) !== null && _a !== void 0 ? _a : true;
753
- }
754
- }
755
- return {
756
- mimeType: codecToCheck.mimeType,
757
- codec: codecToCheck.codec,
758
- supported: isSupported,
759
- supportedIfEncrypted,
760
- };
1360
+ _startPlaybackIfReady(parameters) {
1361
+ if (this._currentContentInfo === null || this._currentContentInfo.manifest === null) {
1362
+ return false;
1363
+ }
1364
+ const drmInitStatus = parameters.drmInitializationStatus.getValue();
1365
+ if (drmInitStatus.initializationState.type !== "initialized") {
1366
+ return false;
1367
+ }
1368
+ const msInitStatus = parameters.mediaSourceStatus.getValue();
1369
+ if (msInitStatus !== 2 /* MediaSourceInitializationStatus.Attached */) {
1370
+ return false;
1371
+ }
1372
+ const { contentId, manifest } = this._currentContentInfo;
1373
+ log.debug("Init", "Calculating initial time");
1374
+ const initialTime = getInitialTime(manifest, this._settings.lowLatencyMode, this._settings.startAt);
1375
+ log.debug("Init", "Initial time calculated", { initialTime });
1376
+ const { enableFastSwitching, onCodecSwitch } = this._settings.bufferOptions;
1377
+ const corePlaybackObserver = this._setUpModulesOnNewMediaSource({
1378
+ initialTime,
1379
+ autoPlay: this._settings.autoPlay,
1380
+ mediaElement: parameters.mediaElement,
1381
+ textDisplayer: parameters.textDisplayer,
1382
+ playbackObserver: parameters.playbackObserver,
1383
+ }, this._currentMediaSourceCanceller.signal);
1384
+ if (this._currentMediaSourceCanceller.isUsed() || corePlaybackObserver === null) {
1385
+ return true;
1386
+ }
1387
+ const initialObservation = corePlaybackObserver.getReference().getValue();
1388
+ const sentInitialObservation = objectAssign(initialObservation, {
1389
+ position: initialObservation.position.serialize(),
1390
+ });
1391
+ this._settings.coreInterface.sendMessage({
1392
+ type: "start" /* MainThreadMessageType.StartPreparedContent */,
1393
+ contentId,
1394
+ value: {
1395
+ initialTime,
1396
+ initialObservation: sentInitialObservation,
1397
+ drmSystemId: drmInitStatus.drmSystemId,
1398
+ enableFastSwitching,
1399
+ onCodecSwitch,
1400
+ },
1401
+ });
1402
+ corePlaybackObserver.listen((obs) => {
1403
+ this._settings.coreInterface.sendMessage({
1404
+ type: "observation" /* MainThreadMessageType.PlaybackObservation */,
1405
+ contentId,
1406
+ value: objectAssign(obs, { position: obs.position.serialize() }),
1407
+ });
1408
+ }, {
1409
+ includeLastObservation: false,
1410
+ clearSignal: this._currentMediaSourceCanceller.signal,
761
1411
  });
762
- return codecsSupportInfo;
1412
+ this.trigger("manifestReady", manifest);
1413
+ return true;
763
1414
  }
764
1415
  /**
765
- * Update the support status of all Representations in the Manifest.
766
- *
767
- * To call anytime either the Manifest is linked to new codecs or new means
768
- * to test for codec support are available.
769
- * @param {Object} manifest
1416
+ * Handles core messages asking to create a MediaSource.
1417
+ * @param {Object} msg - The core's message received.
1418
+ * @param {HTMLMediaElement} mediaElement - HTMLMediaElement on which the
1419
+ * content plays.
1420
+ * @param {Object} coreInterface - The interface to the core.
770
1421
  */
771
- _refreshManifestCodecSupport(manifest, mediaElement) {
772
- const codecsToTest = manifest.getCodecsWithUnknownSupport();
773
- const codecsSupportInfo = this.getCodecsSupportInfo(codecsToTest, mediaElement);
774
- if (codecsSupportInfo.length > 0) {
1422
+ _onCreateMediaSourceMessage(msg, mediaElement, mediaSourceStatus, coreInterface) {
1423
+ var _a;
1424
+ if (((_a = this._currentContentInfo) === null || _a === void 0 ? void 0 : _a.contentId) !== msg.contentId) {
1425
+ log.info("Init", "Ignoring MediaSource attachment due to wrong `contentId`");
1426
+ }
1427
+ else {
1428
+ const { mediaSourceId } = msg;
775
1429
  try {
776
- manifest.updateCodecSupport(codecsSupportInfo);
1430
+ mediaSourceStatus.onUpdate((currStatus, stopListening) => {
1431
+ var _a;
1432
+ if (this._currentContentInfo === null) {
1433
+ stopListening();
1434
+ return;
1435
+ }
1436
+ if (currStatus === 1 /* MediaSourceInitializationStatus.AttachNow */) {
1437
+ stopListening();
1438
+ const mediaSource = new MainMediaSourceInterface(mediaSourceId, "FORCED_MEDIA_SOURCE" in mediaElement
1439
+ ? mediaElement.FORCED_MEDIA_SOURCE
1440
+ : undefined);
1441
+ if (((_a = this._currentContentInfo.mediaSourceInfo) === null || _a === void 0 ? void 0 : _a.type) === "main") {
1442
+ this._currentContentInfo.mediaSourceInfo.mediaSource.dispose();
1443
+ }
1444
+ this._currentContentInfo.mediaSourceInfo = {
1445
+ type: "main",
1446
+ mediaSource,
1447
+ };
1448
+ mediaSource.addEventListener("mediaSourceOpen", () => {
1449
+ coreInterface.sendMessage({
1450
+ type: "media-source-ready-state-change" /* MainThreadMessageType.MediaSourceReadyStateChange */,
1451
+ mediaSourceId,
1452
+ value: "open",
1453
+ });
1454
+ });
1455
+ mediaSource.addEventListener("mediaSourceEnded", () => {
1456
+ coreInterface.sendMessage({
1457
+ type: "media-source-ready-state-change" /* MainThreadMessageType.MediaSourceReadyStateChange */,
1458
+ mediaSourceId,
1459
+ value: "ended",
1460
+ });
1461
+ });
1462
+ mediaSource.addEventListener("mediaSourceClose", () => {
1463
+ coreInterface.sendMessage({
1464
+ type: "media-source-ready-state-change" /* MainThreadMessageType.MediaSourceReadyStateChange */,
1465
+ mediaSourceId,
1466
+ value: "closed",
1467
+ });
1468
+ });
1469
+ let url = null;
1470
+ if (mediaSource.handle.type === "handle") {
1471
+ mediaElement.srcObject = mediaSource.handle.value;
1472
+ }
1473
+ else {
1474
+ url = URL.createObjectURL(mediaSource.handle.value);
1475
+ mediaElement.src = url;
1476
+ }
1477
+ this._currentMediaSourceCanceller.signal.register(() => {
1478
+ mediaSource.dispose();
1479
+ resetMediaElement(mediaElement, url);
1480
+ });
1481
+ mediaSourceStatus.setValue(2 /* MediaSourceInitializationStatus.Attached */);
1482
+ disableRemotePlaybackOnManagedMediaSource(mediaElement, this._currentMediaSourceCanceller.signal);
1483
+ }
1484
+ }, {
1485
+ emitCurrentValue: true,
1486
+ clearSignal: this._currentMediaSourceCanceller.signal,
1487
+ });
777
1488
  }
778
- catch (err) {
779
- this._onFatalError(err);
1489
+ catch (_err) {
1490
+ const error = new OtherError("NONE", "Unknown error when creating the MediaSource");
1491
+ this._onFatalError(error);
780
1492
  }
781
1493
  }
782
1494
  }
783
1495
  }
784
- function createTextDisplayer(mediaElement, textTrackOptions) {
785
- if (textTrackOptions.textTrackMode === "html" && features.htmlTextDisplayer !== null) {
786
- return new features.htmlTextDisplayer(mediaElement, textTrackOptions.textTrackElement);
1496
+ function bindNumberReferencesToCore(coreInterface, cancellationSignal, ...refs) {
1497
+ for (const ref of refs) {
1498
+ ref[0].onUpdate((newVal) => {
1499
+ // NOTE: The TypeScript checks have already been made by this function's
1500
+ // overload, but the body here is not aware of that.
1501
+ coreInterface.sendMessage({
1502
+ type: "ref-update" /* MainThreadMessageType.ReferenceUpdate */,
1503
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
1504
+ value: { name: ref[1], newVal: newVal },
1505
+ });
1506
+ }, { clearSignal: cancellationSignal, emitCurrentValue: true });
1507
+ }
1508
+ }
1509
+ function formatCoreError(sentError) {
1510
+ switch (sentError.name) {
1511
+ case "NetworkError":
1512
+ return new NetworkError(sentError.code, new RequestError(sentError.baseError.url, sentError.baseError.status, sentError.baseError.type));
1513
+ case "MediaError":
1514
+ // eslint-disable-next-line
1515
+ return new MediaError(sentError.code, sentError.reason, {
1516
+ tracks: sentError.tracks,
1517
+ });
1518
+ case "EncryptedMediaError":
1519
+ // We assume that everything have already been checked Worker-side here
1520
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
1521
+ return new EncryptedMediaError(sentError.code, sentError.reason, {
1522
+ keyStatuses: sentError.keyStatuses,
1523
+ keySystemConfiguration: sentError.keySystemConfiguration,
1524
+ keySystem: sentError.keySystem,
1525
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1526
+ });
1527
+ case "OtherError":
1528
+ return new OtherError(sentError.code, sentError.reason);
1529
+ }
1530
+ }
1531
+ function formatSourceBufferError(error) {
1532
+ if (error instanceof SourceBufferError) {
1533
+ return error;
1534
+ }
1535
+ else if (error instanceof Error) {
1536
+ return new SourceBufferError(error.name, error.message, error.name === "QuotaExceededError");
787
1537
  }
788
- else if (features.nativeTextDisplayer !== null) {
789
- return new features.nativeTextDisplayer(mediaElement);
1538
+ else {
1539
+ return new SourceBufferError("Error", "Unknown SourceBufferError Error", false);
790
1540
  }
791
- return null;
792
1541
  }
793
1542
  /**
794
- * Change the decipherability of Representations which have their key id in one
795
- * of the given Arrays:
796
- *
797
- * - Those who have a key id listed in `whitelistedKeyIds` will have their
798
- * decipherability updated to `true`
799
- *
800
- * - Those who have a key id listed in `blacklistedKeyIds` will have their
801
- * decipherability updated to `false`
1543
+ * The Core might send back logs. In that situation, the message might be
1544
+ * formatted slightly differently to be able to cross threads (so a
1545
+ * serializable format has to be sent).
802
1546
  *
803
- * - Those who have a key id listed in `delistedKeyIds` will have their
804
- * decipherability updated to `undefined`.
1547
+ * This function translates that Core format to what's expected by the
1548
+ * logger.
805
1549
  *
806
- * @param {Object} manifest
807
- * @param {Array.<Uint8Array>} whitelistedKeyIds
808
- * @param {Array.<Uint8Array>} blacklistedKeyIds
809
- * @param {Array.<Uint8Array>} delistedKeyIds
810
- */
811
- function updateKeyIdsDecipherabilityOnManifest(manifest, whitelistedKeyIds, blacklistedKeyIds, delistedKeyIds) {
812
- manifest.updateRepresentationsDeciperability((ctx) => {
813
- const { representation } = ctx;
814
- if (representation.contentProtections === undefined) {
815
- return representation.decipherable;
816
- }
817
- const contentKIDs = representation.contentProtections.keyIds;
818
- if (contentKIDs !== undefined) {
819
- for (const elt of contentKIDs) {
820
- for (const blacklistedKeyId of blacklistedKeyIds) {
821
- if (areArraysOfNumbersEqual(blacklistedKeyId, elt)) {
822
- return false;
823
- }
824
- }
825
- for (const whitelistedKeyId of whitelistedKeyIds) {
826
- if (areArraysOfNumbersEqual(whitelistedKeyId, elt)) {
827
- return true;
828
- }
829
- }
830
- for (const delistedKeyId of delistedKeyIds) {
831
- if (areArraysOfNumbersEqual(delistedKeyId, elt)) {
832
- return undefined;
833
- }
834
- }
835
- }
836
- }
837
- return representation.decipherable;
838
- });
839
- }
840
- /**
841
- * Update decipherability to `false` to any Representation which is linked to
842
- * the given initialization data.
843
- * @param {Object} manifest
844
- * @param {Object} initData
1550
+ * @param {*} arg
1551
+ * @returns {*}
845
1552
  */
846
- function blackListProtectionDataOnManifest(manifest, initData) {
847
- manifest.updateRepresentationsDeciperability((ctx) => {
848
- var _a, _b;
849
- const rep = ctx.representation;
850
- if (rep.decipherable === false) {
851
- return false;
852
- }
853
- const segmentProtections = (_b = (_a = rep.contentProtections) === null || _a === void 0 ? void 0 : _a.initData) !== null && _b !== void 0 ? _b : [];
854
- for (const protection of segmentProtections) {
855
- if (initData.type === undefined || protection.type === initData.type) {
856
- const containedInitData = initData.values
857
- .getFormattedValues()
858
- .every((undecipherableVal) => {
859
- return protection.values.some((currVal) => {
860
- return ((undecipherableVal.systemId === undefined ||
861
- currVal.systemId === undecipherableVal.systemId) &&
862
- areArraysOfNumbersEqual(currVal.data, undecipherableVal.data));
863
- });
864
- });
865
- if (containedInitData) {
866
- return false;
867
- }
868
- }
869
- }
870
- return rep.decipherable;
871
- });
872
- }
873
- /**
874
- * Handle accordingly an `IFreezeResolution` object.
875
- * @param {Object|null} freezeResolution - The `IFreezeResolution` suggested.
876
- * @param {Object} param - Parameters that might be needed to implement the
877
- * resolution.
878
- * @param {Object} param.manifest - The current content's Manifest object.
879
- * @param {Object} param.playbackObserver - Object regularly emitting playback
880
- * conditions.
881
- * @param {Function} param.triggerReload - Function to call if we need to ask
882
- * for a "MediaSource reload".
883
- * @param {Boolean} param.enableRepresentationAvoidance - If `true`, this
884
- * function is authorized to mark `Representation` as "to avoid" if the
885
- * `IFreezeResolution` object suggest it.
886
- */
887
- function handleFreezeResolution(freezeResolution, { playbackObserver, enableRepresentationAvoidance, manifest, triggerReload, }) {
888
- switch (freezeResolution.type) {
889
- case "reload": {
890
- log.info("Init", "Planning reload due to freeze");
891
- triggerReload();
892
- break;
893
- }
894
- case "flush": {
895
- log.info("Init", "Flushing buffer due to freeze");
896
- const observation = playbackObserver.getReference().getValue();
897
- const currentTime = observation.position.isAwaitingFuturePosition()
898
- ? observation.position.getWanted()
899
- : playbackObserver.getCurrentTime();
900
- const relativeResumingPosition = freezeResolution.value.relativeSeek;
901
- const wantedSeekingTime = currentTime + relativeResumingPosition;
902
- playbackObserver.setCurrentTime(wantedSeekingTime);
903
- break;
904
- }
905
- case "avoid-representations": {
906
- const contents = freezeResolution.value;
907
- if (enableRepresentationAvoidance) {
908
- manifest.addRepresentationsToAvoid(contents);
909
- }
910
- triggerReload();
911
- break;
912
- }
913
- default:
914
- assertUnreachable(freezeResolution);
1553
+ function formatSentLogObject(arg) {
1554
+ if (typeof arg !== "object") {
1555
+ return arg;
1556
+ }
1557
+ if ((arg === null || arg === void 0 ? void 0 : arg.isSerializedError) === true) {
1558
+ return formatCoreError(arg);
915
1559
  }
1560
+ return arg;
916
1561
  }