rx-player 4.5.0-dev.2026033100 → 4.5.0-dev.2026041501

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 (251) hide show
  1. package/CHANGELOG.md +22 -5
  2. package/VERSION +1 -1
  3. package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
  4. package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.js +1 -1
  5. package/dist/commonjs/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
  6. package/dist/commonjs/__GENERATED_CODE/embedded_worker.js +1 -1
  7. package/dist/commonjs/compat/can_patch_out_pssh.d.ts +42 -0
  8. package/dist/commonjs/compat/can_patch_out_pssh.d.ts.map +1 -0
  9. package/dist/commonjs/compat/can_patch_out_pssh.js +53 -0
  10. package/dist/commonjs/compat/env_detector.d.ts +2 -0
  11. package/dist/commonjs/compat/env_detector.d.ts.map +1 -1
  12. package/dist/commonjs/compat/env_detector.js +5 -0
  13. package/dist/commonjs/core/adaptive/network_analyzer.d.ts +1 -2
  14. package/dist/commonjs/core/adaptive/network_analyzer.d.ts.map +1 -1
  15. package/dist/commonjs/core/adaptive/network_analyzer.js +3 -3
  16. package/dist/commonjs/core/adaptive/utils/representation_score_calculator.js +2 -2
  17. package/dist/commonjs/core/cmcd/cmcd_data_builder.d.ts.map +1 -1
  18. package/dist/commonjs/core/cmcd/cmcd_data_builder.js +9 -3
  19. package/dist/commonjs/core/entry/content_preparer.d.ts.map +1 -1
  20. package/dist/commonjs/core/entry/content_preparer.js +5 -7
  21. package/dist/commonjs/core/entry/core_entry.d.ts.map +1 -1
  22. package/dist/commonjs/core/entry/core_entry.js +6 -2
  23. package/dist/commonjs/core/entry/core_text_displayer_interface.js +3 -3
  24. package/dist/commonjs/core/fetchers/manifest/manifest_fetcher.d.ts.map +1 -1
  25. package/dist/commonjs/core/fetchers/manifest/manifest_fetcher.js +12 -0
  26. package/dist/commonjs/core/fetchers/thumbnails/thumbnail_fetcher.js +1 -1
  27. package/dist/commonjs/core/fetchers/utils/schedule_request.d.ts.map +1 -1
  28. package/dist/commonjs/core/fetchers/utils/schedule_request.js +4 -3
  29. package/dist/commonjs/core/segment_sinks/garbage_collector.d.ts +0 -2
  30. package/dist/commonjs/core/segment_sinks/garbage_collector.d.ts.map +1 -1
  31. package/dist/commonjs/core/segment_sinks/garbage_collector.js +0 -3
  32. package/dist/commonjs/core/segment_sinks/implementations/text/text_segment_sink.d.ts +1 -1
  33. package/dist/commonjs/core/segment_sinks/implementations/text/text_segment_sink.d.ts.map +1 -1
  34. package/dist/commonjs/core/segment_sinks/implementations/text/text_segment_sink.js +2 -2
  35. package/dist/commonjs/core/stream/adaptation/adaptation_stream.d.ts.map +1 -1
  36. package/dist/commonjs/core/stream/adaptation/adaptation_stream.js +6 -6
  37. package/dist/commonjs/core/stream/orchestrator/stream_orchestrator.d.ts.map +1 -1
  38. package/dist/commonjs/core/stream/orchestrator/stream_orchestrator.js +37 -40
  39. package/dist/commonjs/default_config.d.ts +5 -0
  40. package/dist/commonjs/default_config.d.ts.map +1 -1
  41. package/dist/commonjs/default_config.js +5 -0
  42. package/dist/commonjs/main_thread/api/public_api.d.ts.map +1 -1
  43. package/dist/commonjs/main_thread/api/public_api.js +23 -16
  44. package/dist/commonjs/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
  45. package/dist/commonjs/main_thread/decrypt/content_decryptor.js +4 -1
  46. package/dist/commonjs/main_thread/decrypt/session_events_listener.js +1 -1
  47. package/dist/commonjs/main_thread/decrypt/set_server_certificate.d.ts +2 -0
  48. package/dist/commonjs/main_thread/decrypt/set_server_certificate.d.ts.map +1 -1
  49. package/dist/commonjs/main_thread/decrypt/set_server_certificate.js +4 -0
  50. package/dist/commonjs/main_thread/init/media_source_content_initializer.d.ts +0 -8
  51. package/dist/commonjs/main_thread/init/media_source_content_initializer.d.ts.map +1 -1
  52. package/dist/commonjs/main_thread/init/media_source_content_initializer.js +58 -50
  53. package/dist/commonjs/main_thread/init/utils/stream_events_emitter/stream_events_emitter.d.ts +35 -5
  54. package/dist/commonjs/main_thread/init/utils/stream_events_emitter/stream_events_emitter.d.ts.map +1 -1
  55. package/dist/commonjs/main_thread/init/utils/stream_events_emitter/stream_events_emitter.js +60 -19
  56. package/dist/commonjs/main_thread/render_thumbnail.d.ts.map +1 -1
  57. package/dist/commonjs/main_thread/render_thumbnail.js +4 -0
  58. package/dist/commonjs/main_thread/tracks_store/media_element_tracks_store.d.ts.map +1 -1
  59. package/dist/commonjs/main_thread/tracks_store/media_element_tracks_store.js +1 -0
  60. package/dist/commonjs/main_thread/tracks_store/tracks_store.d.ts +1 -1
  61. package/dist/commonjs/main_thread/tracks_store/tracks_store.js +1 -1
  62. package/dist/{es2017/parsers/containers/isobmff/take_pssh_out.d.ts → commonjs/parsers/containers/isobmff/extract_pssh.d.ts} +6 -4
  63. package/dist/commonjs/parsers/containers/isobmff/extract_pssh.d.ts.map +1 -0
  64. package/dist/commonjs/parsers/containers/isobmff/{take_pssh_out.js → extract_pssh.js} +22 -17
  65. package/dist/commonjs/parsers/containers/isobmff/index.d.ts +2 -2
  66. package/dist/commonjs/parsers/containers/isobmff/index.d.ts.map +1 -1
  67. package/dist/commonjs/parsers/containers/isobmff/index.js +4 -4
  68. package/dist/commonjs/playback_observer/core_playback_observer.d.ts +4 -4
  69. package/dist/commonjs/playback_observer/core_playback_observer.d.ts.map +1 -1
  70. package/dist/commonjs/playback_observer/media_element_playback_observer.d.ts +1 -2
  71. package/dist/commonjs/playback_observer/media_element_playback_observer.d.ts.map +1 -1
  72. package/dist/commonjs/transports/dash/segment_parser.js +1 -1
  73. package/dist/commonjs/transports/local/segment_parser.js +1 -1
  74. package/dist/commonjs/utils/test-utils.d.ts +30 -0
  75. package/dist/commonjs/utils/test-utils.d.ts.map +1 -0
  76. package/dist/commonjs/utils/test-utils.js +79 -0
  77. package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
  78. package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.js +1 -1
  79. package/dist/es2017/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
  80. package/dist/es2017/__GENERATED_CODE/embedded_worker.js +1 -1
  81. package/dist/es2017/compat/can_patch_out_pssh.d.ts +42 -0
  82. package/dist/es2017/compat/can_patch_out_pssh.d.ts.map +1 -0
  83. package/dist/es2017/compat/can_patch_out_pssh.js +50 -0
  84. package/dist/es2017/compat/env_detector.d.ts +2 -0
  85. package/dist/es2017/compat/env_detector.d.ts.map +1 -1
  86. package/dist/es2017/compat/env_detector.js +5 -0
  87. package/dist/es2017/core/adaptive/network_analyzer.d.ts +1 -2
  88. package/dist/es2017/core/adaptive/network_analyzer.d.ts.map +1 -1
  89. package/dist/es2017/core/adaptive/network_analyzer.js +3 -3
  90. package/dist/es2017/core/adaptive/utils/representation_score_calculator.js +2 -2
  91. package/dist/es2017/core/cmcd/cmcd_data_builder.d.ts.map +1 -1
  92. package/dist/es2017/core/cmcd/cmcd_data_builder.js +9 -3
  93. package/dist/es2017/core/entry/content_preparer.d.ts.map +1 -1
  94. package/dist/es2017/core/entry/content_preparer.js +3 -5
  95. package/dist/es2017/core/entry/core_entry.d.ts.map +1 -1
  96. package/dist/es2017/core/entry/core_entry.js +6 -2
  97. package/dist/es2017/core/entry/core_text_displayer_interface.js +3 -3
  98. package/dist/es2017/core/fetchers/manifest/manifest_fetcher.d.ts.map +1 -1
  99. package/dist/es2017/core/fetchers/manifest/manifest_fetcher.js +12 -0
  100. package/dist/es2017/core/fetchers/thumbnails/thumbnail_fetcher.js +1 -1
  101. package/dist/es2017/core/fetchers/utils/schedule_request.d.ts.map +1 -1
  102. package/dist/es2017/core/fetchers/utils/schedule_request.js +2 -3
  103. package/dist/es2017/core/segment_sinks/garbage_collector.d.ts +0 -2
  104. package/dist/es2017/core/segment_sinks/garbage_collector.d.ts.map +1 -1
  105. package/dist/es2017/core/segment_sinks/garbage_collector.js +0 -3
  106. package/dist/es2017/core/segment_sinks/implementations/text/text_segment_sink.d.ts +1 -1
  107. package/dist/es2017/core/segment_sinks/implementations/text/text_segment_sink.d.ts.map +1 -1
  108. package/dist/es2017/core/segment_sinks/implementations/text/text_segment_sink.js +2 -2
  109. package/dist/es2017/core/stream/adaptation/adaptation_stream.d.ts.map +1 -1
  110. package/dist/es2017/core/stream/adaptation/adaptation_stream.js +6 -6
  111. package/dist/es2017/core/stream/orchestrator/stream_orchestrator.d.ts.map +1 -1
  112. package/dist/es2017/core/stream/orchestrator/stream_orchestrator.js +40 -39
  113. package/dist/es2017/default_config.d.ts +5 -0
  114. package/dist/es2017/default_config.d.ts.map +1 -1
  115. package/dist/es2017/default_config.js +5 -0
  116. package/dist/es2017/main_thread/api/public_api.d.ts.map +1 -1
  117. package/dist/es2017/main_thread/api/public_api.js +20 -13
  118. package/dist/es2017/main_thread/decrypt/content_decryptor.d.ts.map +1 -1
  119. package/dist/es2017/main_thread/decrypt/content_decryptor.js +4 -1
  120. package/dist/es2017/main_thread/decrypt/session_events_listener.js +1 -1
  121. package/dist/es2017/main_thread/decrypt/set_server_certificate.d.ts +2 -0
  122. package/dist/es2017/main_thread/decrypt/set_server_certificate.d.ts.map +1 -1
  123. package/dist/es2017/main_thread/decrypt/set_server_certificate.js +4 -0
  124. package/dist/es2017/main_thread/init/media_source_content_initializer.d.ts +0 -8
  125. package/dist/es2017/main_thread/init/media_source_content_initializer.d.ts.map +1 -1
  126. package/dist/es2017/main_thread/init/media_source_content_initializer.js +58 -50
  127. package/dist/es2017/main_thread/init/utils/stream_events_emitter/stream_events_emitter.d.ts +35 -5
  128. package/dist/es2017/main_thread/init/utils/stream_events_emitter/stream_events_emitter.d.ts.map +1 -1
  129. package/dist/es2017/main_thread/init/utils/stream_events_emitter/stream_events_emitter.js +60 -19
  130. package/dist/es2017/main_thread/render_thumbnail.d.ts.map +1 -1
  131. package/dist/es2017/main_thread/render_thumbnail.js +4 -0
  132. package/dist/es2017/main_thread/tracks_store/media_element_tracks_store.d.ts.map +1 -1
  133. package/dist/es2017/main_thread/tracks_store/media_element_tracks_store.js +1 -0
  134. package/dist/es2017/main_thread/tracks_store/tracks_store.d.ts +1 -1
  135. package/dist/es2017/main_thread/tracks_store/tracks_store.js +1 -1
  136. package/dist/{commonjs/parsers/containers/isobmff/take_pssh_out.d.ts → es2017/parsers/containers/isobmff/extract_pssh.d.ts} +6 -4
  137. package/dist/es2017/parsers/containers/isobmff/extract_pssh.d.ts.map +1 -0
  138. package/dist/es2017/parsers/containers/isobmff/{take_pssh_out.js → extract_pssh.js} +21 -16
  139. package/dist/es2017/parsers/containers/isobmff/index.d.ts +2 -2
  140. package/dist/es2017/parsers/containers/isobmff/index.d.ts.map +1 -1
  141. package/dist/es2017/parsers/containers/isobmff/index.js +2 -2
  142. package/dist/es2017/playback_observer/core_playback_observer.d.ts +4 -4
  143. package/dist/es2017/playback_observer/core_playback_observer.d.ts.map +1 -1
  144. package/dist/es2017/playback_observer/media_element_playback_observer.d.ts +1 -2
  145. package/dist/es2017/playback_observer/media_element_playback_observer.d.ts.map +1 -1
  146. package/dist/es2017/transports/dash/segment_parser.js +2 -2
  147. package/dist/es2017/transports/local/segment_parser.js +2 -2
  148. package/dist/es2017/utils/test-utils.d.ts +30 -0
  149. package/dist/es2017/utils/test-utils.d.ts.map +1 -0
  150. package/dist/es2017/utils/test-utils.js +36 -0
  151. package/dist/mpd-parser.wasm +0 -0
  152. package/dist/worker.js +6 -6
  153. package/package.json +4 -2
  154. package/src/README.md +7 -7
  155. package/src/__GENERATED_CODE/embedded_dash_wasm.ts +1 -1
  156. package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
  157. package/src/compat/__tests__/can_patch_out_pssh.test.ts +40 -0
  158. package/src/compat/can_patch_out_pssh.ts +53 -0
  159. package/src/compat/env_detector.ts +4 -0
  160. package/src/core/README.md +1 -1
  161. package/src/core/adaptive/README.md +3 -3
  162. package/src/core/adaptive/__tests__/adaptive_representation_selector.test.ts +181 -110
  163. package/src/core/adaptive/__tests__/guess_based_chooser.test.ts +229 -123
  164. package/src/core/adaptive/__tests__/mocks.ts +100 -0
  165. package/src/core/adaptive/__tests__/network_analyzer.test.ts +152 -59
  166. package/src/core/adaptive/network_analyzer.ts +4 -4
  167. package/src/core/adaptive/utils/__tests__/filter_by_bitrate.test.ts +11 -19
  168. package/src/core/adaptive/utils/__tests__/filter_by_resolution.test.ts +12 -12
  169. package/src/core/adaptive/utils/__tests__/last_estimate_storage.test.ts +25 -12
  170. package/src/core/adaptive/utils/__tests__/pending_requests_store.test.ts +13 -9
  171. package/src/core/adaptive/utils/__tests__/representation_score_calculator.test.ts +11 -11
  172. package/src/core/adaptive/utils/__tests__/select_optimal_representation.test.ts +13 -23
  173. package/src/core/adaptive/utils/representation_score_calculator.ts +2 -2
  174. package/src/core/cmcd/__tests__/cmcd_data_builder.test.ts +60 -15
  175. package/src/core/cmcd/cmcd_data_builder.ts +9 -3
  176. package/src/core/entry/README.md +2 -2
  177. package/src/core/entry/__tests__/core_text_displayer_interface.test.ts +20 -0
  178. package/src/core/entry/content_preparer.ts +2 -5
  179. package/src/core/entry/core_entry.ts +6 -2
  180. package/src/core/entry/core_text_displayer_interface.ts +3 -3
  181. package/src/core/fetchers/manifest/__tests__/manifest_fetcher.test.ts +52 -3
  182. package/src/core/fetchers/manifest/manifest_fetcher.ts +12 -0
  183. package/src/core/fetchers/thumbnails/__tests__/thumbnail_fetcher.test.ts +70 -0
  184. package/src/core/fetchers/thumbnails/thumbnail_fetcher.ts +1 -1
  185. package/src/core/fetchers/utils/schedule_request.ts +5 -3
  186. package/src/core/segment_sinks/__tests__/garbage_collector.test.ts +434 -0
  187. package/src/core/segment_sinks/__tests__/mocks.ts +49 -0
  188. package/src/core/segment_sinks/garbage_collector.ts +0 -3
  189. package/src/core/segment_sinks/implementations/text/__tests__/text_segment_sink.test.ts +177 -0
  190. package/src/core/segment_sinks/implementations/text/text_segment_sink.ts +2 -2
  191. package/src/core/segment_sinks/inventory/__tests__/buffered_history.test.ts +215 -0
  192. package/src/core/segment_sinks/inventory/__tests__/segment_inventory.test.ts +448 -0
  193. package/src/core/stream/adaptation/__tests__/adaptation_stream.test.ts +973 -0
  194. package/src/core/stream/adaptation/__tests__/get_representations_switch_strategy.test.ts +283 -374
  195. package/src/core/stream/adaptation/adaptation_stream.ts +6 -8
  196. package/src/core/stream/orchestrator/README.md +4 -4
  197. package/src/core/stream/orchestrator/__tests__/stream_orchestrator.test.ts +707 -0
  198. package/src/core/stream/orchestrator/stream_orchestrator.ts +41 -46
  199. package/src/core/stream/period/utils/__tests__/get_adaptation_switch_strategy.test.ts +290 -220
  200. package/src/core/stream/representation/__tests__/encryption_data_notifier.test.ts +93 -63
  201. package/src/core/stream/representation/utils/__tests__/append_segment_to_buffer.test.ts +106 -63
  202. package/src/core/stream/representation/utils/__tests__/check_for_discontinuity.test.ts +179 -204
  203. package/src/core/stream/representation/utils/__tests__/get_segment_priority.test.ts +7 -7
  204. package/src/core/stream/representation/utils/__tests__/push_init_segment.test.ts +103 -60
  205. package/src/core/stream/representation/utils/__tests__/push_media_segment.test.ts +231 -165
  206. package/src/default_config.ts +6 -0
  207. package/src/experimental/README.md +1 -1
  208. package/src/features/README.md +3 -3
  209. package/src/main_thread/api/README.md +6 -7
  210. package/src/main_thread/api/public_api.ts +16 -10
  211. package/src/main_thread/decrypt/README.md +4 -4
  212. package/src/main_thread/decrypt/__tests__/__global__/content_decryptor.test.ts +135 -0
  213. package/src/main_thread/decrypt/__tests__/__global__/get_license.test.ts +70 -0
  214. package/src/main_thread/decrypt/__tests__/__global__/server_certificate.test.ts +44 -0
  215. package/src/main_thread/decrypt/__tests__/__global__/utils.ts +2 -2
  216. package/src/main_thread/decrypt/content_decryptor.ts +6 -1
  217. package/src/main_thread/decrypt/session_events_listener.ts +1 -1
  218. package/src/main_thread/decrypt/set_server_certificate.ts +5 -0
  219. package/src/main_thread/init/media_source_content_initializer.ts +69 -55
  220. package/src/main_thread/init/utils/__tests__/stream_events_emitter.test.ts +175 -0
  221. package/src/main_thread/init/utils/stream_events_emitter/stream_events_emitter.ts +90 -26
  222. package/src/main_thread/render_thumbnail.ts +4 -0
  223. package/src/main_thread/tracks_store/README.md +12 -0
  224. package/src/main_thread/tracks_store/__tests__/media_element_tracks_store.test.ts +25 -18
  225. package/src/main_thread/tracks_store/media_element_tracks_store.ts +1 -0
  226. package/src/main_thread/tracks_store/tracks_store.ts +1 -1
  227. package/src/manifest/classes/__tests__/mocks.ts +202 -0
  228. package/src/parsers/containers/isobmff/__tests__/extract_pssh.test.ts +199 -0
  229. package/src/parsers/containers/isobmff/{take_pssh_out.ts → extract_pssh.ts} +21 -17
  230. package/src/parsers/containers/isobmff/index.ts +2 -2
  231. package/src/parsers/manifest/dash/wasm-parser/README.md +9 -9
  232. package/src/playback_observer/__tests__/mocks.ts +152 -0
  233. package/src/playback_observer/core_playback_observer.ts +4 -4
  234. package/src/playback_observer/media_element_playback_observer.ts +1 -1
  235. package/src/tools/README.md +2 -2
  236. package/src/transports/README.md +5 -5
  237. package/src/transports/dash/segment_parser.ts +2 -2
  238. package/src/transports/local/segment_parser.ts +2 -2
  239. package/src/transports/metaplaylist/README.md +4 -4
  240. package/src/utils/README.md +3 -3
  241. package/src/utils/test-utils.ts +50 -0
  242. package/dist/commonjs/core/entry/synchronize_sinks_on_observation.d.ts +0 -11
  243. package/dist/commonjs/core/entry/synchronize_sinks_on_observation.d.ts.map +0 -1
  244. package/dist/commonjs/core/entry/synchronize_sinks_on_observation.js +0 -20
  245. package/dist/commonjs/parsers/containers/isobmff/take_pssh_out.d.ts.map +0 -1
  246. package/dist/es2017/core/entry/synchronize_sinks_on_observation.d.ts +0 -11
  247. package/dist/es2017/core/entry/synchronize_sinks_on_observation.d.ts.map +0 -1
  248. package/dist/es2017/core/entry/synchronize_sinks_on_observation.js +0 -17
  249. package/dist/es2017/parsers/containers/isobmff/take_pssh_out.d.ts.map +0 -1
  250. package/src/core/adaptive/utils/__tests__/bandwith_estimator.test.ts +0 -117
  251. package/src/core/entry/synchronize_sinks_on_observation.ts +0 -22
@@ -1,15 +1,22 @@
1
1
  import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
2
  import type { IRepresentation } from "../../../manifest";
3
+ import {
4
+ DummyRepresentation,
5
+ DummyAdaptation,
6
+ DummyPeriod,
7
+ DummyManifest,
8
+ createSegment,
9
+ } from "../../../manifest/classes/__tests__/mocks";
10
+ import noop from "../../../utils/noop";
11
+ import { makeMockedClass } from "../../../utils/test-utils";
3
12
  import GuessBasedChooser from "../guess_based_chooser";
13
+ import type LastEstimateStorage from "../utils/last_estimate_storage";
4
14
  import { ABRAlgorithmType } from "../utils/last_estimate_storage";
5
15
  import type { IRequestInfo } from "../utils/pending_requests_store";
6
16
  import type { IRepresentationMaintainabilityScore } from "../utils/representation_score_calculator";
17
+ import type RepresentationScoreCalculator from "../utils/representation_score_calculator";
7
18
  import { ScoreConfidenceLevel } from "../utils/representation_score_calculator";
8
19
 
9
- /* eslint-disable @typescript-eslint/no-explicit-any */
10
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
11
- /* eslint-disable @typescript-eslint/no-unsafe-argument */
12
-
13
20
  const mocks = vi.hoisted(() => ({
14
21
  estimateRequestBandwidth: vi.fn(),
15
22
  getMonotonicTimeStamp: vi.fn(),
@@ -21,26 +28,18 @@ vi.mock("../../../log", () => ({
21
28
  error: vi.fn(),
22
29
  },
23
30
  }));
24
-
25
- vi.mock("../../../utils/array_find_index", () => ({
26
- // eslint-disable-next-line no-restricted-properties
27
- default: vi.fn((arr, predicate) => arr.findIndex(predicate)),
28
- }));
29
-
30
31
  vi.mock("../../../utils/monotonic_timestamp", () => ({
31
32
  default: mocks.getMonotonicTimeStamp,
32
33
  }));
33
-
34
34
  vi.mock("../network_analyzer", () => ({
35
35
  estimateRequestBandwidth: mocks.estimateRequestBandwidth,
36
36
  }));
37
37
 
38
- // Helper functions
39
38
  function createRepresentation(id: string, bitrate: number): IRepresentation {
40
- return {
39
+ return new DummyRepresentation({
41
40
  id,
42
41
  bitrate,
43
- } as IRepresentation;
42
+ });
44
43
  }
45
44
 
46
45
  function createScoreData(
@@ -58,41 +57,53 @@ function createRequest(
58
57
  ): IRequestInfo {
59
58
  return {
60
59
  content: {
61
- representation: { id: representationId } as IRepresentation,
62
- segment: {
60
+ representation: new DummyRepresentation({
61
+ id: representationId,
62
+ }),
63
+ segment: createSegment({
63
64
  duration: segmentDuration,
64
65
  isInit,
65
- },
66
+ }),
67
+ adaptation: new DummyAdaptation(),
68
+ period: new DummyPeriod(),
69
+ manifest: new DummyManifest(),
66
70
  },
67
71
  requestTimestamp,
68
- } as IRequestInfo;
72
+ progress: [],
73
+ };
69
74
  }
70
75
 
76
+ const DummyScoreCalculator = makeMockedClass<RepresentationScoreCalculator>(
77
+ {
78
+ addSample: noop,
79
+ getEstimate: () => createScoreData(1, ScoreConfidenceLevel.LOW),
80
+ getLastStableRepresentation: () => null,
81
+ },
82
+ {},
83
+ );
84
+ const DummyLastEstimateStorage = makeMockedClass<LastEstimateStorage>(
85
+ {
86
+ update: noop,
87
+ },
88
+ { bandwidth: undefined, representation: null, algorithmType: ABRAlgorithmType.None },
89
+ );
90
+
71
91
  describe("GuessBasedChooser", () => {
72
- let mockScoreCalculator: any;
73
- let mockPrevEstimate: any;
74
- let representations: IRepresentation[];
92
+ let mockScoreCalculator: RepresentationScoreCalculator;
93
+ let mockLastEstimateStorage: LastEstimateStorage;
94
+
95
+ const representations = [
96
+ createRepresentation("rep-1", 100000),
97
+ createRepresentation("rep-2", 500000),
98
+ createRepresentation("rep-3", 1000000),
99
+ createRepresentation("rep-4", 2000000),
100
+ createRepresentation("rep-5", 3000000),
101
+ ];
75
102
 
76
103
  beforeEach(() => {
77
104
  mocks.getMonotonicTimeStamp.mockReturnValue(10000);
78
-
79
- // Setup mock representations (sorted by bitrate ascending)
80
- representations = [
81
- createRepresentation("rep-1", 100000),
82
- createRepresentation("rep-2", 500000),
83
- createRepresentation("rep-3", 1000000),
84
- createRepresentation("rep-4", 2000000),
85
- createRepresentation("rep-5", 3000000),
86
- ];
87
-
88
- mockScoreCalculator = {
89
- getEstimate: vi.fn(),
90
- };
91
-
92
- mockPrevEstimate = {
93
- representation: null,
94
- algorithmType: ABRAlgorithmType.GuessBased,
95
- };
105
+ mockScoreCalculator = new DummyScoreCalculator();
106
+ mockLastEstimateStorage = new DummyLastEstimateStorage();
96
107
  });
97
108
 
98
109
  afterEach(() => {
@@ -101,7 +112,7 @@ describe("GuessBasedChooser", () => {
101
112
 
102
113
  describe("constructor", () => {
103
114
  it("should initialize with correct default values", () => {
104
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
115
+ const chooser = new GuessBasedChooser(mockScoreCalculator, mockLastEstimateStorage);
105
116
  expect(chooser).toBeDefined();
106
117
  });
107
118
  });
@@ -109,8 +120,11 @@ describe("GuessBasedChooser", () => {
109
120
  describe("getGuess", () => {
110
121
  describe("when last chosen representation is null", () => {
111
122
  it("should return null - nothing to base guess on", () => {
112
- mockPrevEstimate.representation = null;
113
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
123
+ mockLastEstimateStorage.representation = null;
124
+ const chooser = new GuessBasedChooser(
125
+ mockScoreCalculator,
126
+ mockLastEstimateStorage,
127
+ );
114
128
 
115
129
  const result = chooser.getGuess(
116
130
  representations,
@@ -126,10 +140,13 @@ describe("GuessBasedChooser", () => {
126
140
 
127
141
  describe("when incomingBestBitrate > lastChosenRep.bitrate", () => {
128
142
  it("should return null - ABR estimates are already superior", () => {
129
- mockPrevEstimate.representation = representations[1]; // 500000
130
- mockPrevEstimate.algorithmType = ABRAlgorithmType.GuessBased;
143
+ mockLastEstimateStorage.representation = representations[1]; // 500000
144
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.GuessBased;
131
145
 
132
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
146
+ const chooser = new GuessBasedChooser(
147
+ mockScoreCalculator,
148
+ mockLastEstimateStorage,
149
+ );
133
150
 
134
151
  const result = chooser.getGuess(
135
152
  representations,
@@ -143,10 +160,13 @@ describe("GuessBasedChooser", () => {
143
160
  });
144
161
 
145
162
  it("should reset consecutive wrong guesses when algorithm was GuessBased", () => {
146
- mockPrevEstimate.representation = representations[1];
147
- mockPrevEstimate.algorithmType = ABRAlgorithmType.GuessBased;
163
+ mockLastEstimateStorage.representation = representations[1];
164
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.GuessBased;
148
165
 
149
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
166
+ const chooser = new GuessBasedChooser(
167
+ mockScoreCalculator,
168
+ mockLastEstimateStorage,
169
+ );
150
170
 
151
171
  // First call should reset counter
152
172
  chooser.getGuess(
@@ -172,14 +192,17 @@ describe("GuessBasedChooser", () => {
172
192
 
173
193
  describe("when not in guessing mode yet", () => {
174
194
  beforeEach(() => {
175
- mockPrevEstimate.representation = representations[1];
176
- mockPrevEstimate.algorithmType = ABRAlgorithmType.BufferBased;
195
+ mockLastEstimateStorage.representation = representations[1];
196
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.BufferBased;
177
197
  });
178
198
 
179
199
  it("should return null when score data is undefined", () => {
180
- mockScoreCalculator.getEstimate.mockReturnValue(undefined);
200
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(undefined);
181
201
 
182
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
202
+ const chooser = new GuessBasedChooser(
203
+ mockScoreCalculator,
204
+ mockLastEstimateStorage,
205
+ );
183
206
 
184
207
  const result = chooser.getGuess(
185
208
  representations,
@@ -193,11 +216,13 @@ describe("GuessBasedChooser", () => {
193
216
  });
194
217
 
195
218
  it("should return next representation when conditions allow guessing higher", () => {
196
- mockScoreCalculator.getEstimate.mockReturnValue(
219
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
197
220
  createScoreData(1.5, ScoreConfidenceLevel.HIGH),
198
221
  );
199
-
200
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
222
+ const chooser = new GuessBasedChooser(
223
+ mockScoreCalculator,
224
+ mockLastEstimateStorage,
225
+ );
201
226
 
202
227
  const result = chooser.getGuess(
203
228
  representations,
@@ -211,11 +236,14 @@ describe("GuessBasedChooser", () => {
211
236
  });
212
237
 
213
238
  it("should return null when buffer gap is too low to guess higher", () => {
214
- mockScoreCalculator.getEstimate.mockReturnValue(
239
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
215
240
  createScoreData(1.5, ScoreConfidenceLevel.HIGH),
216
241
  );
217
242
 
218
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
243
+ const chooser = new GuessBasedChooser(
244
+ mockScoreCalculator,
245
+ mockLastEstimateStorage,
246
+ );
219
247
 
220
248
  const result = chooser.getGuess(
221
249
  representations,
@@ -229,11 +257,14 @@ describe("GuessBasedChooser", () => {
229
257
  });
230
258
 
231
259
  it("should return null when confidence level is not HIGH", () => {
232
- mockScoreCalculator.getEstimate.mockReturnValue(
260
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
233
261
  createScoreData(1.5, ScoreConfidenceLevel.LOW),
234
262
  );
235
263
 
236
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
264
+ const chooser = new GuessBasedChooser(
265
+ mockScoreCalculator,
266
+ mockLastEstimateStorage,
267
+ );
237
268
 
238
269
  const result = chooser.getGuess(
239
270
  representations,
@@ -247,11 +278,14 @@ describe("GuessBasedChooser", () => {
247
278
  });
248
279
 
249
280
  it("should return null when score/speed ratio is too low", () => {
250
- mockScoreCalculator.getEstimate.mockReturnValue(
281
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
251
282
  createScoreData(1.005, ScoreConfidenceLevel.HIGH),
252
283
  );
253
284
 
254
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
285
+ const chooser = new GuessBasedChooser(
286
+ mockScoreCalculator,
287
+ mockLastEstimateStorage,
288
+ );
255
289
 
256
290
  const result = chooser.getGuess(
257
291
  representations,
@@ -265,11 +299,14 @@ describe("GuessBasedChooser", () => {
265
299
  });
266
300
 
267
301
  it("should account for playback speed when checking score", () => {
268
- mockScoreCalculator.getEstimate.mockReturnValue(
302
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
269
303
  createScoreData(2.0, ScoreConfidenceLevel.HIGH),
270
304
  );
271
305
 
272
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
306
+ const chooser = new GuessBasedChooser(
307
+ mockScoreCalculator,
308
+ mockLastEstimateStorage,
309
+ );
273
310
 
274
311
  const result = chooser.getGuess(
275
312
  representations,
@@ -283,11 +320,14 @@ describe("GuessBasedChooser", () => {
283
320
  });
284
321
 
285
322
  it("should return null when already at highest representation", () => {
286
- mockScoreCalculator.getEstimate.mockReturnValue(
323
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
287
324
  createScoreData(1.5, ScoreConfidenceLevel.HIGH),
288
325
  );
289
326
 
290
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
327
+ const chooser = new GuessBasedChooser(
328
+ mockScoreCalculator,
329
+ mockLastEstimateStorage,
330
+ );
291
331
 
292
332
  const result = chooser.getGuess(
293
333
  representations,
@@ -303,16 +343,19 @@ describe("GuessBasedChooser", () => {
303
343
 
304
344
  describe("when already in guessing mode", () => {
305
345
  beforeEach(() => {
306
- mockPrevEstimate.representation = representations[2]; // 1000000
307
- mockPrevEstimate.algorithmType = ABRAlgorithmType.GuessBased;
346
+ mockLastEstimateStorage.representation = representations[2]; // 1000000
347
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.GuessBased;
308
348
  });
309
349
 
310
350
  it("should take higher guess when conditions are met", () => {
311
- mockScoreCalculator.getEstimate.mockReturnValue(
351
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
312
352
  createScoreData(2.0, ScoreConfidenceLevel.HIGH),
313
353
  );
314
354
 
315
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
355
+ const chooser = new GuessBasedChooser(
356
+ mockScoreCalculator,
357
+ mockLastEstimateStorage,
358
+ );
316
359
 
317
360
  const result = chooser.getGuess(
318
361
  representations,
@@ -325,12 +368,15 @@ describe("GuessBasedChooser", () => {
325
368
  });
326
369
 
327
370
  it("should take same guess when conditions are met with highest guess", () => {
328
- mockPrevEstimate.representation = representations[4];
329
- mockScoreCalculator.getEstimate.mockReturnValue(
371
+ mockLastEstimateStorage.representation = representations[4];
372
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
330
373
  createScoreData(2.0, ScoreConfidenceLevel.HIGH),
331
374
  );
332
375
 
333
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
376
+ const chooser = new GuessBasedChooser(
377
+ mockScoreCalculator,
378
+ mockLastEstimateStorage,
379
+ );
334
380
 
335
381
  const result = chooser.getGuess(
336
382
  representations,
@@ -343,11 +389,14 @@ describe("GuessBasedChooser", () => {
343
389
  });
344
390
 
345
391
  it("should return last chosen representation when current differs", () => {
346
- mockScoreCalculator.getEstimate.mockReturnValue(
392
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
347
393
  createScoreData(1.2, ScoreConfidenceLevel.HIGH),
348
394
  );
349
395
 
350
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
396
+ const chooser = new GuessBasedChooser(
397
+ mockScoreCalculator,
398
+ mockLastEstimateStorage,
399
+ );
351
400
 
352
401
  const result = chooser.getGuess(
353
402
  representations,
@@ -361,11 +410,14 @@ describe("GuessBasedChooser", () => {
361
410
  });
362
411
 
363
412
  it("should stop guess and downgrade when score is too low", () => {
364
- mockScoreCalculator.getEstimate.mockReturnValue(
413
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
365
414
  createScoreData(0.9, ScoreConfidenceLevel.HIGH),
366
415
  );
367
416
 
368
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
417
+ const chooser = new GuessBasedChooser(
418
+ mockScoreCalculator,
419
+ mockLastEstimateStorage,
420
+ );
369
421
 
370
422
  const result = chooser.getGuess(
371
423
  representations,
@@ -379,11 +431,14 @@ describe("GuessBasedChooser", () => {
379
431
  });
380
432
 
381
433
  it("should stop guess when buffer gap is low and score is marginal", () => {
382
- mockScoreCalculator.getEstimate.mockReturnValue(
434
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
383
435
  createScoreData(1.1, ScoreConfidenceLevel.HIGH),
384
436
  );
385
437
 
386
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
438
+ const chooser = new GuessBasedChooser(
439
+ mockScoreCalculator,
440
+ mockLastEstimateStorage,
441
+ );
387
442
 
388
443
  const result = chooser.getGuess(
389
444
  representations,
@@ -397,9 +452,12 @@ describe("GuessBasedChooser", () => {
397
452
  });
398
453
 
399
454
  it("should stop guess when score is undefined and buffer gap is low", () => {
400
- mockScoreCalculator.getEstimate.mockReturnValue(undefined);
455
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(undefined);
401
456
 
402
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
457
+ const chooser = new GuessBasedChooser(
458
+ mockScoreCalculator,
459
+ mockLastEstimateStorage,
460
+ );
403
461
 
404
462
  const result = chooser.getGuess(
405
463
  representations,
@@ -413,11 +471,14 @@ describe("GuessBasedChooser", () => {
413
471
  });
414
472
 
415
473
  it("should block guesses for increasing duration after consecutive wrong guesses", () => {
416
- mockScoreCalculator.getEstimate.mockReturnValue(
474
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
417
475
  createScoreData(0.9, ScoreConfidenceLevel.HIGH),
418
476
  );
419
477
 
420
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
478
+ const chooser = new GuessBasedChooser(
479
+ mockScoreCalculator,
480
+ mockLastEstimateStorage,
481
+ );
421
482
 
422
483
  // First wrong guess
423
484
  chooser.getGuess(
@@ -430,7 +491,7 @@ describe("GuessBasedChooser", () => {
430
491
 
431
492
  // Try to guess again immediately
432
493
  mocks.getMonotonicTimeStamp.mockReturnValue(10000 + 5000); // 5 seconds later
433
- mockPrevEstimate.algorithmType = ABRAlgorithmType.BufferBased;
494
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.BufferBased;
434
495
 
435
496
  const result = chooser.getGuess(
436
497
  representations,
@@ -445,11 +506,14 @@ describe("GuessBasedChooser", () => {
445
506
  });
446
507
 
447
508
  it("should allow guessing after block period expires", () => {
448
- mockScoreCalculator.getEstimate.mockReturnValue(
509
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
449
510
  createScoreData(0.9, ScoreConfidenceLevel.HIGH),
450
511
  );
451
512
 
452
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
513
+ const chooser = new GuessBasedChooser(
514
+ mockScoreCalculator,
515
+ mockLastEstimateStorage,
516
+ );
453
517
 
454
518
  // First wrong guess
455
519
  chooser.getGuess(
@@ -462,8 +526,8 @@ describe("GuessBasedChooser", () => {
462
526
 
463
527
  // Wait for block to expire
464
528
  mocks.getMonotonicTimeStamp.mockReturnValue(10000 + 20000); // 20 seconds later
465
- mockPrevEstimate.algorithmType = ABRAlgorithmType.BufferBased;
466
- mockScoreCalculator.getEstimate.mockReturnValue(
529
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.BufferBased;
530
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
467
531
  createScoreData(1.5, ScoreConfidenceLevel.HIGH),
468
532
  );
469
533
 
@@ -480,11 +544,14 @@ describe("GuessBasedChooser", () => {
480
544
  });
481
545
 
482
546
  it("should guess higher when conditions allow in guessing mode", () => {
483
- mockScoreCalculator.getEstimate.mockReturnValue(
547
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
484
548
  createScoreData(1.5, ScoreConfidenceLevel.HIGH),
485
549
  );
486
550
 
487
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
551
+ const chooser = new GuessBasedChooser(
552
+ mockScoreCalculator,
553
+ mockLastEstimateStorage,
554
+ );
488
555
 
489
556
  const result = chooser.getGuess(
490
557
  representations,
@@ -498,9 +565,12 @@ describe("GuessBasedChooser", () => {
498
565
  });
499
566
 
500
567
  it("should return current representation when score data is undefined and not stopping", () => {
501
- mockScoreCalculator.getEstimate.mockReturnValue(undefined);
568
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(undefined);
502
569
 
503
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
570
+ const chooser = new GuessBasedChooser(
571
+ mockScoreCalculator,
572
+ mockLastEstimateStorage,
573
+ );
504
574
 
505
575
  const result = chooser.getGuess(
506
576
  representations,
@@ -516,9 +586,9 @@ describe("GuessBasedChooser", () => {
516
586
 
517
587
  describe("request-based guess stopping", () => {
518
588
  beforeEach(() => {
519
- mockPrevEstimate.representation = representations[2];
520
- mockPrevEstimate.algorithmType = ABRAlgorithmType.GuessBased;
521
- mockScoreCalculator.getEstimate.mockReturnValue(
589
+ mockLastEstimateStorage.representation = representations[2];
590
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.GuessBased;
591
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
522
592
  createScoreData(1.2, ScoreConfidenceLevel.HIGH),
523
593
  );
524
594
  });
@@ -528,7 +598,10 @@ describe("GuessBasedChooser", () => {
528
598
  createRequest("rep-3", 0, 8000, true), // 2000ms elapsed (10000 - 8000)
529
599
  ];
530
600
 
531
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
601
+ const chooser = new GuessBasedChooser(
602
+ mockScoreCalculator,
603
+ mockLastEstimateStorage,
604
+ );
532
605
 
533
606
  const result = chooser.getGuess(
534
607
  representations,
@@ -546,7 +619,10 @@ describe("GuessBasedChooser", () => {
546
619
  createRequest("rep-3", 0, 9500, true), // 500ms elapsed
547
620
  ];
548
621
 
549
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
622
+ const chooser = new GuessBasedChooser(
623
+ mockScoreCalculator,
624
+ mockLastEstimateStorage,
625
+ );
550
626
 
551
627
  const result = chooser.getGuess(
552
628
  representations,
@@ -564,7 +640,10 @@ describe("GuessBasedChooser", () => {
564
640
  createRequest("rep-3", 2, 5000, false), // 5000ms elapsed, duration is 2s
565
641
  ];
566
642
 
567
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
643
+ const chooser = new GuessBasedChooser(
644
+ mockScoreCalculator,
645
+ mockLastEstimateStorage,
646
+ );
568
647
 
569
648
  const result = chooser.getGuess(
570
649
  representations,
@@ -582,7 +661,10 @@ describe("GuessBasedChooser", () => {
582
661
  createRequest("rep-3", 2, 8500, false), // 1500ms elapsed, duration is 2s (threshold: 2200ms)
583
662
  ];
584
663
 
585
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
664
+ const chooser = new GuessBasedChooser(
665
+ mockScoreCalculator,
666
+ mockLastEstimateStorage,
667
+ );
586
668
 
587
669
  const result = chooser.getGuess(
588
670
  representations,
@@ -600,7 +682,10 @@ describe("GuessBasedChooser", () => {
600
682
 
601
683
  const requests = [createRequest("rep-3", 2, 9000, false)];
602
684
 
603
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
685
+ const chooser = new GuessBasedChooser(
686
+ mockScoreCalculator,
687
+ mockLastEstimateStorage,
688
+ );
604
689
 
605
690
  const result = chooser.getGuess(
606
691
  representations,
@@ -616,11 +701,14 @@ describe("GuessBasedChooser", () => {
616
701
  it("should not consider requests for other representations", () => {
617
702
  const requests = [createRequest("rep-4", 2, 5000, false)];
618
703
 
619
- mockScoreCalculator.getEstimate.mockReturnValue(
704
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
620
705
  createScoreData(1.1, ScoreConfidenceLevel.HIGH),
621
706
  );
622
707
 
623
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
708
+ const chooser = new GuessBasedChooser(
709
+ mockScoreCalculator,
710
+ mockLastEstimateStorage,
711
+ );
624
712
 
625
713
  const result = chooser.getGuess(
626
714
  representations,
@@ -640,7 +728,10 @@ describe("GuessBasedChooser", () => {
640
728
  createRequest("rep-3", 2, 9000, false), // OK
641
729
  ];
642
730
 
643
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
731
+ const chooser = new GuessBasedChooser(
732
+ mockScoreCalculator,
733
+ mockLastEstimateStorage,
734
+ );
644
735
 
645
736
  const result = chooser.getGuess(
646
737
  representations,
@@ -656,16 +747,19 @@ describe("GuessBasedChooser", () => {
656
747
 
657
748
  describe("guess validation", () => {
658
749
  beforeEach(() => {
659
- mockPrevEstimate.representation = representations[2];
660
- mockPrevEstimate.algorithmType = ABRAlgorithmType.GuessBased;
750
+ mockLastEstimateStorage.representation = representations[2];
751
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.GuessBased;
661
752
  });
662
753
 
663
754
  it("should validate guess with high score and high confidence", () => {
664
- mockScoreCalculator.getEstimate.mockReturnValue(
755
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
665
756
  createScoreData(1.6, ScoreConfidenceLevel.HIGH),
666
757
  );
667
758
 
668
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
759
+ const chooser = new GuessBasedChooser(
760
+ mockScoreCalculator,
761
+ mockLastEstimateStorage,
762
+ );
669
763
 
670
764
  chooser.getGuess(
671
765
  representations,
@@ -688,11 +782,14 @@ describe("GuessBasedChooser", () => {
688
782
  });
689
783
 
690
784
  it("should validate guess when incoming bitrate matches and it's an improvement", () => {
691
- mockScoreCalculator.getEstimate.mockReturnValue(
785
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
692
786
  createScoreData(1.2, ScoreConfidenceLevel.LOW),
693
787
  );
694
788
 
695
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
789
+ const chooser = new GuessBasedChooser(
790
+ mockScoreCalculator,
791
+ mockLastEstimateStorage,
792
+ );
696
793
 
697
794
  const result = chooser.getGuess(
698
795
  representations,
@@ -709,13 +806,16 @@ describe("GuessBasedChooser", () => {
709
806
 
710
807
  describe("edge cases", () => {
711
808
  it("should handle infinite buffer gap correctly", () => {
712
- mockPrevEstimate.representation = representations[1];
713
- mockPrevEstimate.algorithmType = ABRAlgorithmType.BufferBased;
714
- mockScoreCalculator.getEstimate.mockReturnValue(
809
+ mockLastEstimateStorage.representation = representations[1];
810
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.BufferBased;
811
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
715
812
  createScoreData(1.5, ScoreConfidenceLevel.HIGH),
716
813
  );
717
814
 
718
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
815
+ const chooser = new GuessBasedChooser(
816
+ mockScoreCalculator,
817
+ mockLastEstimateStorage,
818
+ );
719
819
 
720
820
  const result = chooser.getGuess(
721
821
  representations,
@@ -729,13 +829,16 @@ describe("GuessBasedChooser", () => {
729
829
  });
730
830
 
731
831
  it("should handle NaN buffer gap by not guessing", () => {
732
- mockPrevEstimate.representation = representations[1];
733
- mockPrevEstimate.algorithmType = ABRAlgorithmType.BufferBased;
734
- mockScoreCalculator.getEstimate.mockReturnValue(
832
+ mockLastEstimateStorage.representation = representations[1];
833
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.BufferBased;
834
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
735
835
  createScoreData(1.5, ScoreConfidenceLevel.HIGH),
736
836
  );
737
837
 
738
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
838
+ const chooser = new GuessBasedChooser(
839
+ mockScoreCalculator,
840
+ mockLastEstimateStorage,
841
+ );
739
842
 
740
843
  const result = chooser.getGuess(
741
844
  representations,
@@ -749,13 +852,16 @@ describe("GuessBasedChooser", () => {
749
852
  });
750
853
 
751
854
  it("should cap block duration at 120 seconds", () => {
752
- mockScoreCalculator.getEstimate.mockReturnValue(
855
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
753
856
  createScoreData(0.9, ScoreConfidenceLevel.HIGH),
754
857
  );
755
- mockPrevEstimate.algorithmType = ABRAlgorithmType.GuessBased;
756
- mockPrevEstimate.representation = representations[2];
858
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.GuessBased;
859
+ mockLastEstimateStorage.representation = representations[2];
757
860
 
758
- const chooser = new GuessBasedChooser(mockScoreCalculator, mockPrevEstimate);
861
+ const chooser = new GuessBasedChooser(
862
+ mockScoreCalculator,
863
+ mockLastEstimateStorage,
864
+ );
759
865
 
760
866
  // Trigger many consecutive wrong guesses
761
867
  for (let i = 0; i < 20; i++) {
@@ -772,9 +878,9 @@ describe("GuessBasedChooser", () => {
772
878
  // The block should be capped at 120 seconds max
773
879
  // After 120 seconds, should be able to guess again
774
880
  mocks.getMonotonicTimeStamp.mockReturnValue(10000 + 20000 + 120100);
775
- mockPrevEstimate.algorithmType = ABRAlgorithmType.BufferBased;
776
- mockPrevEstimate.representation = representations[1]; // Update to reflect actual downgraded state
777
- mockScoreCalculator.getEstimate.mockReturnValue(
881
+ mockLastEstimateStorage.algorithmType = ABRAlgorithmType.BufferBased;
882
+ mockLastEstimateStorage.representation = representations[1]; // Update to reflect actual downgraded state
883
+ vi.spyOn(mockScoreCalculator, "getEstimate").mockReturnValue(
778
884
  createScoreData(1.5, ScoreConfidenceLevel.HIGH),
779
885
  );
780
886