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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. package/.eslintrc.js +8 -0
  2. package/CHANGELOG.md +93 -0
  3. package/CONTRIBUTING.md +48 -168
  4. package/FILES.md +40 -92
  5. package/VERSION +1 -1
  6. package/dist/_esm5.processed/compat/browser_detection.d.ts +25 -12
  7. package/dist/_esm5.processed/compat/browser_detection.js +85 -38
  8. package/dist/_esm5.processed/compat/can_reuse_media_keys.js +2 -2
  9. package/dist/_esm5.processed/compat/eme/close_session.js +2 -2
  10. package/dist/_esm5.processed/compat/eme/load_session.js +1 -1
  11. package/dist/_esm5.processed/compat/event_listeners.js +1 -1
  12. package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.d.ts +21 -0
  13. package/dist/_esm5.processed/compat/has_issues_with_high_media_source_duration.js +26 -0
  14. package/dist/_esm5.processed/config.d.ts +4 -0
  15. package/dist/_esm5.processed/core/adaptive/adaptive_representation_selector.js +9 -6
  16. package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.d.ts +18 -1
  17. package/dist/_esm5.processed/core/adaptive/buffer_based_chooser.js +106 -25
  18. package/dist/_esm5.processed/core/adaptive/guess_based_chooser.js +6 -6
  19. package/dist/_esm5.processed/core/adaptive/network_analyzer.js +8 -5
  20. package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.d.ts +19 -1
  21. package/dist/_esm5.processed/core/adaptive/utils/representation_score_calculator.js +1 -1
  22. package/dist/_esm5.processed/core/api/debug/buffer_graph.d.ts +28 -0
  23. package/dist/_esm5.processed/core/api/debug/buffer_graph.js +175 -0
  24. package/dist/_esm5.processed/core/api/debug/buffer_size_graph.d.ts +10 -0
  25. package/dist/_esm5.processed/core/api/debug/buffer_size_graph.js +104 -0
  26. package/dist/_esm5.processed/core/api/debug/constants.d.ts +2 -0
  27. package/dist/_esm5.processed/core/api/debug/constants.js +2 -0
  28. package/dist/_esm5.processed/core/api/debug/index.d.ts +2 -0
  29. package/dist/_esm5.processed/core/api/debug/index.js +2 -0
  30. package/dist/_esm5.processed/core/api/debug/modules/general_info.d.ts +3 -0
  31. package/dist/_esm5.processed/core/api/debug/modules/general_info.js +180 -0
  32. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.d.ts +4 -0
  33. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_content.js +121 -0
  34. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.d.ts +3 -0
  35. package/dist/_esm5.processed/core/api/debug/modules/segment_buffer_size.js +35 -0
  36. package/dist/_esm5.processed/core/api/debug/render.d.ts +3 -0
  37. package/dist/_esm5.processed/core/api/debug/render.js +32 -0
  38. package/dist/_esm5.processed/core/api/debug/utils.d.ts +39 -0
  39. package/dist/_esm5.processed/core/api/debug/utils.js +57 -0
  40. package/dist/_esm5.processed/core/api/playback_observer.js +4 -2
  41. package/dist/_esm5.processed/core/api/public_api.d.ts +60 -3
  42. package/dist/_esm5.processed/core/api/public_api.js +280 -60
  43. package/dist/_esm5.processed/core/api/track_management/media_element_tracks_store.js +10 -1
  44. package/dist/_esm5.processed/core/api/track_management/track_dispatcher.d.ts +13 -1
  45. package/dist/_esm5.processed/core/api/track_management/track_dispatcher.js +30 -15
  46. package/dist/_esm5.processed/core/api/track_management/tracks_store.d.ts +3 -1
  47. package/dist/_esm5.processed/core/api/track_management/tracks_store.js +67 -152
  48. package/dist/_esm5.processed/core/api/utils.d.ts +10 -0
  49. package/dist/_esm5.processed/core/api/utils.js +23 -3
  50. package/dist/_esm5.processed/core/decrypt/__tests__/__global__/utils.d.ts +27 -8
  51. package/dist/_esm5.processed/core/decrypt/__tests__/__global__/utils.js +28 -7
  52. package/dist/_esm5.processed/core/decrypt/attach_media_keys.js +1 -1
  53. package/dist/_esm5.processed/core/decrypt/content_decryptor.js +1 -1
  54. package/dist/_esm5.processed/core/decrypt/find_key_system.js +29 -6
  55. package/dist/_esm5.processed/core/decrypt/session_events_listener.js +42 -32
  56. package/dist/_esm5.processed/core/decrypt/utils/check_key_statuses.js +4 -0
  57. package/dist/_esm5.processed/core/decrypt/utils/clean_old_loaded_sessions.js +2 -0
  58. package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +5 -1
  59. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.d.ts +17 -8
  60. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.js +10 -6
  61. package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.js +5 -4
  62. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +22 -5
  63. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +37 -21
  64. package/dist/_esm5.processed/core/fetchers/segment/task_prioritizer.js +21 -23
  65. package/dist/_esm5.processed/core/fetchers/utils/schedule_request.js +17 -7
  66. package/dist/_esm5.processed/core/init/directfile_content_initializer.js +2 -2
  67. package/dist/_esm5.processed/core/init/media_source_content_initializer.js +74 -41
  68. package/dist/_esm5.processed/core/init/types.d.ts +9 -1
  69. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.d.ts +28 -1
  70. package/dist/_esm5.processed/core/init/utils/content_time_boundaries_observer.js +24 -11
  71. package/dist/_esm5.processed/core/init/utils/create_media_source.js +3 -12
  72. package/dist/_esm5.processed/core/init/utils/end_of_stream.js +6 -3
  73. package/dist/_esm5.processed/core/init/utils/get_loaded_reference.js +2 -1
  74. package/dist/_esm5.processed/core/init/utils/initial_seek_and_play.js +9 -5
  75. package/dist/_esm5.processed/core/init/utils/initialize_content_decryption.js +2 -1
  76. package/dist/_esm5.processed/core/init/utils/media_source_duration_updater.d.ts +58 -0
  77. package/dist/_esm5.processed/core/init/utils/{media_duration_updater.js → media_source_duration_updater.js} +87 -86
  78. package/dist/_esm5.processed/core/init/utils/rebuffering_controller.d.ts +36 -2
  79. package/dist/_esm5.processed/core/init/utils/rebuffering_controller.js +83 -3
  80. package/dist/_esm5.processed/core/init/utils/stream_events_emitter/stream_events_emitter.js +6 -4
  81. package/dist/_esm5.processed/core/init/utils/throw_on_media_error.js +1 -1
  82. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.d.ts +18 -7
  83. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +38 -50
  84. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.d.ts +8 -0
  85. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +16 -2
  86. package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.d.ts +8 -0
  87. package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.js +12 -0
  88. package/dist/_esm5.processed/core/segment_buffers/implementations/types.d.ts +11 -4
  89. package/dist/_esm5.processed/core/segment_buffers/index.d.ts +2 -2
  90. package/dist/_esm5.processed/core/segment_buffers/segment_buffers_store.js +13 -9
  91. package/dist/_esm5.processed/core/stream/adaptation/adaptation_stream.js +30 -16
  92. package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.d.ts +47 -0
  93. package/dist/_esm5.processed/core/stream/adaptation/utils/create_representation_estimator.js +70 -0
  94. package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +41 -20
  95. package/dist/_esm5.processed/core/stream/period/period_stream.js +12 -11
  96. package/dist/_esm5.processed/core/stream/representation/representation_stream.js +37 -28
  97. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.d.ts +4 -2
  98. package/dist/_esm5.processed/core/stream/representation/utils/append_segment_to_buffer.js +3 -3
  99. package/dist/_esm5.processed/core/stream/representation/utils/downloading_queue.js +16 -6
  100. package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.d.ts +3 -2
  101. package/dist/_esm5.processed/core/stream/representation/utils/push_init_segment.js +8 -8
  102. package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.d.ts +2 -2
  103. package/dist/_esm5.processed/core/stream/representation/utils/push_media_segment.js +2 -3
  104. package/dist/_esm5.processed/core/stream/utils/create_reload_request.js +1 -1
  105. package/dist/_esm5.processed/default_config.d.ts +41 -0
  106. package/dist/_esm5.processed/default_config.js +46 -2
  107. package/dist/_esm5.processed/errors/index.d.ts +2 -2
  108. package/dist/_esm5.processed/errors/media_error.d.ts +23 -1
  109. package/dist/_esm5.processed/errors/media_error.js +18 -5
  110. package/dist/_esm5.processed/experimental/features/debug_element.d.ts +8 -0
  111. package/dist/_esm5.processed/experimental/features/debug_element.js +10 -0
  112. package/dist/_esm5.processed/experimental/features/index.d.ts +1 -0
  113. package/dist/_esm5.processed/experimental/features/index.js +1 -0
  114. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.d.ts +1 -1
  115. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/load_and_push_segment.js +8 -7
  116. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.js +7 -4
  117. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +24 -12
  118. package/dist/_esm5.processed/experimental/tools/mediaCapabilitiesProber/index.js +0 -2
  119. package/dist/_esm5.processed/features/features_object.js +1 -0
  120. package/dist/_esm5.processed/features/initialize_features.js +13 -10
  121. package/dist/_esm5.processed/features/types.d.ts +3 -0
  122. package/dist/_esm5.processed/manifest/adaptation.d.ts +21 -2
  123. package/dist/_esm5.processed/manifest/adaptation.js +80 -1
  124. package/dist/_esm5.processed/manifest/manifest.js +2 -0
  125. package/dist/_esm5.processed/manifest/period.js +2 -2
  126. package/dist/_esm5.processed/manifest/representation.d.ts +33 -2
  127. package/dist/_esm5.processed/manifest/representation.js +32 -4
  128. package/dist/_esm5.processed/manifest/utils.js +1 -3
  129. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_adaptation_sets.js +105 -137
  130. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +25 -5
  131. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.d.ts +1 -1
  132. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/parse_from_document.js +1 -1
  133. package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.js +1 -0
  134. package/dist/_esm5.processed/public_types.d.ts +13 -3
  135. package/dist/_esm5.processed/tools/TextTrackRenderer/text_track_renderer.js +1 -1
  136. package/dist/_esm5.processed/transports/dash/add_segment_integrity_checks_to_loader.js +15 -11
  137. package/dist/_esm5.processed/transports/dash/low_latency_segment_loader.js +2 -2
  138. package/dist/_esm5.processed/transports/dash/manifest_parser.js +1 -1
  139. package/dist/_esm5.processed/transports/dash/segment_loader.js +4 -4
  140. package/dist/_esm5.processed/transports/local/segment_loader.js +13 -26
  141. package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.d.ts +4 -6
  142. package/dist/_esm5.processed/transports/smooth/isobmff/create_boxes.js +4 -6
  143. package/dist/_esm5.processed/transports/smooth/segment_loader.js +4 -4
  144. package/dist/_esm5.processed/transports/utils/call_custom_manifest_loader.js +3 -3
  145. package/dist/_esm5.processed/utils/cancellable_sleep.js +4 -10
  146. package/dist/_esm5.processed/utils/create_cancellable_promise.d.ts +26 -0
  147. package/dist/_esm5.processed/utils/create_cancellable_promise.js +52 -0
  148. package/dist/_esm5.processed/utils/is_null_or_undefined.d.ts +1 -1
  149. package/dist/_esm5.processed/utils/is_null_or_undefined.js +1 -1
  150. package/dist/_esm5.processed/utils/reference.js +6 -0
  151. package/dist/_esm5.processed/utils/request/xhr.js +1 -1
  152. package/dist/_esm5.processed/utils/task_canceller.d.ts +34 -15
  153. package/dist/_esm5.processed/utils/task_canceller.js +55 -22
  154. package/dist/mpd-parser.wasm +0 -0
  155. package/dist/rx-player.js +5424 -4712
  156. package/dist/rx-player.min.js +1 -1
  157. package/jest.config.js +1 -5
  158. package/package.json +44 -40
  159. package/scripts/build/constants.d.ts +1 -0
  160. package/scripts/build/generate_build.js +1 -1
  161. package/scripts/fast_demo_build.js +40 -40
  162. package/scripts/generate_full_demo.js +1 -1
  163. package/sonar-project.properties +1 -1
  164. package/src/compat/browser_detection.ts +105 -52
  165. package/src/compat/can_reuse_media_keys.ts +5 -2
  166. package/src/compat/eme/close_session.ts +2 -2
  167. package/src/compat/eme/load_session.ts +1 -1
  168. package/src/compat/event_listeners.ts +1 -1
  169. package/src/compat/has_issues_with_high_media_source_duration.ts +27 -0
  170. package/src/core/adaptive/__tests__/buffer_based_chooser.test.ts +147 -48
  171. package/src/core/adaptive/adaptive_representation_selector.ts +11 -6
  172. package/src/core/adaptive/buffer_based_chooser.ts +144 -26
  173. package/src/core/adaptive/guess_based_chooser.ts +9 -8
  174. package/src/core/adaptive/network_analyzer.ts +9 -4
  175. package/src/core/adaptive/utils/representation_score_calculator.ts +22 -2
  176. package/src/core/api/debug/buffer_graph.ts +247 -0
  177. package/src/core/api/debug/buffer_size_graph.ts +130 -0
  178. package/src/core/api/debug/constants.ts +2 -0
  179. package/src/core/api/debug/index.ts +3 -0
  180. package/src/core/api/debug/modules/general_info.ts +184 -0
  181. package/src/core/api/debug/modules/segment_buffer_content.ts +155 -0
  182. package/src/core/api/debug/modules/segment_buffer_size.ts +48 -0
  183. package/src/core/api/debug/render.ts +40 -0
  184. package/src/core/api/debug/utils.ts +103 -0
  185. package/src/core/api/playback_observer.ts +5 -2
  186. package/src/core/api/public_api.ts +334 -73
  187. package/src/core/api/track_management/media_element_tracks_store.ts +17 -8
  188. package/src/core/api/track_management/track_dispatcher.ts +37 -14
  189. package/src/core/api/track_management/tracks_store.ts +77 -167
  190. package/src/core/api/utils.ts +29 -3
  191. package/src/core/decrypt/__tests__/__global__/utils.ts +61 -40
  192. package/src/core/decrypt/attach_media_keys.ts +1 -1
  193. package/src/core/decrypt/content_decryptor.ts +1 -1
  194. package/src/core/decrypt/find_key_system.ts +25 -11
  195. package/src/core/decrypt/session_events_listener.ts +45 -39
  196. package/src/core/decrypt/utils/check_key_statuses.ts +6 -0
  197. package/src/core/decrypt/utils/clean_old_loaded_sessions.ts +2 -1
  198. package/src/core/decrypt/utils/loaded_sessions_store.ts +8 -1
  199. package/src/core/fetchers/cdn_prioritizer.ts +18 -9
  200. package/src/core/fetchers/manifest/manifest_fetcher.ts +5 -4
  201. package/src/core/fetchers/segment/segment_fetcher.ts +36 -14
  202. package/src/core/fetchers/segment/task_prioritizer.ts +25 -30
  203. package/src/core/fetchers/utils/schedule_request.ts +18 -7
  204. package/src/core/init/directfile_content_initializer.ts +2 -1
  205. package/src/core/init/media_source_content_initializer.ts +89 -50
  206. package/src/core/init/types.ts +9 -1
  207. package/src/core/init/utils/content_time_boundaries_observer.ts +48 -12
  208. package/src/core/init/utils/create_media_source.ts +4 -16
  209. package/src/core/init/utils/end_of_stream.ts +6 -3
  210. package/src/core/init/utils/get_loaded_reference.ts +2 -1
  211. package/src/core/init/utils/initial_seek_and_play.ts +9 -5
  212. package/src/core/init/utils/initialize_content_decryption.ts +2 -1
  213. package/src/core/init/utils/{media_duration_updater.ts → media_source_duration_updater.ts} +103 -110
  214. package/src/core/init/utils/rebuffering_controller.ts +115 -4
  215. package/src/core/init/utils/stream_events_emitter/stream_events_emitter.ts +6 -4
  216. package/src/core/init/utils/throw_on_media_error.ts +1 -1
  217. package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +63 -66
  218. package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +20 -2
  219. package/src/core/segment_buffers/implementations/text/native/native_text_segment_buffer.ts +16 -0
  220. package/src/core/segment_buffers/implementations/types.ts +16 -4
  221. package/src/core/segment_buffers/index.ts +2 -0
  222. package/src/core/segment_buffers/segment_buffers_store.ts +16 -13
  223. package/src/core/stream/adaptation/adaptation_stream.ts +33 -19
  224. package/src/core/stream/adaptation/utils/create_representation_estimator.ts +114 -0
  225. package/src/core/stream/orchestrator/stream_orchestrator.ts +42 -20
  226. package/src/core/stream/period/period_stream.ts +13 -11
  227. package/src/core/stream/representation/representation_stream.ts +49 -37
  228. package/src/core/stream/representation/utils/append_segment_to_buffer.ts +9 -4
  229. package/src/core/stream/representation/utils/downloading_queue.ts +16 -4
  230. package/src/core/stream/representation/utils/push_init_segment.ts +11 -6
  231. package/src/core/stream/representation/utils/push_media_segment.ts +3 -3
  232. package/src/core/stream/utils/create_reload_request.ts +1 -1
  233. package/src/default_config.ts +59 -11
  234. package/src/errors/__tests__/media_error.test.ts +6 -6
  235. package/src/errors/index.ts +4 -1
  236. package/src/errors/media_error.ts +67 -1
  237. package/src/experimental/features/__tests__/debug_element.test.ts +26 -0
  238. package/src/experimental/features/debug_element.ts +13 -0
  239. package/src/experimental/features/index.ts +1 -0
  240. package/src/experimental/tools/VideoThumbnailLoader/load_and_push_segment.ts +10 -7
  241. package/src/experimental/tools/VideoThumbnailLoader/prepare_source_buffer.ts +7 -4
  242. package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +25 -10
  243. package/src/experimental/tools/mediaCapabilitiesProber/index.ts +0 -4
  244. package/src/features/__tests__/initialize_features.test.ts +11 -0
  245. package/src/features/features_object.ts +1 -0
  246. package/src/features/initialize_features.ts +15 -10
  247. package/src/features/types.ts +9 -0
  248. package/src/manifest/__tests__/manifest.test.ts +7 -7
  249. package/src/manifest/__tests__/period.test.ts +90 -45
  250. package/src/manifest/adaptation.ts +96 -1
  251. package/src/manifest/manifest.ts +4 -0
  252. package/src/manifest/period.ts +4 -2
  253. package/src/manifest/representation.ts +77 -5
  254. package/src/manifest/utils.ts +1 -3
  255. package/src/parsers/manifest/dash/common/parse_adaptation_sets.ts +116 -151
  256. package/src/parsers/manifest/dash/common/parse_representations.ts +21 -4
  257. package/src/parsers/manifest/dash/js-parser/parse_from_document.ts +1 -1
  258. package/src/parsers/manifest/dash/wasm-parser/ts/dash-wasm-parser.ts +1 -0
  259. package/src/parsers/texttracks/ttml/parse_ttml.ts +1 -1
  260. package/src/public_types.ts +16 -1
  261. package/src/tools/TextTrackRenderer/text_track_renderer.ts +1 -1
  262. package/src/transports/dash/add_segment_integrity_checks_to_loader.ts +31 -22
  263. package/src/transports/dash/low_latency_segment_loader.ts +2 -2
  264. package/src/transports/dash/manifest_parser.ts +1 -1
  265. package/src/transports/dash/segment_loader.ts +4 -4
  266. package/src/transports/local/segment_loader.ts +14 -30
  267. package/src/transports/smooth/isobmff/create_boxes.ts +4 -6
  268. package/src/transports/smooth/segment_loader.ts +4 -4
  269. package/src/transports/utils/call_custom_manifest_loader.ts +3 -3
  270. package/src/typings/globals.d.ts +21 -19
  271. package/src/utils/cancellable_sleep.ts +5 -14
  272. package/src/utils/create_cancellable_promise.ts +69 -0
  273. package/src/utils/is_null_or_undefined.ts +1 -1
  274. package/src/utils/reference.ts +6 -0
  275. package/src/utils/request/xhr.ts +1 -1
  276. package/src/utils/task_canceller.ts +63 -34
  277. package/tsconfig.json +1 -1
  278. package/tsconfig.modules.json +1 -1
  279. package/dist/_esm5.processed/core/init/utils/media_duration_updater.d.ts +0 -56
  280. package/locked_reps.js +0 -46
  281. package/scripts/doc-generator/construct_table_of_contents.js +0 -76
  282. package/scripts/doc-generator/convert_MD_to_HMTL.js +0 -26
  283. package/scripts/doc-generator/create_documentation.js +0 -331
  284. package/scripts/doc-generator/create_documentation_page.js +0 -209
  285. package/scripts/doc-generator/create_page.js +0 -210
  286. package/scripts/doc-generator/generate_header_html.js +0 -147
  287. package/scripts/doc-generator/generate_page_html.js +0 -115
  288. package/scripts/doc-generator/generate_page_list_html.js +0 -92
  289. package/scripts/doc-generator/generate_sidebar_html.js +0 -85
  290. package/scripts/doc-generator/get_search_data_for_content.js +0 -137
  291. package/scripts/doc-generator/index.js +0 -34
  292. package/scripts/doc-generator/parse_doc_configs.js +0 -327
  293. package/scripts/doc-generator/scripts/lunr.js +0 -10
  294. package/scripts/doc-generator/scripts/script.js +0 -451
  295. package/scripts/doc-generator/styles/code.css +0 -99
  296. package/scripts/doc-generator/styles/style.css +0 -835
  297. package/scripts/doc-generator/utils.js +0 -74
@@ -21,10 +21,8 @@ import {
21
21
  import config from "../../../../config";
22
22
  import log from "../../../../log";
23
23
  import { getLoggableSegmentId } from "../../../../manifest";
24
- import areArraysOfNumbersEqual from "../../../../utils/are_arrays_of_numbers_equal";
25
24
  import assertUnreachable from "../../../../utils/assert_unreachable";
26
- import { toUint8Array } from "../../../../utils/byte_parsing";
27
- import hashBuffer from "../../../../utils/hash_buffer";
25
+ import createCancellablePromise from "../../../../utils/create_cancellable_promise";
28
26
  import noop from "../../../../utils/noop";
29
27
  import objectAssign from "../../../../utils/object_assign";
30
28
  import TaskCanceller, {
@@ -138,20 +136,26 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
138
136
  private _pendingTask : IAVSBPendingTask | null;
139
137
 
140
138
  /**
141
- * Keep track of the of the latest init segment pushed in the linked
142
- * SourceBuffer.
139
+ * Keep track of the unique identifier of the of the latest init segment
140
+ * pushed to the linked SourceBuffer.
143
141
  *
144
- * This allows to be sure the right initialization segment is pushed before
145
- * any chunk is.
142
+ * Such identifiers are first declared through the `declareInitSegment`
143
+ * method and the corresponding initialization segment is then pushed through
144
+ * the `pushChunk` method.
145
+ *
146
+ * Keeping track of this allows to be sure the right initialization segment is
147
+ * pushed before any chunk is.
146
148
  *
147
149
  * `null` if no initialization segment have been pushed to the
148
150
  * `AudioVideoSegmentBuffer` yet.
149
151
  */
150
- private _lastInitSegment : { /** The init segment itself. */
151
- data : Uint8Array;
152
- /** Hash of the initSegment for fast comparison */
153
- hash : number; } |
154
- null;
152
+ private _lastInitSegmentUniqueId : string | null;
153
+
154
+ /**
155
+ * Link unique identifiers for initialization segments (as communicated by
156
+ * `declareInitSegment`) to the corresponding initialization data.
157
+ */
158
+ private _initSegmentsMap : Map<string, BufferSource>;
155
159
 
156
160
  /**
157
161
  * @constructor
@@ -173,8 +177,9 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
173
177
  this._sourceBuffer = sourceBuffer;
174
178
  this._queue = [];
175
179
  this._pendingTask = null;
176
- this._lastInitSegment = null;
180
+ this._lastInitSegmentUniqueId = null;
177
181
  this.codec = codec;
182
+ this._initSegmentsMap = new Map();
178
183
 
179
184
  const onError = this._onPendingTaskError.bind(this);
180
185
  const reCheck = this._flush.bind(this);
@@ -197,6 +202,20 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
197
202
  });
198
203
  }
199
204
 
205
+ public declareInitSegment(
206
+ uniqueId : string,
207
+ initSegmentData : unknown
208
+ ) : void {
209
+ assertDataIsBufferSource(initSegmentData);
210
+ this._initSegmentsMap.set(uniqueId, initSegmentData);
211
+ }
212
+
213
+ public freeInitSegment(
214
+ uniqueId : string
215
+ ) : void {
216
+ this._initSegmentsMap.delete(uniqueId);
217
+ }
218
+
200
219
  /**
201
220
  * Push a chunk of the media segment given to the attached SourceBuffer, in a
202
221
  * FIFO queue.
@@ -228,12 +247,12 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
228
247
  infos : IPushChunkInfos<unknown>,
229
248
  cancellationSignal : CancellationSignal
230
249
  ) : Promise<void> {
231
- assertPushedDataIsBufferSource(infos);
250
+ assertDataIsBufferSource(infos.data.chunk);
232
251
  log.debug("AVSB: receiving order to push data to the SourceBuffer",
233
252
  this.bufferType,
234
253
  getLoggableSegmentId(infos.inventoryInfos));
235
254
  return this._addToQueue({ type: SegmentBufferOperation.Push,
236
- value: infos },
255
+ value: infos as IPushChunkInfos<BufferSource> },
237
256
  cancellationSignal);
238
257
  }
239
258
 
@@ -349,7 +368,7 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
349
368
  * @param {Event} err
350
369
  */
351
370
  private _onPendingTaskError(err : unknown) : void {
352
- this._lastInitSegment = null; // initialize init segment as a security
371
+ this._lastInitSegmentUniqueId = null; // initialize init segment as a security
353
372
  if (this._pendingTask !== null) {
354
373
  const error = err instanceof Error ?
355
374
  err :
@@ -369,15 +388,15 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
369
388
  operation : ISBOperation<BufferSource>,
370
389
  cancellationSignal : CancellationSignal
371
390
  ) : Promise<void> {
372
- return new Promise((resolve, reject) => {
373
- if (cancellationSignal.cancellationError !== null) {
374
- return reject(cancellationSignal.cancellationError);
375
- }
391
+ return createCancellablePromise(cancellationSignal, (resolve, reject) => {
376
392
  const shouldRestartQueue = this._queue.length === 0 &&
377
393
  this._pendingTask === null;
378
394
  const queueItem = objectAssign({ resolve, reject }, operation);
379
395
  this._queue.push(queueItem);
380
- cancellationSignal.register((error : CancellationError) => {
396
+ if (shouldRestartQueue) {
397
+ this._flush();
398
+ }
399
+ return () => {
381
400
  // Remove the corresponding element from the AudioVideoSegmentBuffer's
382
401
  // queue.
383
402
  // If the operation was a pending task, it should still continue to not
@@ -388,12 +407,7 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
388
407
  }
389
408
  queueItem.resolve = noop;
390
409
  queueItem.reject = noop;
391
- reject(error);
392
- });
393
-
394
- if (shouldRestartQueue) {
395
- this._flush();
396
- }
410
+ };
397
411
  });
398
412
  }
399
413
 
@@ -451,7 +465,7 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
451
465
  const error = e instanceof Error ?
452
466
  e :
453
467
  new Error("An unknown error occured when preparing a push operation");
454
- this._lastInitSegment = null; // initialize init segment as a security
468
+ this._lastInitSegmentUniqueId = null; // initialize init segment as a security
455
469
  nextItem.reject(error);
456
470
  return;
457
471
  }
@@ -561,15 +575,17 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
561
575
  this._sourceBuffer.appendWindowEnd = appendWindow[1];
562
576
  }
563
577
 
564
- if (data.initSegment !== null &&
565
- (hasUpdatedSourceBufferType || !this._isLastInitSegment(data.initSegment)))
578
+ if (data.initSegmentUniqueId !== null &&
579
+ (hasUpdatedSourceBufferType ||
580
+ !this._isLastInitSegment(data.initSegmentUniqueId)))
566
581
  {
567
582
  // Push initialization segment before the media segment
568
- const segmentData = data.initSegment;
583
+ const segmentData = this._initSegmentsMap.get(data.initSegmentUniqueId);
584
+ if (segmentData === undefined) {
585
+ throw new Error("Invalid initialization segment uniqueId");
586
+ }
569
587
  dataToPush.push(segmentData);
570
- const initU8 = toUint8Array(segmentData);
571
- this._lastInitSegment = { data: initU8,
572
- hash: hashBuffer(initU8) };
588
+ this._lastInitSegmentUniqueId = data.initSegmentUniqueId;
573
589
  }
574
590
 
575
591
  if (data.chunk !== null) {
@@ -580,28 +596,16 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
580
596
  }
581
597
 
582
598
  /**
583
- * Return `true` if the given `segmentData` is the same segment than the last
599
+ * Return `true` if the given `uniqueId` is the identifier of the last
584
600
  * initialization segment pushed to the `AudioVideoSegmentBuffer`.
585
- * @param {BufferSource} segmentData
601
+ * @param {string} uniqueId
586
602
  * @returns {boolean}
587
603
  */
588
- private _isLastInitSegment(segmentData : BufferSource) : boolean {
589
- if (this._lastInitSegment === null) {
604
+ private _isLastInitSegment(uniqueId : string) : boolean {
605
+ if (this._lastInitSegmentUniqueId === null) {
590
606
  return false;
591
607
  }
592
- if (this._lastInitSegment.data === segmentData) {
593
- return true;
594
- }
595
- const oldInit = this._lastInitSegment.data;
596
- if (oldInit.byteLength === segmentData.byteLength) {
597
- const newInitU8 = toUint8Array(segmentData);
598
- if (hashBuffer(newInitU8) === this._lastInitSegment.hash &&
599
- areArraysOfNumbersEqual(oldInit, newInitU8))
600
- {
601
- return true;
602
- }
603
- }
604
- return false;
608
+ return this._lastInitSegmentUniqueId === uniqueId;
605
609
  }
606
610
  }
607
611
 
@@ -609,27 +613,20 @@ export default class AudioVideoSegmentBuffer extends SegmentBuffer {
609
613
  * Throw if the given input is not in the expected format.
610
614
  * Allows to enforce runtime type-checking as compile-time type-checking here is
611
615
  * difficult to enforce.
612
- * @param {Object} pushedData
616
+ * @param {Object} data
613
617
  */
614
- function assertPushedDataIsBufferSource(
615
- pushedData : IPushChunkInfos<unknown>
616
- ) : asserts pushedData is IPushChunkInfos<BufferSource> {
618
+ function assertDataIsBufferSource(
619
+ data : unknown
620
+ ) : asserts data is BufferSource {
617
621
  if (__ENVIRONMENT__.CURRENT_ENV === __ENVIRONMENT__.PRODUCTION as number) {
618
622
  return;
619
623
  }
620
- const { chunk, initSegment } = pushedData.data;
621
624
  if (
622
- typeof chunk !== "object" ||
623
- typeof initSegment !== "object" ||
624
- (
625
- chunk !== null &&
626
- !(chunk instanceof ArrayBuffer) &&
627
- !((chunk as ArrayBufferView).buffer instanceof ArrayBuffer)
628
- ) ||
625
+ typeof data !== "object" ||
629
626
  (
630
- initSegment !== null &&
631
- !(initSegment instanceof ArrayBuffer) &&
632
- !((initSegment as ArrayBufferView).buffer instanceof ArrayBuffer)
627
+ data !== null &&
628
+ !(data instanceof ArrayBuffer) &&
629
+ !((data as ArrayBufferView).buffer instanceof ArrayBuffer)
633
630
  )
634
631
  ) {
635
632
  throw new Error("Invalid data given to the AudioVideoSegmentBuffer");
@@ -137,6 +137,22 @@ export default class HTMLTextSegmentBuffer extends SegmentBuffer {
137
137
  this.autoRefreshSubtitles(this._canceller.signal);
138
138
  }
139
139
 
140
+ /**
141
+ * @param {string} uniqueId
142
+ */
143
+ public declareInitSegment(uniqueId : string): void {
144
+ log.warn("ISB: Declaring initialization segment for image SegmentBuffer",
145
+ uniqueId);
146
+ }
147
+
148
+ /**
149
+ * @param {string} uniqueId
150
+ */
151
+ public freeInitSegment(uniqueId : string): void {
152
+ log.warn("ISB: Freeing initialization segment for image SegmentBuffer",
153
+ uniqueId);
154
+ }
155
+
140
156
  /**
141
157
  * Push text segment to the HTMLTextSegmentBuffer.
142
158
  * @param {Object} infos
@@ -353,7 +369,8 @@ export default class HTMLTextSegmentBuffer extends SegmentBuffer {
353
369
  element : HTMLElement; } => cue.resolution !== null);
354
370
 
355
371
  if (proportionalCues.length > 0) {
356
- this._sizeUpdateCanceller = new TaskCanceller({ cancelOn: this._canceller.signal });
372
+ this._sizeUpdateCanceller = new TaskCanceller();
373
+ this._sizeUpdateCanceller.linkToSignal(this._canceller.signal);
357
374
  const { TEXT_TRACK_SIZE_CHECKS_INTERVAL } = config.getCurrent();
358
375
  // update propertionally-sized elements periodically
359
376
  const heightWidthRef = onHeightWidthChange(this._textTrackElement,
@@ -382,7 +399,8 @@ export default class HTMLTextSegmentBuffer extends SegmentBuffer {
382
399
 
383
400
  const startAutoRefresh = () => {
384
401
  stopAutoRefresh();
385
- autoRefreshCanceller = new TaskCanceller({ cancelOn: cancellationSignal });
402
+ autoRefreshCanceller = new TaskCanceller();
403
+ autoRefreshCanceller.linkToSignal(cancellationSignal);
386
404
  const intervalId = setInterval(() => this.refreshSubtitles(),
387
405
  MAXIMUM_HTML_TEXT_TRACK_UPDATE_INTERVAL);
388
406
  autoRefreshCanceller.signal.register(() => {
@@ -61,6 +61,22 @@ export default class NativeTextSegmentBuffer extends SegmentBuffer {
61
61
  this._trackElement = trackElement;
62
62
  }
63
63
 
64
+ /**
65
+ * @param {string} uniqueId
66
+ */
67
+ public declareInitSegment(uniqueId : string): void {
68
+ log.warn("ISB: Declaring initialization segment for image SegmentBuffer",
69
+ uniqueId);
70
+ }
71
+
72
+ /**
73
+ * @param {string} uniqueId
74
+ */
75
+ public freeInitSegment(uniqueId : string): void {
76
+ log.warn("ISB: Freeing initialization segment for image SegmentBuffer",
77
+ uniqueId);
78
+ }
79
+
64
80
  /**
65
81
  * @param {Object} infos
66
82
  * @returns {Promise}
@@ -87,6 +87,13 @@ export abstract class SegmentBuffer {
87
87
  this._segmentInventory = new SegmentInventory();
88
88
  }
89
89
 
90
+ public abstract declareInitSegment(
91
+ uniqueId : string,
92
+ initSegmentData : unknown
93
+ ) : void;
94
+
95
+ public abstract freeInitSegment(uniqueId : string) : void;
96
+
90
97
  /**
91
98
  * Push a chunk of the media segment given to the attached buffer, in a
92
99
  * FIFO queue.
@@ -96,7 +103,8 @@ export abstract class SegmentBuffer {
96
103
  * pushed.
97
104
  *
98
105
  * Depending on the type of data appended, the pushed chunk might rely on an
99
- * initialization segment, given through the `data.initSegment` property.
106
+ * initialization segment, which had to be previously declared through the
107
+ * `declareInitSegment` method.
100
108
  *
101
109
  * Such initialization segment will be first pushed to the buffer if the
102
110
  * last pushed segment was associated to another initialization segment.
@@ -106,7 +114,7 @@ export abstract class SegmentBuffer {
106
114
  * reference).
107
115
  *
108
116
  * If you don't need any initialization segment to push the wanted chunk, you
109
- * can just set `data.initSegment` to `null`.
117
+ * can just set the corresponding property to `null`.
110
118
  *
111
119
  * You can also only push an initialization segment by setting the
112
120
  * `data.chunk` argument to null.
@@ -229,12 +237,16 @@ export type IBufferType = "audio" |
229
237
  */
230
238
  export interface IPushedChunkData<T> {
231
239
  /**
232
- * The whole initialization segment's data related to the chunk you want to
240
+ * The `uniqueId` of the initialization segment linked to the data you want to
233
241
  * push.
242
+ *
243
+ * That identifier should previously have been declared through the
244
+ * `declareInitSegment` method and not freed.
245
+ *
234
246
  * To set to `null` either if no initialization data is needed, or if you are
235
247
  * confident that the last pushed one is compatible.
236
248
  */
237
- initSegment: T | null;
249
+ initSegmentUniqueId : string | null;
238
250
  /**
239
251
  * Chunk you want to push.
240
252
  * This can be the whole decodable segment's data or just a decodable sub-part
@@ -30,6 +30,7 @@ import {
30
30
  import {
31
31
  IBufferedChunk,
32
32
  IChunkContext,
33
+ IInsertedChunkInfos,
33
34
  getFirstSegmentAfterPeriod,
34
35
  getLastSegmentBeforePeriod,
35
36
  } from "./inventory";
@@ -51,6 +52,7 @@ export {
51
52
 
52
53
  IBufferedChunk,
53
54
  IChunkContext,
55
+ IInsertedChunkInfos,
54
56
 
55
57
  IPushChunkInfos,
56
58
  IPushedChunkData,
@@ -17,10 +17,8 @@
17
17
  import { MediaError } from "../../errors";
18
18
  import features from "../../features";
19
19
  import log from "../../log";
20
- import {
21
- CancellationError,
22
- CancellationSignal,
23
- } from "../../utils/task_canceller";
20
+ import createCancellablePromise from "../../utils/create_cancellable_promise";
21
+ import { CancellationSignal } from "../../utils/task_canceller";
24
22
  import {
25
23
  AudioVideoSegmentBuffer,
26
24
  IBufferType,
@@ -189,21 +187,26 @@ export default class SegmentBuffersStore {
189
187
  if (this._areNativeBuffersUsable()) {
190
188
  return Promise.resolve();
191
189
  }
192
- return new Promise((res, rej) => {
193
- const onAddedOrDisabled = () => {
190
+ return createCancellablePromise(cancelWaitSignal, (res) => {
191
+ /* eslint-disable-next-line prefer-const */
192
+ let onAddedOrDisabled : () => void;
193
+
194
+ const removeCallback = () => {
195
+ const indexOf = this._onNativeBufferAddedOrDisabled.indexOf(onAddedOrDisabled);
196
+ if (indexOf >= 0) {
197
+ this._onNativeBufferAddedOrDisabled.splice(indexOf, 1);
198
+ }
199
+ };
200
+
201
+ onAddedOrDisabled = () => {
194
202
  if (this._areNativeBuffersUsable()) {
203
+ removeCallback();
195
204
  res();
196
205
  }
197
206
  };
198
207
  this._onNativeBufferAddedOrDisabled.push(onAddedOrDisabled);
199
208
 
200
- cancelWaitSignal.register((error : CancellationError) => {
201
- const indexOf = this._onNativeBufferAddedOrDisabled.indexOf(onAddedOrDisabled);
202
- if (indexOf >= 0) {
203
- this._onNativeBufferAddedOrDisabled.splice(indexOf, 1);
204
- }
205
- rej(error);
206
- });
209
+ return removeCallback;
207
210
  });
208
211
  }
209
212
 
@@ -3,6 +3,8 @@ import { formatError } from "../../../errors";
3
3
  import log from "../../../log";
4
4
  import { Representation } from "../../../manifest";
5
5
  import assertUnreachable from "../../../utils/assert_unreachable";
6
+ import cancellableSleep from "../../../utils/cancellable_sleep";
7
+ import noop from "../../../utils/noop";
6
8
  import objectAssign from "../../../utils/object_assign";
7
9
  import {
8
10
  createMappedReference,
@@ -69,7 +71,8 @@ export default function AdaptationStream<T>(
69
71
  const { manifest, period, adaptation } = content;
70
72
 
71
73
  /** Allows to cancel everything the `AdaptationStream` is doing. */
72
- const adapStreamCanceller = new TaskCanceller({ cancelOn: parentCancelSignal });
74
+ const adapStreamCanceller = new TaskCanceller();
75
+ adapStreamCanceller.linkToSignal(parentCancelSignal);
73
76
 
74
77
  /**
75
78
  * The buffer goal ratio base itself on the value given by `wantedBufferAhead`
@@ -144,9 +147,10 @@ export default function AdaptationStream<T>(
144
147
  cancelCurrentStreams.cancel();
145
148
  }
146
149
  representationsList.setValueIfChanged(val.representations);
147
- cancelCurrentStreams = new TaskCanceller({ cancelOn: adapStreamCanceller.signal });
150
+ cancelCurrentStreams = new TaskCanceller();
151
+ cancelCurrentStreams.linkToSignal(adapStreamCanceller.signal);
148
152
  onRepresentationsChoiceChange(val, cancelCurrentStreams.signal).catch((err) => {
149
- if (cancelCurrentStreams?.isUsed === true &&
153
+ if (cancelCurrentStreams?.isUsed() === true &&
150
154
  TaskCanceller.isCancellationError(err))
151
155
  {
152
156
  return;
@@ -195,13 +199,13 @@ export default function AdaptationStream<T>(
195
199
  case "clean-buffer": // Just clean
196
200
  for (const range of switchStrat.value) {
197
201
  await segmentBuffer.removeBuffer(range.start, range.end, fnCancelSignal);
198
- if (fnCancelSignal.isCancelled) {
202
+ if (fnCancelSignal.isCancelled()) {
199
203
  return;
200
204
  }
201
205
  }
202
206
  if (switchStrat.type === "flush-buffer") {
203
207
  callbacks.needsBufferFlush();
204
- if (fnCancelSignal.isCancelled) {
208
+ if (fnCancelSignal.isCancelled()) {
205
209
  return;
206
210
  }
207
211
  }
@@ -229,7 +233,8 @@ export default function AdaptationStream<T>(
229
233
  * terminating and as such the next one might be immediately created
230
234
  * recursively.
231
235
  */
232
- const repStreamTerminatingCanceller = new TaskCanceller({ cancelOn: fnCancelSignal });
236
+ const repStreamTerminatingCanceller = new TaskCanceller();
237
+ repStreamTerminatingCanceller.linkToSignal(fnCancelSignal);
233
238
  const { representation } = estimateRef.getValue();
234
239
  if (representation === null) {
235
240
  return;
@@ -263,11 +268,11 @@ export default function AdaptationStream<T>(
263
268
 
264
269
  const repInfo = { type: adaptation.type, period, representation };
265
270
  currentRepresentation.setValue(representation);
266
- if (adapStreamCanceller.isUsed) {
271
+ if (adapStreamCanceller.isUsed()) {
267
272
  return ; // previous callback has stopped everything by side-effect
268
273
  }
269
274
  callbacks.representationChange(repInfo);
270
- if (adapStreamCanceller.isUsed) {
275
+ if (adapStreamCanceller.isUsed()) {
271
276
  return ; // previous callback has stopped everything by side-effect
272
277
  }
273
278
 
@@ -284,13 +289,13 @@ export default function AdaptationStream<T>(
284
289
  },
285
290
  addedSegment(segmentInfo) {
286
291
  abrCallbacks.addedSegment(segmentInfo);
287
- if (adapStreamCanceller.isUsed) {
292
+ if (adapStreamCanceller.isUsed()) {
288
293
  return;
289
294
  }
290
295
  callbacks.addedSegment(segmentInfo);
291
296
  },
292
297
  terminating() {
293
- if (repStreamTerminatingCanceller.isUsed) {
298
+ if (repStreamTerminatingCanceller.isUsed()) {
294
299
  return; // Already handled
295
300
  }
296
301
  repStreamTerminatingCanceller.cancel();
@@ -322,7 +327,8 @@ export default function AdaptationStream<T>(
322
327
  representationStreamCallbacks : IRepresentationStreamCallbacks<T>,
323
328
  fnCancelSignal : CancellationSignal
324
329
  ) : void {
325
- const bufferGoalCanceller = new TaskCanceller({ cancelOn: fnCancelSignal });
330
+ const bufferGoalCanceller = new TaskCanceller();
331
+ bufferGoalCanceller.linkToSignal(fnCancelSignal);
326
332
  const bufferGoal = createMappedReference(wantedBufferAhead, prev => {
327
333
  return prev * getBufferGoalRatio(representation);
328
334
  }, bufferGoalCanceller.signal);
@@ -339,19 +345,27 @@ export default function AdaptationStream<T>(
339
345
  defaultCode: "NONE",
340
346
  defaultReason: "Unknown `RepresentationStream` error",
341
347
  });
342
- if (formattedError.code === "BUFFER_FULL_ERROR") {
348
+ if (formattedError.code !== "BUFFER_FULL_ERROR") {
349
+ representationStreamCallbacks.error(err);
350
+ } else {
343
351
  const wba = wantedBufferAhead.getValue();
344
352
  const lastBufferGoalRatio = bufferGoalRatioMap.get(representation.id) ?? 1;
345
- if (lastBufferGoalRatio <= 0.25 || wba * lastBufferGoalRatio <= 2) {
353
+ // 70%, 49%, 34.3%, 24%, 16.81%, 11.76%, 8.24% and 5.76%
354
+ const newBufferGoalRatio = lastBufferGoalRatio * 0.7;
355
+ if (newBufferGoalRatio <= 0.05 || wba * newBufferGoalRatio <= 2) {
346
356
  throw formattedError;
347
357
  }
348
- bufferGoalRatioMap.set(representation.id, lastBufferGoalRatio - 0.25);
349
- return createRepresentationStream(representation,
350
- terminateCurrentStream,
351
- representationStreamCallbacks,
352
- fnCancelSignal);
358
+ bufferGoalRatioMap.set(representation.id, newBufferGoalRatio);
359
+
360
+ // We wait 4 seconds to let the situation evolve by itself before
361
+ // retrying loading segments with a lower buffer goal
362
+ cancellableSleep(4000, adapStreamCanceller.signal).then(() => {
363
+ return createRepresentationStream(representation,
364
+ terminateCurrentStream,
365
+ representationStreamCallbacks,
366
+ fnCancelSignal);
367
+ }).catch(noop);
353
368
  }
354
- representationStreamCallbacks.error(err);
355
369
  },
356
370
  terminating() {
357
371
  bufferGoalCanceller.cancel();
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Copyright 2015 CANAL+ Group
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { MediaError } from "../../../../errors";
18
+ import Manifest, {
19
+ Adaptation,
20
+ Period,
21
+ Representation,
22
+ } from "../../../../manifest";
23
+ import { IPlayerError } from "../../../../public_types";
24
+ import createSharedReference, {
25
+ IReadOnlySharedReference,
26
+ } from "../../../../utils/reference";
27
+ import { CancellationSignal } from "../../../../utils/task_canceller";
28
+ import {
29
+ IABREstimate,
30
+ IRepresentationEstimatorPlaybackObservation,
31
+ IRepresentationEstimator,
32
+ IRepresentationEstimatorCallbacks,
33
+ } from "../../../adaptive";
34
+ import { IReadOnlyPlaybackObserver } from "../../../api";
35
+
36
+ /**
37
+ * Produce estimates to know which Representation should be played.
38
+ * @param {Object} content - The Manifest, Period and Adaptation wanted.
39
+ * @param {Object} representationEstimator - `IRepresentationEstimator` which
40
+ * will produce Representation estimates.
41
+ * @param {Object} currentRepresentation - Reference emitting the
42
+ * currently-loaded Representation.
43
+ * @param {Object} playbackObserver - Allows to observe the current playback
44
+ * conditions.
45
+ * @param {Function} onFatalError - Callback called when a fatal error was
46
+ * thrown. Once this callback is called, no estimate will be produced.
47
+ * @param {Object} cancellationSignal - `CancellationSignal` allowing to abort
48
+ * the production of estimates (and clean-up all linked resources).
49
+ * @returns {Object} - Returns an object with the following properties:
50
+ * - `estimateRef`: Reference emitting the last estimate
51
+ * - `abrCallbacks`: Callbacks allowing to report back network and playback
52
+ * activities to improve the estimates given.
53
+ */
54
+ export default function getRepresentationEstimate(
55
+ content : { manifest : Manifest;
56
+ period : Period;
57
+ adaptation : Adaptation; },
58
+ representationEstimator : IRepresentationEstimator,
59
+ currentRepresentation : IReadOnlySharedReference<Representation | null>,
60
+ playbackObserver : IReadOnlyPlaybackObserver<
61
+ IRepresentationEstimatorPlaybackObservation
62
+ >,
63
+ onFatalError: (err : IPlayerError) => void,
64
+ cancellationSignal : CancellationSignal
65
+ ) : { estimateRef : IReadOnlySharedReference<IABREstimate>;
66
+ abrCallbacks : IRepresentationEstimatorCallbacks; }
67
+ {
68
+ const { manifest, adaptation } = content;
69
+ const representations = createSharedReference<Representation[]>(
70
+ [],
71
+ cancellationSignal);
72
+ updateRepresentationsReference();
73
+ manifest.addEventListener("decipherabilityUpdate", updateRepresentationsReference);
74
+ const unregisterCleanUp = cancellationSignal.register(cleanUp);
75
+ const { estimates: estimateRef,
76
+ callbacks: abrCallbacks } = representationEstimator(content,
77
+ currentRepresentation,
78
+ representations,
79
+ playbackObserver,
80
+ cancellationSignal);
81
+ return { abrCallbacks, estimateRef };
82
+
83
+ function updateRepresentationsReference() : void {
84
+ /** Representations for which a `RepresentationStream` can be created. */
85
+ const newRepr = adaptation.getPlayableRepresentations();
86
+ if (newRepr.length === 0) {
87
+ const noRepErr = new MediaError("NO_PLAYABLE_REPRESENTATION",
88
+ "No Representation in the chosen " +
89
+ adaptation.type + " Adaptation can be played",
90
+ { adaptation });
91
+ cleanUp();
92
+ onFatalError(noRepErr);
93
+ return;
94
+ }
95
+
96
+ const prevRepr = representations.getValue();
97
+ if (prevRepr.length === newRepr.length) {
98
+ if (prevRepr.every((r, idx) => r.id === newRepr[idx].id)) {
99
+ return ;
100
+ }
101
+ }
102
+ representations.setValue(newRepr);
103
+ }
104
+
105
+ /** Clean-up all resources taken here. */
106
+ function cleanUp() : void {
107
+ manifest.removeEventListener("decipherabilityUpdate", updateRepresentationsReference);
108
+
109
+ // check to protect against the case where it is not yet defined.
110
+ if (typeof unregisterCleanUp !== "undefined") {
111
+ unregisterCleanUp();
112
+ }
113
+ }
114
+ }