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,79 +1,143 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
- import { SegmentSinkOperation } from "../../../../segment_sinks";
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import configHandler from "../../../../../config";
3
+ import { type Adaptation, type Period } from "../../../../../manifest/classes";
4
+ import {
5
+ DummyPeriod,
6
+ DummyAdaptation,
7
+ createSegment,
8
+ DummyRepresentation,
9
+ } from "../../../../../manifest/classes/__tests__/mocks";
10
+ import {
11
+ makeReadyOnlyPlaybackObserver,
12
+ DummyObservationPosition,
13
+ } from "../../../../../playback_observer/__tests__/mocks";
14
+ import type { IBufferedChunk, SegmentSink } from "../../../../segment_sinks";
15
+ import { ChunkStatus, SegmentSinkOperation } from "../../../../segment_sinks";
16
+ import { DummySegmentSink } from "../../../../segment_sinks/__tests__/mocks";
17
+ import type { IPeriodStreamPlaybackObservation } from "../../types";
3
18
  import getAdaptationSwitchStrategy from "../get_adaptation_switch_strategy";
4
19
 
5
- /* eslint-disable @typescript-eslint/no-explicit-any */
6
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
7
- /* eslint-disable @typescript-eslint/no-unsafe-argument */
8
-
9
- // Mock only external dependencies that have side effects or complex behavior
10
- vi.mock("../../../../../config", () => ({
11
- default: {
12
- getCurrent: vi.fn(() => ({
20
+ describe("getAdaptationSwitchStrategy", () => {
21
+ let mockSegmentSink: SegmentSink;
22
+ let mockPeriod: Period;
23
+ let mockAdaptation: Adaptation;
24
+ const mockedPlaybackObserver =
25
+ makeReadyOnlyPlaybackObserver<IPeriodStreamPlaybackObservation>({
26
+ position: new DummyObservationPosition({
27
+ getPolled: () => 15,
28
+ }),
29
+ readyState: 3,
30
+ paused: {
31
+ last: false,
32
+ pending: undefined,
33
+ },
34
+ duration: NaN,
35
+ speed: 1,
36
+ maximumPosition: Number.MAX_SAFE_INTEGER,
37
+ buffered: { video: null, audio: null, text: null },
38
+ canStream: true,
39
+ });
40
+ beforeEach(() => {
41
+ const originalConfig = configHandler.getCurrent();
42
+ vi.spyOn(configHandler, "getCurrent").mockReturnValue({
43
+ ...originalConfig,
13
44
  ADAP_REP_SWITCH_BUFFER_PADDINGS: {
14
45
  video: { before: 0.5, after: 0.5 },
15
46
  audio: { before: 0.5, after: 0.5 },
16
47
  text: { before: 0, after: 0 },
17
48
  },
18
- })),
19
- },
20
- }));
21
-
22
- describe("getAdaptationSwitchStrategy", () => {
23
- let mockSegmentSink: any;
24
- let mockPeriod: any;
25
- let mockAdaptation: any;
26
- let mockPlaybackObserver: any;
27
-
28
- beforeEach(() => {
29
- // Create base mocks
30
- mockSegmentSink = {
31
- codec: undefined,
32
- getLastKnownInventory: vi.fn(() => []),
33
- getPendingOperations: vi.fn(() => []),
34
- };
35
-
36
- mockPeriod = {
49
+ });
50
+ mockSegmentSink = new DummySegmentSink({
51
+ getLastKnownInventory: () => [],
52
+ getPendingOperations: () => [],
53
+ });
54
+ mockPeriod = new DummyPeriod({
37
55
  id: "period-1",
38
56
  start: 10,
39
57
  end: 20,
40
- };
41
-
42
- mockAdaptation = {
58
+ });
59
+ mockAdaptation = new DummyAdaptation({
43
60
  id: "adaptation-1",
44
61
  type: "video",
45
- representations: [],
46
- };
47
-
48
- mockPlaybackObserver = {
49
- getCurrentTime: vi.fn(() => 15),
50
- getReadyState: vi.fn(() => 3),
51
- getReference: vi.fn(() => ({
52
- getValue: () => ({
53
- position: {
54
- getPolled: () => 15,
55
- },
62
+ });
63
+ vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockImplementation(
64
+ () => 15,
65
+ );
66
+ vi.spyOn(mockedPlaybackObserver.observer, "getReadyState").mockImplementation(
67
+ () => 3,
68
+ );
69
+ });
70
+ afterEach(() => {
71
+ mockedPlaybackObserver.reset();
72
+ vi.resetModules();
73
+ });
74
+ function makeBufferedChunk({
75
+ bufferedStart,
76
+ bufferedEnd,
77
+ start,
78
+ end,
79
+ periodId = "period-1",
80
+ periodStart = 0,
81
+ periodEnd,
82
+ adaptationId = "adaptation-1",
83
+ representationId = "rep-1",
84
+ }: {
85
+ bufferedStart: number | undefined;
86
+ bufferedEnd: number | undefined;
87
+ start: number;
88
+ end: number;
89
+ periodId?: string;
90
+ periodStart?: number;
91
+ periodEnd?: number | undefined;
92
+ adaptationId?: string;
93
+ representationId?: string;
94
+ }): IBufferedChunk {
95
+ return {
96
+ infos: {
97
+ period: new DummyPeriod({
98
+ id: periodId,
99
+ start: periodStart,
100
+ end: periodEnd,
101
+ }),
102
+ adaptation: new DummyAdaptation({ id: adaptationId }),
103
+ representation: new DummyRepresentation({
104
+ id: representationId,
56
105
  }),
57
- })),
106
+ segment: createSegment({ time: start, end }),
107
+ },
108
+ bufferedStart,
109
+ bufferedEnd,
110
+ start,
111
+ end,
112
+ insertionTs: 0,
113
+ chunkSize: 1024,
114
+ precizeStart: true,
115
+ precizeEnd: true,
116
+ status: ChunkStatus.FullyLoaded,
117
+ splitted: false,
58
118
  };
59
- });
119
+ }
60
120
 
61
121
  describe("codec compatibility", () => {
62
122
  it("should return needs-reload when codec is incompatible and onCodecSwitch is reload", () => {
63
123
  mockSegmentSink.codec = "avc1.64001f";
64
- mockAdaptation.representations = [
65
- {
66
- isPlayable: () => true,
67
- getMimeTypeString: () => "video/mp4; codecs=hev1.1.6.L93.B0",
68
- },
69
- ];
124
+ const currMockAdap = new DummyAdaptation({
125
+ id: "adaptation-1",
126
+ type: "video",
127
+ representations: [
128
+ new DummyRepresentation({
129
+ isPlayable: () => true,
130
+ getMimeTypeString: () => "video/mp4; codecs=hev1.1.6.L93.B0",
131
+ }),
132
+ ],
133
+ });
70
134
 
71
135
  const result = getAdaptationSwitchStrategy(
72
136
  mockSegmentSink,
73
137
  mockPeriod,
74
- mockAdaptation,
138
+ currMockAdap,
75
139
  "seamless",
76
- mockPlaybackObserver,
140
+ mockedPlaybackObserver.observer,
77
141
  { onCodecSwitch: "reload" },
78
142
  );
79
143
 
@@ -82,19 +146,23 @@ describe("getAdaptationSwitchStrategy", () => {
82
146
 
83
147
  it("should continue when codec is compatible", () => {
84
148
  mockSegmentSink.codec = "video/mp4;codecs=avc1.64001f";
85
- mockAdaptation.representations = [
86
- {
87
- isPlayable: () => true,
88
- getMimeTypeString: () => "video/mp4;codecs=avc1.65001f",
89
- },
90
- ];
149
+ const currMockAdap = new DummyAdaptation({
150
+ id: "adaptation-1",
151
+ type: "video",
152
+ representations: [
153
+ new DummyRepresentation({
154
+ isPlayable: () => true,
155
+ getMimeTypeString: () => "video/mp4;codecs=avc1.65001f",
156
+ }),
157
+ ],
158
+ });
91
159
 
92
160
  const result = getAdaptationSwitchStrategy(
93
161
  mockSegmentSink,
94
162
  mockPeriod,
95
- mockAdaptation,
163
+ currMockAdap,
96
164
  "seamless",
97
- mockPlaybackObserver,
165
+ mockedPlaybackObserver.observer,
98
166
  { onCodecSwitch: "reload" },
99
167
  );
100
168
 
@@ -103,19 +171,23 @@ describe("getAdaptationSwitchStrategy", () => {
103
171
 
104
172
  it("should continue when onCodecSwitch is continue regardless of codec", () => {
105
173
  mockSegmentSink.codec = "avc1.64001f";
106
- mockAdaptation.representations = [
107
- {
108
- isPlayable: () => true,
109
- getMimeTypeString: () => "video/mp4; codecs=hev1.1.6.L93.B0",
110
- },
111
- ];
174
+ const currMockAdap = new DummyAdaptation({
175
+ id: "adaptation-1",
176
+ type: "video",
177
+ representations: [
178
+ new DummyRepresentation({
179
+ isPlayable: () => true,
180
+ getMimeTypeString: () => "video/mp4; codecs=hev1.1.6.L93.B0",
181
+ }),
182
+ ],
183
+ });
112
184
 
113
185
  const result = getAdaptationSwitchStrategy(
114
186
  mockSegmentSink,
115
187
  mockPeriod,
116
- mockAdaptation,
188
+ currMockAdap,
117
189
  "seamless",
118
- mockPlaybackObserver,
190
+ mockedPlaybackObserver.observer,
119
191
  { onCodecSwitch: "continue" },
120
192
  );
121
193
 
@@ -125,17 +197,15 @@ describe("getAdaptationSwitchStrategy", () => {
125
197
 
126
198
  describe("no unwanted segments", () => {
127
199
  it("should return continue when no other adaptation is buffered", () => {
128
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
129
- {
200
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
201
+ makeBufferedChunk({
130
202
  start: 10,
131
203
  end: 15,
132
204
  bufferedStart: 10,
133
205
  bufferedEnd: 15,
134
- infos: {
135
- period: { id: "period-1", start: 0 },
136
- adaptation: { id: "adaptation-1" }, // Same adaptation
137
- },
138
- },
206
+ periodId: "period-1",
207
+ adaptationId: "adaptation-1",
208
+ }),
139
209
  ]);
140
210
 
141
211
  const result = getAdaptationSwitchStrategy(
@@ -143,7 +213,7 @@ describe("getAdaptationSwitchStrategy", () => {
143
213
  mockPeriod,
144
214
  mockAdaptation,
145
215
  "seamless",
146
- mockPlaybackObserver,
216
+ mockedPlaybackObserver.observer,
147
217
  { onCodecSwitch: "continue" },
148
218
  );
149
219
 
@@ -151,17 +221,15 @@ describe("getAdaptationSwitchStrategy", () => {
151
221
  });
152
222
 
153
223
  it("should return continue when segments are from different period", () => {
154
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
155
- {
224
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
225
+ makeBufferedChunk({
156
226
  start: 5,
157
227
  end: 10,
158
228
  bufferedStart: 5,
159
229
  bufferedEnd: 10,
160
- infos: {
161
- period: { id: "period-0", start: 0 }, // Different period
162
- adaptation: { id: "adaptation-2" },
163
- },
164
- },
230
+ periodId: "period-0",
231
+ adaptationId: "adaptation-2",
232
+ }),
165
233
  ]);
166
234
 
167
235
  const result = getAdaptationSwitchStrategy(
@@ -169,7 +237,7 @@ describe("getAdaptationSwitchStrategy", () => {
169
237
  mockPeriod,
170
238
  mockAdaptation,
171
239
  "seamless",
172
- mockPlaybackObserver,
240
+ mockedPlaybackObserver.observer,
173
241
  { onCodecSwitch: "continue" },
174
242
  );
175
243
 
@@ -179,17 +247,15 @@ describe("getAdaptationSwitchStrategy", () => {
179
247
 
180
248
  describe("unwanted segments in inventory", () => {
181
249
  it("should detect unwanted segments from different adaptation in same period", () => {
182
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
183
- {
250
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
251
+ makeBufferedChunk({
184
252
  start: 10,
185
253
  end: 15,
186
254
  bufferedStart: 10,
187
255
  bufferedEnd: 15,
188
- infos: {
189
- period: { id: "period-1", start: 0 },
190
- adaptation: { id: "adaptation-2" }, // Different adaptation
191
- },
192
- },
256
+ periodId: "period-1",
257
+ adaptationId: "adaptation-2", // Different adaptation
258
+ }),
193
259
  ]);
194
260
 
195
261
  const result = getAdaptationSwitchStrategy(
@@ -197,7 +263,7 @@ describe("getAdaptationSwitchStrategy", () => {
197
263
  mockPeriod,
198
264
  mockAdaptation,
199
265
  "seamless",
200
- mockPlaybackObserver,
266
+ mockedPlaybackObserver.observer,
201
267
  { onCodecSwitch: "continue" },
202
268
  );
203
269
 
@@ -205,17 +271,15 @@ describe("getAdaptationSwitchStrategy", () => {
205
271
  });
206
272
 
207
273
  it("should use bufferedStart/bufferedEnd when available", () => {
208
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
209
- {
274
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
275
+ makeBufferedChunk({
210
276
  start: 10,
211
277
  end: 15,
212
278
  bufferedStart: 10.5,
213
279
  bufferedEnd: 14.5,
214
- infos: {
215
- period: { id: "period-1", start: 0 },
216
- adaptation: { id: "adaptation-2" },
217
- },
218
- },
280
+ periodId: "period-1",
281
+ adaptationId: "adaptation-2",
282
+ }),
219
283
  ]);
220
284
 
221
285
  const result = getAdaptationSwitchStrategy(
@@ -223,7 +287,7 @@ describe("getAdaptationSwitchStrategy", () => {
223
287
  mockPeriod,
224
288
  mockAdaptation,
225
289
  "seamless",
226
- mockPlaybackObserver,
290
+ mockedPlaybackObserver.observer,
227
291
  { onCodecSwitch: "continue" },
228
292
  );
229
293
 
@@ -233,17 +297,30 @@ describe("getAdaptationSwitchStrategy", () => {
233
297
 
234
298
  describe("pending operations", () => {
235
299
  it("should include unwanted segments from pending push operations", () => {
236
- mockSegmentSink.getPendingOperations.mockReturnValue([
300
+ vi.spyOn(mockSegmentSink, "getPendingOperations").mockReturnValue([
237
301
  {
238
302
  type: SegmentSinkOperation.Push,
239
303
  value: {
240
304
  inventoryInfos: {
241
- period: { id: "period-1", start: 0 },
242
- adaptation: { id: "adaptation-2" },
243
- segment: {
305
+ period: mockPeriod,
306
+ adaptation: new DummyAdaptation({
307
+ id: "adaptation-2",
308
+ }),
309
+ representation: new DummyRepresentation(),
310
+ segment: createSegment({
244
311
  time: 12,
245
312
  duration: 3,
246
- },
313
+ }),
314
+ chunkSize: 1024,
315
+ start: 0,
316
+ end: 1000,
317
+ },
318
+ data: {
319
+ initSegmentUniqueId: "a",
320
+ chunk: 4,
321
+ codec: "toto",
322
+ timestampOffset: 0,
323
+ appendWindow: [undefined, undefined],
247
324
  },
248
325
  },
249
326
  },
@@ -253,7 +330,7 @@ describe("getAdaptationSwitchStrategy", () => {
253
330
  mockPeriod,
254
331
  mockAdaptation,
255
332
  "seamless",
256
- mockPlaybackObserver,
333
+ mockedPlaybackObserver.observer,
257
334
  { onCodecSwitch: "continue" },
258
335
  );
259
336
 
@@ -261,14 +338,19 @@ describe("getAdaptationSwitchStrategy", () => {
261
338
  });
262
339
 
263
340
  it("should ignore non-push operations", () => {
264
- mockSegmentSink.getPendingOperations.mockReturnValue([
341
+ vi.spyOn(mockSegmentSink, "getPendingOperations").mockReturnValue([
265
342
  {
266
343
  type: SegmentSinkOperation.Remove,
267
344
  value: { start: 10, end: 15 },
268
345
  },
269
346
  {
270
347
  type: SegmentSinkOperation.SignalSegmentComplete,
271
- value: { start: 10, end: 15 },
348
+ value: {
349
+ adaptation: mockAdaptation,
350
+ period: mockPeriod,
351
+ representation: new DummyRepresentation(),
352
+ segment: createSegment(),
353
+ },
272
354
  },
273
355
  ]);
274
356
 
@@ -277,7 +359,7 @@ describe("getAdaptationSwitchStrategy", () => {
277
359
  mockPeriod,
278
360
  mockAdaptation,
279
361
  "seamless",
280
- mockPlaybackObserver,
362
+ mockedPlaybackObserver.observer,
281
363
  { onCodecSwitch: "continue" },
282
364
  );
283
365
 
@@ -287,29 +369,26 @@ describe("getAdaptationSwitchStrategy", () => {
287
369
 
288
370
  describe("switching modes", () => {
289
371
  beforeEach(() => {
290
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
291
- {
372
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
373
+ makeBufferedChunk({
292
374
  start: 10,
293
375
  end: 15,
294
376
  bufferedStart: 10,
295
377
  bufferedEnd: 15,
296
- infos: {
297
- period: { id: "period-1", start: 0 },
298
- adaptation: { id: "adaptation-2" },
299
- },
300
- },
378
+ periodId: "period-1",
379
+ adaptationId: "adaptation-2",
380
+ }),
301
381
  ]);
302
382
  });
303
383
 
304
384
  it("should return needs-reload when switchingMode is reload and readyState > 1", () => {
305
- mockPlaybackObserver.getReadyState.mockReturnValue(3);
306
-
385
+ vi.spyOn(mockedPlaybackObserver.observer, "getReadyState").mockReturnValue(3);
307
386
  const result = getAdaptationSwitchStrategy(
308
387
  mockSegmentSink,
309
388
  mockPeriod,
310
389
  mockAdaptation,
311
390
  "reload",
312
- mockPlaybackObserver,
391
+ mockedPlaybackObserver.observer,
313
392
  { onCodecSwitch: "continue" },
314
393
  );
315
394
 
@@ -317,14 +396,14 @@ describe("getAdaptationSwitchStrategy", () => {
317
396
  });
318
397
 
319
398
  it("should not reload when readyState is 1 or less", () => {
320
- mockPlaybackObserver.getReadyState.mockReturnValue(1);
399
+ vi.spyOn(mockedPlaybackObserver.observer, "getReadyState").mockReturnValue(1);
321
400
 
322
401
  const result = getAdaptationSwitchStrategy(
323
402
  mockSegmentSink,
324
403
  mockPeriod,
325
404
  mockAdaptation,
326
405
  "reload",
327
- mockPlaybackObserver,
406
+ mockedPlaybackObserver.observer,
328
407
  { onCodecSwitch: "continue" },
329
408
  );
330
409
 
@@ -337,7 +416,7 @@ describe("getAdaptationSwitchStrategy", () => {
337
416
  mockPeriod,
338
417
  mockAdaptation,
339
418
  "direct",
340
- mockPlaybackObserver,
419
+ mockedPlaybackObserver.observer,
341
420
  { onCodecSwitch: "continue" },
342
421
  );
343
422
 
@@ -347,14 +426,17 @@ describe("getAdaptationSwitchStrategy", () => {
347
426
  });
348
427
 
349
428
  it("should clean-buffer for direct mode with text adaptation", () => {
350
- mockAdaptation.type = "text";
429
+ const currMockAdap = new DummyAdaptation({
430
+ id: "adaptation-1",
431
+ type: "text",
432
+ });
351
433
 
352
434
  const result = getAdaptationSwitchStrategy(
353
435
  mockSegmentSink,
354
436
  mockPeriod,
355
- mockAdaptation,
437
+ currMockAdap,
356
438
  "direct",
357
- mockPlaybackObserver,
439
+ mockedPlaybackObserver.observer,
358
440
  { onCodecSwitch: "continue" },
359
441
  );
360
442
 
@@ -369,7 +451,7 @@ describe("getAdaptationSwitchStrategy", () => {
369
451
  mockPeriod,
370
452
  mockAdaptation,
371
453
  "seamless",
372
- mockPlaybackObserver,
454
+ mockedPlaybackObserver.observer,
373
455
  { onCodecSwitch: "continue" },
374
456
  );
375
457
 
@@ -379,42 +461,37 @@ describe("getAdaptationSwitchStrategy", () => {
379
461
 
380
462
  describe("range exclusion logic", () => {
381
463
  beforeEach(() => {
382
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
383
- {
464
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
465
+ makeBufferedChunk({
384
466
  start: 12,
385
467
  end: 18,
386
468
  bufferedStart: 12,
387
469
  bufferedEnd: 18,
388
- infos: {
389
- period: { id: "period-1", start: 0 },
390
- adaptation: { id: "adaptation-2" },
391
- },
392
- },
470
+ periodId: "period-1",
471
+ adaptationId: "adaptation-2",
472
+ }),
393
473
  ]);
394
474
  });
395
475
 
396
476
  it("should return continue when all unwanted ranges are excluded around current position", () => {
397
477
  // Set up inventory with segments only around current time (which will be excluded)
398
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
399
- {
478
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
479
+ makeBufferedChunk({
400
480
  start: 14.6,
401
481
  end: 15.4,
402
482
  bufferedStart: 14.6,
403
483
  bufferedEnd: 15.4,
404
- infos: {
405
- period: { id: "period-1", start: 0 },
406
- adaptation: { id: "adaptation-2" },
407
- },
408
- },
484
+ periodId: "period-1",
485
+ adaptationId: "adaptation-2",
486
+ }),
409
487
  ]);
410
- mockPlaybackObserver.getCurrentTime.mockReturnValue(15);
411
-
488
+ vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(15);
412
489
  const result = getAdaptationSwitchStrategy(
413
490
  mockSegmentSink,
414
491
  mockPeriod,
415
492
  mockAdaptation,
416
493
  "seamless",
417
- mockPlaybackObserver,
494
+ mockedPlaybackObserver.observer,
418
495
  { onCodecSwitch: "continue" },
419
496
  );
420
497
 
@@ -423,26 +500,25 @@ describe("getAdaptationSwitchStrategy", () => {
423
500
 
424
501
  it("should clean ranges that are far from period boundaries", () => {
425
502
  // Segment in the middle of the period, away from boundaries
426
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
427
- {
503
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
504
+ makeBufferedChunk({
428
505
  start: 13,
429
506
  end: 17,
430
507
  bufferedStart: 13,
431
508
  bufferedEnd: 17,
432
- infos: {
433
- period: { id: "period-1", start: 0 },
434
- adaptation: { id: "adaptation-2" },
435
- },
436
- },
509
+ periodId: "period-1",
510
+ adaptationId: "adaptation-2",
511
+ }),
437
512
  ]);
438
- mockPlaybackObserver.getCurrentTime.mockReturnValue(18); // Away from segment
513
+ // Away from segment
514
+ vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(18);
439
515
 
440
516
  const result = getAdaptationSwitchStrategy(
441
517
  mockSegmentSink,
442
518
  mockPeriod,
443
519
  mockAdaptation,
444
520
  "seamless",
445
- mockPlaybackObserver,
521
+ mockedPlaybackObserver.observer,
446
522
  { onCodecSwitch: "continue" },
447
523
  );
448
524
 
@@ -452,36 +528,32 @@ describe("getAdaptationSwitchStrategy", () => {
452
528
 
453
529
  it("should exclude range near period start when previous period segment is close", () => {
454
530
  // Set up inventory where segment from period-1 exists
455
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
456
- {
531
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
532
+ makeBufferedChunk({
457
533
  start: 8,
458
534
  end: 9.5,
459
535
  bufferedStart: 8,
460
536
  bufferedEnd: 9.5, // Less than 1 second before period start (10)
461
- infos: {
462
- period: { id: "period-0", start: 0 },
463
- adaptation: { id: "adaptation-1" },
464
- },
465
- },
466
- {
537
+ periodId: "period-0",
538
+ adaptationId: "adaptation-1",
539
+ }),
540
+ makeBufferedChunk({
467
541
  start: 10,
468
542
  end: 10.5,
469
543
  bufferedStart: 10,
470
544
  bufferedEnd: 10.5,
471
- infos: {
472
- period: { id: "period-1", start: 0 },
473
- adaptation: { id: "adaptation-2" }, // Different adaptation
474
- },
475
- },
545
+ periodId: "period-1",
546
+ adaptationId: "adaptation-2",
547
+ }),
476
548
  ]);
477
- mockPlaybackObserver.getCurrentTime.mockReturnValue(18); // Far away
549
+ vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(18);
478
550
 
479
551
  const result = getAdaptationSwitchStrategy(
480
552
  mockSegmentSink,
481
553
  mockPeriod,
482
554
  mockAdaptation,
483
555
  "seamless",
484
- mockPlaybackObserver,
556
+ mockedPlaybackObserver.observer,
485
557
  { onCodecSwitch: "continue" },
486
558
  );
487
559
 
@@ -491,36 +563,35 @@ describe("getAdaptationSwitchStrategy", () => {
491
563
 
492
564
  it("should exclude range near period end when next period segment is close", () => {
493
565
  // Set up inventory where segment from next period exists
494
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
495
- {
566
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
567
+ makeBufferedChunk({
496
568
  start: 19.5,
497
569
  end: 20,
498
570
  bufferedStart: 19.5,
499
571
  bufferedEnd: 20,
500
- infos: {
501
- period: { id: "period-1", start: 0, end: 20 },
502
- adaptation: { id: "adaptation-2" }, // Different adaptation
503
- },
504
- },
505
- {
572
+ periodId: "period-1",
573
+ periodStart: 0,
574
+ periodEnd: 20,
575
+ adaptationId: "adaptation-2",
576
+ }),
577
+ makeBufferedChunk({
506
578
  start: 20,
507
579
  end: 21,
508
580
  bufferedStart: 20.5, // Less than 1 second after period end (20)
509
581
  bufferedEnd: 21,
510
- infos: {
511
- period: { id: "period-2", start: 20 },
512
- adaptation: { id: "adaptation-1" },
513
- },
514
- },
582
+ periodId: "period-2",
583
+ periodStart: 20,
584
+ adaptationId: "adaptation-1",
585
+ }),
515
586
  ]);
516
- mockPlaybackObserver.getCurrentTime.mockReturnValue(12); // Far away
587
+ vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(12);
517
588
 
518
589
  const result = getAdaptationSwitchStrategy(
519
590
  mockSegmentSink,
520
591
  mockPeriod,
521
592
  mockAdaptation,
522
593
  "seamless",
523
- mockPlaybackObserver,
594
+ mockedPlaybackObserver.observer,
524
595
  { onCodecSwitch: "continue" },
525
596
  );
526
597
 
@@ -530,26 +601,25 @@ describe("getAdaptationSwitchStrategy", () => {
530
601
 
531
602
  it("should not exclude period end range when period.end is undefined", () => {
532
603
  mockPeriod.end = undefined;
533
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
534
- {
604
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
605
+ makeBufferedChunk({
535
606
  start: 12,
536
607
  end: 15,
537
608
  bufferedStart: 12,
538
609
  bufferedEnd: 15,
539
- infos: {
540
- period: { id: "period-1", start: 10 },
541
- adaptation: { id: "adaptation-2" },
542
- },
543
- },
610
+ periodId: "period-1",
611
+ periodStart: 10,
612
+ adaptationId: "adaptation-2",
613
+ }),
544
614
  ]);
545
- mockPlaybackObserver.getCurrentTime.mockReturnValue(18);
615
+ vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(18);
546
616
 
547
617
  const result = getAdaptationSwitchStrategy(
548
618
  mockSegmentSink,
549
619
  mockPeriod,
550
620
  mockAdaptation,
551
621
  "seamless",
552
- mockPlaybackObserver,
622
+ mockedPlaybackObserver.observer,
553
623
  { onCodecSwitch: "continue" },
554
624
  );
555
625
 
@@ -558,26 +628,25 @@ describe("getAdaptationSwitchStrategy", () => {
558
628
  });
559
629
 
560
630
  it("should exclude current position padding for seamless mode", () => {
561
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
562
- {
631
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
632
+ makeBufferedChunk({
563
633
  start: 14.6,
564
634
  end: 15.4,
565
635
  bufferedStart: 14.6,
566
636
  bufferedEnd: 15.4,
567
- infos: {
568
- period: { id: "period-1", start: 10 },
569
- adaptation: { id: "adaptation-2" },
570
- },
571
- },
637
+ periodId: "period-1",
638
+ periodStart: 10,
639
+ adaptationId: "adaptation-2",
640
+ }),
572
641
  ]);
573
- mockPlaybackObserver.getCurrentTime.mockReturnValue(15);
642
+ vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(15);
574
643
 
575
644
  const result = getAdaptationSwitchStrategy(
576
645
  mockSegmentSink,
577
646
  mockPeriod,
578
647
  mockAdaptation,
579
648
  "seamless",
580
- mockPlaybackObserver,
649
+ mockedPlaybackObserver.observer,
581
650
  { onCodecSwitch: "continue" },
582
651
  );
583
652
 
@@ -586,26 +655,25 @@ describe("getAdaptationSwitchStrategy", () => {
586
655
  });
587
656
 
588
657
  it("should not exclude current position padding for direct mode", () => {
589
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
590
- {
658
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
659
+ makeBufferedChunk({
591
660
  start: 14.6,
592
661
  end: 15.4,
593
662
  bufferedStart: 14.6,
594
663
  bufferedEnd: 15.4,
595
- infos: {
596
- period: { id: "period-1", start: 10 },
597
- adaptation: { id: "adaptation-2" },
598
- },
599
- },
664
+ periodId: "period-1",
665
+ periodStart: 10,
666
+ adaptationId: "adaptation-2",
667
+ }),
600
668
  ]);
601
- mockPlaybackObserver.getCurrentTime.mockReturnValue(15);
669
+ vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(15);
602
670
 
603
671
  const result = getAdaptationSwitchStrategy(
604
672
  mockSegmentSink,
605
673
  mockPeriod,
606
674
  mockAdaptation,
607
675
  "direct",
608
- mockPlaybackObserver,
676
+ mockedPlaybackObserver.observer,
609
677
  { onCodecSwitch: "continue" },
610
678
  );
611
679
 
@@ -615,18 +683,20 @@ describe("getAdaptationSwitchStrategy", () => {
615
683
  });
616
684
 
617
685
  it("should use polled position when getCurrentTime returns undefined", () => {
618
- mockPlaybackObserver.getCurrentTime.mockReturnValue(undefined);
619
- mockSegmentSink.getLastKnownInventory.mockReturnValue([
620
- {
686
+ const mockGetRef = vi.spyOn(mockedPlaybackObserver.observer, "getReference");
687
+ vi.spyOn(mockedPlaybackObserver.observer, "getCurrentTime").mockReturnValue(
688
+ undefined,
689
+ );
690
+ vi.spyOn(mockSegmentSink, "getLastKnownInventory").mockReturnValue([
691
+ makeBufferedChunk({
621
692
  start: 14.6,
622
693
  end: 15.4,
623
694
  bufferedStart: 14.6,
624
695
  bufferedEnd: 15.4,
625
- infos: {
626
- period: { id: "period-1", start: 10 },
627
- adaptation: { id: "adaptation-2" },
628
- },
629
- },
696
+ periodId: "period-1",
697
+ periodStart: 10,
698
+ adaptationId: "adaptation-2",
699
+ }),
630
700
  ]);
631
701
 
632
702
  const result = getAdaptationSwitchStrategy(
@@ -634,11 +704,11 @@ describe("getAdaptationSwitchStrategy", () => {
634
704
  mockPeriod,
635
705
  mockAdaptation,
636
706
  "seamless",
637
- mockPlaybackObserver,
707
+ mockedPlaybackObserver.observer,
638
708
  { onCodecSwitch: "continue" },
639
709
  );
640
710
 
641
- expect(mockPlaybackObserver.getReference).toHaveBeenCalled();
711
+ expect(mockGetRef).toHaveBeenCalled();
642
712
  // Should still exclude based on polled position (15)
643
713
  expect(result).toEqual({ type: "continue", value: undefined });
644
714
  });