@livepeer-frameworks/player-core 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/README.md +11 -9
  2. package/dist/cjs/core/ABRController.js +456 -0
  3. package/dist/cjs/core/ABRController.js.map +1 -0
  4. package/dist/cjs/core/CodecUtils.js +195 -0
  5. package/dist/cjs/core/CodecUtils.js.map +1 -0
  6. package/dist/cjs/core/ErrorClassifier.js +410 -0
  7. package/dist/cjs/core/ErrorClassifier.js.map +1 -0
  8. package/dist/cjs/core/EventEmitter.js +108 -0
  9. package/dist/cjs/core/EventEmitter.js.map +1 -0
  10. package/dist/cjs/core/GatewayClient.js +342 -0
  11. package/dist/cjs/core/GatewayClient.js.map +1 -0
  12. package/dist/cjs/core/InteractionController.js +606 -0
  13. package/dist/cjs/core/InteractionController.js.map +1 -0
  14. package/dist/cjs/core/LiveDurationProxy.js +186 -0
  15. package/dist/cjs/core/LiveDurationProxy.js.map +1 -0
  16. package/dist/cjs/core/MetaTrackManager.js +624 -0
  17. package/dist/cjs/core/MetaTrackManager.js.map +1 -0
  18. package/dist/cjs/core/MistReporter.js +449 -0
  19. package/dist/cjs/core/MistReporter.js.map +1 -0
  20. package/dist/cjs/core/MistSignaling.js +264 -0
  21. package/dist/cjs/core/MistSignaling.js.map +1 -0
  22. package/dist/cjs/core/PlayerController.js +2658 -0
  23. package/dist/cjs/core/PlayerController.js.map +1 -0
  24. package/dist/cjs/core/PlayerInterface.js +269 -0
  25. package/dist/cjs/core/PlayerInterface.js.map +1 -0
  26. package/dist/cjs/core/PlayerManager.js +806 -0
  27. package/dist/cjs/core/PlayerManager.js.map +1 -0
  28. package/dist/cjs/core/PlayerRegistry.js +270 -0
  29. package/dist/cjs/core/PlayerRegistry.js.map +1 -0
  30. package/dist/cjs/core/QualityMonitor.js +474 -0
  31. package/dist/cjs/core/QualityMonitor.js.map +1 -0
  32. package/dist/cjs/core/SeekingUtils.js +292 -0
  33. package/dist/cjs/core/SeekingUtils.js.map +1 -0
  34. package/dist/cjs/core/StreamStateClient.js +381 -0
  35. package/dist/cjs/core/StreamStateClient.js.map +1 -0
  36. package/dist/cjs/core/SubtitleManager.js +227 -0
  37. package/dist/cjs/core/SubtitleManager.js.map +1 -0
  38. package/dist/cjs/core/TelemetryReporter.js +258 -0
  39. package/dist/cjs/core/TelemetryReporter.js.map +1 -0
  40. package/dist/cjs/core/TimeFormat.js +176 -0
  41. package/dist/cjs/core/TimeFormat.js.map +1 -0
  42. package/dist/cjs/core/TimerManager.js +176 -0
  43. package/dist/cjs/core/TimerManager.js.map +1 -0
  44. package/dist/cjs/core/UrlUtils.js +160 -0
  45. package/dist/cjs/core/UrlUtils.js.map +1 -0
  46. package/dist/cjs/core/detector.js +293 -0
  47. package/dist/cjs/core/detector.js.map +1 -0
  48. package/dist/cjs/core/scorer.js +443 -0
  49. package/dist/cjs/core/scorer.js.map +1 -0
  50. package/dist/cjs/index.js +121 -20134
  51. package/dist/cjs/index.js.map +1 -1
  52. package/dist/cjs/lib/utils.js +11 -0
  53. package/dist/cjs/lib/utils.js.map +1 -0
  54. package/dist/cjs/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.js +6 -0
  55. package/dist/cjs/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.js.map +1 -0
  56. package/dist/cjs/node_modules/.pnpm/tailwind-merge@3.4.0/node_modules/tailwind-merge/dist/bundle-mjs.js +3042 -0
  57. package/dist/cjs/node_modules/.pnpm/tailwind-merge@3.4.0/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  58. package/dist/cjs/players/DashJsPlayer.js +638 -0
  59. package/dist/cjs/players/DashJsPlayer.js.map +1 -0
  60. package/dist/cjs/players/HlsJsPlayer.js +482 -0
  61. package/dist/cjs/players/HlsJsPlayer.js.map +1 -0
  62. package/dist/cjs/players/MewsWsPlayer/SourceBufferManager.js +522 -0
  63. package/dist/cjs/players/MewsWsPlayer/SourceBufferManager.js.map +1 -0
  64. package/dist/cjs/players/MewsWsPlayer/WebSocketManager.js +215 -0
  65. package/dist/cjs/players/MewsWsPlayer/WebSocketManager.js.map +1 -0
  66. package/dist/cjs/players/MewsWsPlayer/index.js +987 -0
  67. package/dist/cjs/players/MewsWsPlayer/index.js.map +1 -0
  68. package/dist/cjs/players/MistPlayer.js +185 -0
  69. package/dist/cjs/players/MistPlayer.js.map +1 -0
  70. package/dist/cjs/players/MistWebRTCPlayer/index.js +635 -0
  71. package/dist/cjs/players/MistWebRTCPlayer/index.js.map +1 -0
  72. package/dist/cjs/players/NativePlayer.js +762 -0
  73. package/dist/cjs/players/NativePlayer.js.map +1 -0
  74. package/dist/cjs/players/VideoJsPlayer.js +585 -0
  75. package/dist/cjs/players/VideoJsPlayer.js.map +1 -0
  76. package/dist/cjs/players/WebCodecsPlayer/JitterBuffer.js +236 -0
  77. package/dist/cjs/players/WebCodecsPlayer/JitterBuffer.js.map +1 -0
  78. package/dist/cjs/players/WebCodecsPlayer/LatencyProfiles.js +143 -0
  79. package/dist/cjs/players/WebCodecsPlayer/LatencyProfiles.js.map +1 -0
  80. package/dist/cjs/players/WebCodecsPlayer/RawChunkParser.js +96 -0
  81. package/dist/cjs/players/WebCodecsPlayer/RawChunkParser.js.map +1 -0
  82. package/dist/cjs/players/WebCodecsPlayer/SyncController.js +359 -0
  83. package/dist/cjs/players/WebCodecsPlayer/SyncController.js.map +1 -0
  84. package/dist/cjs/players/WebCodecsPlayer/WebSocketController.js +460 -0
  85. package/dist/cjs/players/WebCodecsPlayer/WebSocketController.js.map +1 -0
  86. package/dist/cjs/players/WebCodecsPlayer/index.js +1467 -0
  87. package/dist/cjs/players/WebCodecsPlayer/index.js.map +1 -0
  88. package/dist/cjs/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.js +320 -0
  89. package/dist/cjs/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.js.map +1 -0
  90. package/dist/cjs/styles/index.js +57 -0
  91. package/dist/cjs/styles/index.js.map +1 -0
  92. package/dist/cjs/vanilla/FrameWorksPlayer.js +269 -0
  93. package/dist/cjs/vanilla/FrameWorksPlayer.js.map +1 -0
  94. package/dist/cjs/vanilla.js +11 -0
  95. package/dist/cjs/vanilla.js.map +1 -0
  96. package/dist/esm/core/ABRController.js +454 -0
  97. package/dist/esm/core/ABRController.js.map +1 -0
  98. package/dist/esm/core/CodecUtils.js +193 -0
  99. package/dist/esm/core/CodecUtils.js.map +1 -0
  100. package/dist/esm/core/ErrorClassifier.js +408 -0
  101. package/dist/esm/core/ErrorClassifier.js.map +1 -0
  102. package/dist/esm/core/EventEmitter.js +106 -0
  103. package/dist/esm/core/EventEmitter.js.map +1 -0
  104. package/dist/esm/core/GatewayClient.js +340 -0
  105. package/dist/esm/core/GatewayClient.js.map +1 -0
  106. package/dist/esm/core/InteractionController.js +604 -0
  107. package/dist/esm/core/InteractionController.js.map +1 -0
  108. package/dist/esm/core/LiveDurationProxy.js +184 -0
  109. package/dist/esm/core/LiveDurationProxy.js.map +1 -0
  110. package/dist/esm/core/MetaTrackManager.js +622 -0
  111. package/dist/esm/core/MetaTrackManager.js.map +1 -0
  112. package/dist/esm/core/MistReporter.js +447 -0
  113. package/dist/esm/core/MistReporter.js.map +1 -0
  114. package/dist/esm/core/MistSignaling.js +262 -0
  115. package/dist/esm/core/MistSignaling.js.map +1 -0
  116. package/dist/esm/core/PlayerController.js +2651 -0
  117. package/dist/esm/core/PlayerController.js.map +1 -0
  118. package/dist/esm/core/PlayerInterface.js +267 -0
  119. package/dist/esm/core/PlayerInterface.js.map +1 -0
  120. package/dist/esm/core/PlayerManager.js +804 -0
  121. package/dist/esm/core/PlayerManager.js.map +1 -0
  122. package/dist/esm/core/PlayerRegistry.js +264 -0
  123. package/dist/esm/core/PlayerRegistry.js.map +1 -0
  124. package/dist/esm/core/QualityMonitor.js +471 -0
  125. package/dist/esm/core/QualityMonitor.js.map +1 -0
  126. package/dist/esm/core/SeekingUtils.js +280 -0
  127. package/dist/esm/core/SeekingUtils.js.map +1 -0
  128. package/dist/esm/core/StreamStateClient.js +379 -0
  129. package/dist/esm/core/StreamStateClient.js.map +1 -0
  130. package/dist/esm/core/SubtitleManager.js +225 -0
  131. package/dist/esm/core/SubtitleManager.js.map +1 -0
  132. package/dist/esm/core/TelemetryReporter.js +256 -0
  133. package/dist/esm/core/TelemetryReporter.js.map +1 -0
  134. package/dist/esm/core/TimeFormat.js +169 -0
  135. package/dist/esm/core/TimeFormat.js.map +1 -0
  136. package/dist/esm/core/TimerManager.js +174 -0
  137. package/dist/esm/core/TimerManager.js.map +1 -0
  138. package/dist/esm/core/UrlUtils.js +151 -0
  139. package/dist/esm/core/UrlUtils.js.map +1 -0
  140. package/dist/esm/core/detector.js +279 -0
  141. package/dist/esm/core/detector.js.map +1 -0
  142. package/dist/esm/core/scorer.js +422 -0
  143. package/dist/esm/core/scorer.js.map +1 -0
  144. package/dist/esm/index.js +26 -20043
  145. package/dist/esm/index.js.map +1 -1
  146. package/dist/esm/lib/utils.js +9 -0
  147. package/dist/esm/lib/utils.js.map +1 -0
  148. package/dist/esm/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.js +4 -0
  149. package/dist/esm/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.js.map +1 -0
  150. package/dist/esm/node_modules/.pnpm/tailwind-merge@3.4.0/node_modules/tailwind-merge/dist/bundle-mjs.js +3036 -0
  151. package/dist/esm/node_modules/.pnpm/tailwind-merge@3.4.0/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  152. package/dist/esm/players/DashJsPlayer.js +636 -0
  153. package/dist/esm/players/DashJsPlayer.js.map +1 -0
  154. package/dist/esm/players/HlsJsPlayer.js +480 -0
  155. package/dist/esm/players/HlsJsPlayer.js.map +1 -0
  156. package/dist/esm/players/MewsWsPlayer/SourceBufferManager.js +520 -0
  157. package/dist/esm/players/MewsWsPlayer/SourceBufferManager.js.map +1 -0
  158. package/dist/esm/players/MewsWsPlayer/WebSocketManager.js +213 -0
  159. package/dist/esm/players/MewsWsPlayer/WebSocketManager.js.map +1 -0
  160. package/dist/esm/players/MewsWsPlayer/index.js +985 -0
  161. package/dist/esm/players/MewsWsPlayer/index.js.map +1 -0
  162. package/dist/esm/players/MistPlayer.js +183 -0
  163. package/dist/esm/players/MistPlayer.js.map +1 -0
  164. package/dist/esm/players/MistWebRTCPlayer/index.js +633 -0
  165. package/dist/esm/players/MistWebRTCPlayer/index.js.map +1 -0
  166. package/dist/esm/players/NativePlayer.js +759 -0
  167. package/dist/esm/players/NativePlayer.js.map +1 -0
  168. package/dist/esm/players/VideoJsPlayer.js +583 -0
  169. package/dist/esm/players/VideoJsPlayer.js.map +1 -0
  170. package/dist/esm/players/WebCodecsPlayer/JitterBuffer.js +233 -0
  171. package/dist/esm/players/WebCodecsPlayer/JitterBuffer.js.map +1 -0
  172. package/dist/esm/players/WebCodecsPlayer/LatencyProfiles.js +134 -0
  173. package/dist/esm/players/WebCodecsPlayer/LatencyProfiles.js.map +1 -0
  174. package/dist/esm/players/WebCodecsPlayer/RawChunkParser.js +91 -0
  175. package/dist/esm/players/WebCodecsPlayer/RawChunkParser.js.map +1 -0
  176. package/dist/esm/players/WebCodecsPlayer/SyncController.js +357 -0
  177. package/dist/esm/players/WebCodecsPlayer/SyncController.js.map +1 -0
  178. package/dist/esm/players/WebCodecsPlayer/WebSocketController.js +458 -0
  179. package/dist/esm/players/WebCodecsPlayer/WebSocketController.js.map +1 -0
  180. package/dist/esm/players/WebCodecsPlayer/index.js +1458 -0
  181. package/dist/esm/players/WebCodecsPlayer/index.js.map +1 -0
  182. package/dist/esm/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.js +315 -0
  183. package/dist/esm/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.js.map +1 -0
  184. package/dist/esm/styles/index.js +54 -0
  185. package/dist/esm/styles/index.js.map +1 -0
  186. package/dist/esm/vanilla/FrameWorksPlayer.js +264 -0
  187. package/dist/esm/vanilla/FrameWorksPlayer.js.map +1 -0
  188. package/dist/esm/vanilla.js +2 -0
  189. package/dist/esm/vanilla.js.map +1 -0
  190. package/dist/player.css +185 -42
  191. package/dist/types/core/ABRController.d.ts +4 -4
  192. package/dist/types/core/CodecUtils.d.ts +1 -1
  193. package/dist/types/core/ErrorClassifier.d.ts +77 -0
  194. package/dist/types/core/GatewayClient.d.ts +4 -4
  195. package/dist/types/core/MetaTrackManager.d.ts +2 -2
  196. package/dist/types/core/MistReporter.d.ts +3 -3
  197. package/dist/types/core/MistSignaling.d.ts +12 -12
  198. package/dist/types/core/PlayerController.d.ts +19 -14
  199. package/dist/types/core/PlayerInterface.d.ts +100 -2
  200. package/dist/types/core/PlayerManager.d.ts +36 -9
  201. package/dist/types/core/PlayerRegistry.d.ts +11 -11
  202. package/dist/types/core/QualityMonitor.d.ts +2 -2
  203. package/dist/types/core/SeekingUtils.d.ts +2 -2
  204. package/dist/types/core/StreamStateClient.d.ts +2 -2
  205. package/dist/types/core/TelemetryReporter.d.ts +1 -1
  206. package/dist/types/core/TimerManager.d.ts +1 -1
  207. package/dist/types/core/detector.d.ts +1 -1
  208. package/dist/types/core/index.d.ts +44 -44
  209. package/dist/types/core/scorer.d.ts +1 -1
  210. package/dist/types/core/selector.d.ts +2 -2
  211. package/dist/types/index.d.ts +35 -34
  212. package/dist/types/players/DashJsPlayer.d.ts +3 -3
  213. package/dist/types/players/HlsJsPlayer.d.ts +3 -3
  214. package/dist/types/players/MewsWsPlayer/SourceBufferManager.d.ts +1 -1
  215. package/dist/types/players/MewsWsPlayer/WebSocketManager.d.ts +1 -1
  216. package/dist/types/players/MewsWsPlayer/index.d.ts +2 -2
  217. package/dist/types/players/MewsWsPlayer/types.d.ts +15 -15
  218. package/dist/types/players/MistPlayer.d.ts +2 -2
  219. package/dist/types/players/MistWebRTCPlayer/index.d.ts +3 -3
  220. package/dist/types/players/NativePlayer.d.ts +3 -3
  221. package/dist/types/players/VideoJsPlayer.d.ts +3 -3
  222. package/dist/types/players/WebCodecsPlayer/JitterBuffer.d.ts +3 -3
  223. package/dist/types/players/WebCodecsPlayer/LatencyProfiles.d.ts +1 -1
  224. package/dist/types/players/WebCodecsPlayer/RawChunkParser.d.ts +2 -2
  225. package/dist/types/players/WebCodecsPlayer/SyncController.d.ts +2 -2
  226. package/dist/types/players/WebCodecsPlayer/WebSocketController.d.ts +3 -3
  227. package/dist/types/players/WebCodecsPlayer/index.d.ts +9 -9
  228. package/dist/types/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.d.ts +1 -1
  229. package/dist/types/players/WebCodecsPlayer/types.d.ts +49 -49
  230. package/dist/types/players/WebCodecsPlayer/worker/types.d.ts +31 -31
  231. package/dist/types/players/index.d.ts +5 -8
  232. package/dist/types/types.d.ts +15 -15
  233. package/dist/types/vanilla/FrameWorksPlayer.d.ts +2 -2
  234. package/dist/types/vanilla/index.d.ts +4 -4
  235. package/dist/workers/decoder.worker.js +129 -122
  236. package/dist/workers/decoder.worker.js.map +1 -1
  237. package/package.json +31 -15
  238. package/src/core/ABRController.ts +38 -36
  239. package/src/core/CodecUtils.ts +49 -46
  240. package/src/core/Disposable.ts +4 -4
  241. package/src/core/ErrorClassifier.ts +499 -0
  242. package/src/core/EventEmitter.ts +1 -1
  243. package/src/core/GatewayClient.ts +41 -39
  244. package/src/core/InteractionController.ts +89 -82
  245. package/src/core/LiveDurationProxy.ts +14 -15
  246. package/src/core/MetaTrackManager.ts +73 -65
  247. package/src/core/MistReporter.ts +72 -45
  248. package/src/core/MistSignaling.ts +59 -56
  249. package/src/core/PlayerController.ts +542 -384
  250. package/src/core/PlayerInterface.ts +192 -59
  251. package/src/core/PlayerManager.ts +354 -164
  252. package/src/core/PlayerRegistry.ts +238 -87
  253. package/src/core/QualityMonitor.ts +38 -31
  254. package/src/core/ScreenWakeLockManager.ts +8 -9
  255. package/src/core/SeekingUtils.ts +31 -22
  256. package/src/core/StreamStateClient.ts +74 -68
  257. package/src/core/SubtitleManager.ts +24 -22
  258. package/src/core/TelemetryReporter.ts +38 -32
  259. package/src/core/TimeFormat.ts +13 -17
  260. package/src/core/TimerManager.ts +24 -8
  261. package/src/core/UrlUtils.ts +20 -17
  262. package/src/core/detector.ts +44 -44
  263. package/src/core/index.ts +57 -48
  264. package/src/core/scorer.ts +136 -141
  265. package/src/core/selector.ts +2 -6
  266. package/src/global.d.ts +1 -1
  267. package/src/index.ts +56 -36
  268. package/src/players/DashJsPlayer.ts +164 -115
  269. package/src/players/HlsJsPlayer.ts +132 -78
  270. package/src/players/MewsWsPlayer/SourceBufferManager.ts +41 -36
  271. package/src/players/MewsWsPlayer/WebSocketManager.ts +9 -9
  272. package/src/players/MewsWsPlayer/index.ts +192 -152
  273. package/src/players/MewsWsPlayer/types.ts +21 -21
  274. package/src/players/MistPlayer.ts +45 -26
  275. package/src/players/MistWebRTCPlayer/index.ts +175 -129
  276. package/src/players/NativePlayer.ts +203 -143
  277. package/src/players/VideoJsPlayer.ts +170 -118
  278. package/src/players/WebCodecsPlayer/JitterBuffer.ts +6 -7
  279. package/src/players/WebCodecsPlayer/LatencyProfiles.ts +43 -43
  280. package/src/players/WebCodecsPlayer/RawChunkParser.ts +10 -10
  281. package/src/players/WebCodecsPlayer/SyncController.ts +45 -53
  282. package/src/players/WebCodecsPlayer/WebSocketController.ts +66 -68
  283. package/src/players/WebCodecsPlayer/index.ts +265 -223
  284. package/src/players/WebCodecsPlayer/polyfills/MediaStreamTrackGenerator.ts +12 -17
  285. package/src/players/WebCodecsPlayer/types.ts +56 -56
  286. package/src/players/WebCodecsPlayer/worker/decoder.worker.ts +238 -182
  287. package/src/players/WebCodecsPlayer/worker/types.ts +31 -31
  288. package/src/players/index.ts +5 -16
  289. package/src/styles/animations.css +2 -1
  290. package/src/styles/player.css +185 -42
  291. package/src/styles/tailwind.css +473 -159
  292. package/src/types.ts +43 -43
  293. package/src/vanilla/FrameWorksPlayer.ts +26 -14
  294. package/src/vanilla/index.ts +4 -4
package/README.md CHANGED
@@ -15,36 +15,37 @@ npm i @livepeer-frameworks/player-core
15
15
  ## Basic Usage
16
16
 
17
17
  ```ts
18
- import { PlayerController } from '@livepeer-frameworks/player-core';
18
+ import { PlayerController } from "@livepeer-frameworks/player-core";
19
19
 
20
20
  const controller = new PlayerController({
21
- contentId: 'pk_...', // playbackId
22
- contentType: 'live',
23
- gatewayUrl: 'https://your-bridge/graphql',
21
+ contentId: "pk_...", // playbackId
22
+ contentType: "live",
23
+ gatewayUrl: "https://your-bridge/graphql",
24
24
  debug: true,
25
25
  });
26
26
 
27
- const container = document.getElementById('player')!;
27
+ const container = document.getElementById("player")!;
28
28
  await controller.attach(container);
29
29
  ```
30
30
 
31
31
  Notes:
32
+
32
33
  - There is **no default gateway**; provide `gatewayUrl` unless you pass `endpoints` or `mistUrl`.
33
34
 
34
35
  ### Direct MistServer Node (mistUrl)
35
36
 
36
37
  ```ts
37
38
  const controller = new PlayerController({
38
- contentId: 'pk_...',
39
- contentType: 'live',
40
- mistUrl: 'https://edge.example.com',
39
+ contentId: "pk_...",
40
+ contentType: "live",
41
+ mistUrl: "https://edge.example.com",
41
42
  });
42
43
  ```
43
44
 
44
45
  ### Styles
45
46
 
46
47
  ```ts
47
- import '@livepeer-frameworks/player-core/player.css';
48
+ import "@livepeer-frameworks/player-core/player.css";
48
49
  ```
49
50
 
50
51
  ## Controls & Shortcuts
@@ -73,6 +74,7 @@ The player ships with keyboard/mouse shortcuts when the player is focused (click
73
74
  | Click/Tap and hold | 2x speed | Disabled on live-only |
74
75
 
75
76
  **Constraints**
77
+
76
78
  - Live-only streams disable seeking/skip/2x hold and frame-step.
77
79
  - Live with DVR buffer enables the same shortcuts as VOD.
78
80
  - Frame stepping only moves within already buffered ranges (no network seek). WebCodecs supports true frame stepping when paused.
@@ -0,0 +1,456 @@
1
+ 'use strict';
2
+
3
+ var TimerManager = require('./TimerManager.js');
4
+
5
+ /**
6
+ * Default ABR options
7
+ */
8
+ const DEFAULT_OPTIONS = {
9
+ mode: "auto",
10
+ maxResolution: { width: 1920, height: 1080 },
11
+ maxBitrate: 8000000, // 8 Mbps
12
+ minBufferForUpgrade: 10,
13
+ downgradeThreshold: 60,
14
+ };
15
+ /**
16
+ * ABRController - Adaptive Bitrate Controller
17
+ *
18
+ * Manages automatic quality selection based on:
19
+ * - ABR_resize: Matches video resolution to viewport size
20
+ * - ABR_bitrate: Switches quality based on playback performance
21
+ * - auto: Combines both modes
22
+ * - manual: No automatic switching
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const abr = new ABRController({
27
+ * options: { mode: 'auto' },
28
+ * getQualities: () => player.getQualities(),
29
+ * selectQuality: (id) => player.selectQuality(id),
30
+ * });
31
+ *
32
+ * abr.start(videoElement);
33
+ * abr.onQualityChange((quality) => console.log('Quality:', quality.score));
34
+ * ```
35
+ */
36
+ class ABRController {
37
+ constructor(config) {
38
+ this.videoElement = null;
39
+ this.currentQualityId = "auto";
40
+ this.lastDecision = "none";
41
+ this.lastDecisionTime = 0;
42
+ this.resizeObserver = null;
43
+ this.qualityChangeCallbacks = [];
44
+ // Active monitoring
45
+ this.timers = new TimerManager.TimerManager();
46
+ this.bandwidthHistory = [];
47
+ this.lastUpgradeTime = 0;
48
+ this.lastDowngradeTime = 0;
49
+ this.currentQualityBitrate = 0;
50
+ this.options = { ...DEFAULT_OPTIONS, ...config.options };
51
+ this.config = config;
52
+ this.debug = config.debug ?? false;
53
+ }
54
+ /**
55
+ * Start ABR control
56
+ */
57
+ start(videoElement) {
58
+ this.stop();
59
+ this.videoElement = videoElement;
60
+ if (this.options.mode === "manual") {
61
+ this.log("Manual mode - no automatic ABR");
62
+ return;
63
+ }
64
+ // Setup resize observer for ABR_resize mode
65
+ if (this.options.mode === "resize" || this.options.mode === "auto") {
66
+ this.setupResizeObserver();
67
+ }
68
+ // Start active bandwidth monitoring for bitrate mode
69
+ if (this.options.mode === "bitrate" || this.options.mode === "auto") {
70
+ this.startActiveMonitoring();
71
+ }
72
+ }
73
+ /**
74
+ * Stop ABR control
75
+ */
76
+ stop() {
77
+ if (this.resizeObserver) {
78
+ this.resizeObserver.disconnect();
79
+ this.resizeObserver = null;
80
+ }
81
+ this.timers.destroy();
82
+ this.videoElement = null;
83
+ this.bandwidthHistory = [];
84
+ }
85
+ /**
86
+ * Start active bandwidth monitoring loop
87
+ * Continuously monitors bandwidth and proactively switches quality
88
+ */
89
+ startActiveMonitoring() {
90
+ this.timers.startInterval(() => this.checkBandwidthAndSwitch(), ABRController.MONITORING_INTERVAL_MS, "monitoring");
91
+ // Initial check
92
+ this.checkBandwidthAndSwitch();
93
+ }
94
+ /**
95
+ * Check current bandwidth and switch quality if needed
96
+ *
97
+ * Uses hysteresis (D2) and separate cooldowns (D3) to prevent oscillation:
98
+ * - Downgrade: immediate response (0ms cooldown), triggers at 0.8x
99
+ * - Upgrade: 5s cooldown, requires 1.5x headroom, holds until 1.2x
100
+ */
101
+ async checkBandwidthAndSwitch() {
102
+ if (!this.videoElement)
103
+ return;
104
+ const now = Date.now();
105
+ // Get bandwidth estimate from player stats
106
+ const bandwidth = await this.getBandwidthEstimate();
107
+ if (bandwidth <= 0)
108
+ return;
109
+ // Add to history
110
+ this.bandwidthHistory.push(bandwidth);
111
+ if (this.bandwidthHistory.length > ABRController.BANDWIDTH_HISTORY_SIZE) {
112
+ this.bandwidthHistory.shift();
113
+ }
114
+ // Use smoothed bandwidth (average of history)
115
+ const smoothedBandwidth = this.getSmoothedBandwidth();
116
+ if (smoothedBandwidth <= 0)
117
+ return;
118
+ const qualities = this.config.getQualities();
119
+ const currentQuality = this.config.getCurrentQuality?.();
120
+ if (!currentQuality || qualities.length === 0)
121
+ return;
122
+ const currentBitrate = currentQuality.bitrate || 0;
123
+ // Track current quality bitrate for hysteresis
124
+ if (this.currentQualityBitrate !== currentBitrate) {
125
+ this.currentQualityBitrate = currentBitrate;
126
+ }
127
+ // D3: Check for downgrade (immediate, no cooldown)
128
+ if (now - this.lastDowngradeTime >= ABRController.DOWNGRADE_COOLDOWN_MS) {
129
+ if (smoothedBandwidth < currentBitrate * ABRController.DOWNGRADE_THRESHOLD) {
130
+ const lowerQuality = this.findLowerQuality(qualities, currentQuality);
131
+ if (lowerQuality) {
132
+ this.log(`ABR: bandwidth ${Math.round(smoothedBandwidth / 1000)}kbps < ${Math.round((currentBitrate * ABRController.DOWNGRADE_THRESHOLD) / 1000)}kbps threshold -> downgrading to ${lowerQuality.label}`);
133
+ this.lastDecision = "downgrade";
134
+ this.lastDecisionTime = now;
135
+ this.lastDowngradeTime = now;
136
+ this.selectQuality(lowerQuality.id);
137
+ return;
138
+ }
139
+ }
140
+ }
141
+ // D3: Check for upgrade (5s cooldown required)
142
+ if (now - this.lastUpgradeTime >= ABRController.UPGRADE_COOLDOWN_MS) {
143
+ const higherQuality = this.findHigherQuality(qualities, currentQuality);
144
+ if (higherQuality && this.isWithinConstraints(higherQuality)) {
145
+ const targetBitrate = higherQuality.bitrate || 0;
146
+ // D2: Hysteresis - require 1.5x headroom to upgrade
147
+ // Once at a quality level, stay until bandwidth drops below 1.2x (not 1.0x)
148
+ const shouldUpgrade = smoothedBandwidth >= targetBitrate * ABRController.UPGRADE_HEADROOM;
149
+ smoothedBandwidth >= targetBitrate * ABRController.UPGRADE_HOLD_THRESHOLD;
150
+ if (shouldUpgrade) {
151
+ this.log(`ABR: bandwidth ${Math.round(smoothedBandwidth / 1000)}kbps >= ${Math.round((targetBitrate * ABRController.UPGRADE_HEADROOM) / 1000)}kbps headroom -> upgrading to ${higherQuality.label}`);
152
+ this.lastDecision = "upgrade";
153
+ this.lastDecisionTime = now;
154
+ this.lastUpgradeTime = now;
155
+ this.selectQuality(higherQuality.id);
156
+ return;
157
+ }
158
+ }
159
+ }
160
+ }
161
+ /**
162
+ * Get bandwidth estimate from player stats
163
+ */
164
+ async getBandwidthEstimate() {
165
+ // Try to get bandwidth from player stats
166
+ if (this.config.getBandwidthEstimate) {
167
+ const estimate = await this.config.getBandwidthEstimate();
168
+ if (estimate > 0)
169
+ return estimate;
170
+ }
171
+ // Fallback: estimate from buffer growth (rough)
172
+ const video = this.videoElement;
173
+ if (!video || video.buffered.length === 0)
174
+ return 0;
175
+ // This is a rough fallback - prefer player-specific estimates
176
+ return 0;
177
+ }
178
+ /**
179
+ * Get smoothed bandwidth from history
180
+ */
181
+ getSmoothedBandwidth() {
182
+ if (this.bandwidthHistory.length === 0)
183
+ return 0;
184
+ if (this.bandwidthHistory.length < 3) {
185
+ // Need at least 3 samples for reliable estimate
186
+ return 0;
187
+ }
188
+ const sum = this.bandwidthHistory.reduce((a, b) => a + b, 0);
189
+ return sum / this.bandwidthHistory.length;
190
+ }
191
+ /**
192
+ * Get current bandwidth estimate (for external use)
193
+ */
194
+ getCurrentBandwidth() {
195
+ return this.getSmoothedBandwidth();
196
+ }
197
+ /**
198
+ * Setup resize observer for viewport-based quality selection
199
+ */
200
+ setupResizeObserver() {
201
+ const video = this.videoElement;
202
+ if (!video)
203
+ return;
204
+ this.resizeObserver = new ResizeObserver((entries) => {
205
+ for (const entry of entries) {
206
+ const { width, height } = entry.contentRect;
207
+ this.handleResize(width, height);
208
+ }
209
+ });
210
+ // Observe the video element's container
211
+ const container = video.parentElement;
212
+ if (container) {
213
+ this.resizeObserver.observe(container);
214
+ }
215
+ // Initial resize handling
216
+ const rect = video.getBoundingClientRect();
217
+ this.handleResize(rect.width, rect.height);
218
+ }
219
+ /**
220
+ * Handle viewport resize (ABR_resize mode)
221
+ */
222
+ handleResize(width, height) {
223
+ if (this.options.mode !== "resize" && this.options.mode !== "auto") {
224
+ return;
225
+ }
226
+ const qualities = this.config.getQualities();
227
+ if (qualities.length === 0)
228
+ return;
229
+ // Find best quality for viewport size
230
+ const targetWidth = Math.min(width * window.devicePixelRatio, this.options.maxResolution.width);
231
+ const targetHeight = Math.min(height * window.devicePixelRatio, this.options.maxResolution.height);
232
+ const bestQuality = this.findBestQualityForResolution(qualities, targetWidth, targetHeight);
233
+ if (bestQuality && bestQuality.id !== this.currentQualityId) {
234
+ this.log(`Resize ABR: ${width}x${height} -> selecting ${bestQuality.label}`);
235
+ this.selectQuality(bestQuality.id);
236
+ }
237
+ }
238
+ /**
239
+ * Handle quality degradation (ABR_bitrate mode)
240
+ *
241
+ * Called by QualityMonitor when playback quality drops
242
+ */
243
+ handleQualityDegraded(quality) {
244
+ if (this.options.mode !== "bitrate" && this.options.mode !== "auto") {
245
+ return;
246
+ }
247
+ // D3: Downgrade should be fast (0ms default), but still respects configured cooldown
248
+ const now = Date.now();
249
+ if (now - this.lastDowngradeTime < ABRController.DOWNGRADE_COOLDOWN_MS) {
250
+ return;
251
+ }
252
+ if (quality.score < this.options.downgradeThreshold) {
253
+ const qualities = this.config.getQualities();
254
+ const currentQuality = this.config.getCurrentQuality?.();
255
+ if (currentQuality) {
256
+ // Find a lower quality level
257
+ const lowerQuality = this.findLowerQuality(qualities, currentQuality);
258
+ if (lowerQuality) {
259
+ this.log(`Bitrate ABR: score ${quality.score} -> downgrading to ${lowerQuality.label}`);
260
+ this.lastDecision = "downgrade";
261
+ this.lastDecisionTime = now;
262
+ this.lastDowngradeTime = now;
263
+ this.selectQuality(lowerQuality.id);
264
+ }
265
+ }
266
+ }
267
+ }
268
+ /**
269
+ * Handle quality improvement opportunity
270
+ *
271
+ * Called when conditions are good enough to try higher quality
272
+ */
273
+ handleQualityImproved(quality) {
274
+ if (this.options.mode !== "bitrate" && this.options.mode !== "auto") {
275
+ return;
276
+ }
277
+ // D3: Upgrade requires sustained stability (5s default) to prevent flapping
278
+ const now = Date.now();
279
+ if (now - this.lastUpgradeTime < ABRController.UPGRADE_COOLDOWN_MS) {
280
+ return;
281
+ }
282
+ // Only upgrade if buffer is healthy and quality is good
283
+ if (quality.score >= 90 && quality.bufferedAhead >= this.options.minBufferForUpgrade) {
284
+ const qualities = this.config.getQualities();
285
+ const currentQuality = this.config.getCurrentQuality?.();
286
+ if (currentQuality) {
287
+ // Find a higher quality level
288
+ const higherQuality = this.findHigherQuality(qualities, currentQuality);
289
+ if (higherQuality && this.isWithinConstraints(higherQuality)) {
290
+ this.log(`Bitrate ABR: score ${quality.score} -> upgrading to ${higherQuality.label}`);
291
+ this.lastDecision = "upgrade";
292
+ this.lastDecisionTime = now;
293
+ this.lastUpgradeTime = now;
294
+ this.selectQuality(higherQuality.id);
295
+ }
296
+ }
297
+ }
298
+ }
299
+ /**
300
+ * Find best quality level for given resolution
301
+ */
302
+ findBestQualityForResolution(qualities, targetWidth, targetHeight) {
303
+ // Filter out qualities that exceed constraints
304
+ const validQualities = qualities.filter((q) => this.isWithinConstraints(q));
305
+ if (validQualities.length === 0)
306
+ return null;
307
+ // Sort by resolution (ascending)
308
+ const sorted = [...validQualities].sort((a, b) => {
309
+ const aPixels = (a.width ?? 0) * (a.height ?? 0);
310
+ const bPixels = (b.width ?? 0) * (b.height ?? 0);
311
+ return aPixels - bPixels;
312
+ });
313
+ // Find smallest quality that is >= target resolution
314
+ for (const q of sorted) {
315
+ const qWidth = q.width ?? 0;
316
+ const qHeight = q.height ?? 0;
317
+ if (qWidth >= targetWidth && qHeight >= targetHeight) {
318
+ return q;
319
+ }
320
+ }
321
+ // If no quality is large enough, return the highest available
322
+ return sorted[sorted.length - 1];
323
+ }
324
+ /**
325
+ * Find a lower quality level
326
+ */
327
+ findLowerQuality(qualities, current) {
328
+ const currentBitrate = current.bitrate ?? 0;
329
+ // Sort by bitrate descending
330
+ const sorted = [...qualities].sort((a, b) => (b.bitrate ?? 0) - (a.bitrate ?? 0));
331
+ // Find next lower bitrate
332
+ for (const q of sorted) {
333
+ if ((q.bitrate ?? 0) < currentBitrate) {
334
+ return q;
335
+ }
336
+ }
337
+ return null;
338
+ }
339
+ /**
340
+ * Find a higher quality level
341
+ */
342
+ findHigherQuality(qualities, current) {
343
+ const currentBitrate = current.bitrate ?? 0;
344
+ // Sort by bitrate ascending
345
+ const sorted = [...qualities].sort((a, b) => (a.bitrate ?? 0) - (b.bitrate ?? 0));
346
+ // Find next higher bitrate
347
+ for (const q of sorted) {
348
+ if ((q.bitrate ?? 0) > currentBitrate) {
349
+ return q;
350
+ }
351
+ }
352
+ return null;
353
+ }
354
+ /**
355
+ * Check if quality is within configured constraints
356
+ */
357
+ isWithinConstraints(quality) {
358
+ const { maxResolution, maxBitrate } = this.options;
359
+ if (quality.width && quality.width > maxResolution.width)
360
+ return false;
361
+ if (quality.height && quality.height > maxResolution.height)
362
+ return false;
363
+ if (quality.bitrate && quality.bitrate > maxBitrate)
364
+ return false;
365
+ return true;
366
+ }
367
+ /**
368
+ * Select a quality level
369
+ */
370
+ selectQuality(id) {
371
+ this.currentQualityId = id;
372
+ this.config.selectQuality(id);
373
+ // Notify callbacks
374
+ const qualities = this.config.getQualities();
375
+ const selected = qualities.find((q) => q.id === id);
376
+ if (selected) {
377
+ this.qualityChangeCallbacks.forEach((cb) => cb(selected));
378
+ }
379
+ }
380
+ /**
381
+ * Register callback for quality changes
382
+ */
383
+ onQualityChange(callback) {
384
+ this.qualityChangeCallbacks.push(callback);
385
+ return () => {
386
+ const idx = this.qualityChangeCallbacks.indexOf(callback);
387
+ if (idx >= 0) {
388
+ this.qualityChangeCallbacks.splice(idx, 1);
389
+ }
390
+ };
391
+ }
392
+ /**
393
+ * Manually set quality (switches to manual mode temporarily)
394
+ */
395
+ setQuality(id) {
396
+ this.selectQuality(id);
397
+ }
398
+ /**
399
+ * Get current ABR mode
400
+ */
401
+ getMode() {
402
+ return this.options.mode;
403
+ }
404
+ /**
405
+ * Set ABR mode at runtime.
406
+ * Restarts monitoring if video element is attached.
407
+ */
408
+ setMode(mode) {
409
+ if (this.options.mode === mode)
410
+ return;
411
+ this.options.mode = mode;
412
+ this.log(`Mode changed to: ${mode}`);
413
+ // Restart with new mode if we have a video element
414
+ if (this.videoElement) {
415
+ const video = this.videoElement;
416
+ this.stop();
417
+ this.start(video);
418
+ }
419
+ }
420
+ /**
421
+ * Update ABR options
422
+ */
423
+ updateOptions(options) {
424
+ this.options = { ...this.options, ...options };
425
+ }
426
+ /**
427
+ * Get last ABR decision
428
+ */
429
+ getLastDecision() {
430
+ return this.lastDecision;
431
+ }
432
+ /**
433
+ * Debug logging
434
+ */
435
+ log(message) {
436
+ if (this.debug) {
437
+ console.debug(`[ABRController] ${message}`);
438
+ }
439
+ }
440
+ }
441
+ ABRController.BANDWIDTH_HISTORY_SIZE = 10;
442
+ ABRController.MONITORING_INTERVAL_MS = 1000;
443
+ // D3: Separate upgrade/downgrade cooldowns
444
+ // Downgrade is immediate (0ms) for quick response to problems
445
+ // Upgrade requires 5s stability to prevent flapping
446
+ ABRController.UPGRADE_COOLDOWN_MS = 5000;
447
+ ABRController.DOWNGRADE_COOLDOWN_MS = 0;
448
+ // D2: Hysteresis bands to prevent oscillation at boundaries
449
+ // Upgrade: must exceed 1.5x to upgrade, stay until drops below 1.2x
450
+ // Downgrade: must drop below 0.8x to downgrade
451
+ ABRController.UPGRADE_HEADROOM = 1.5;
452
+ ABRController.UPGRADE_HOLD_THRESHOLD = 1.2;
453
+ ABRController.DOWNGRADE_THRESHOLD = 0.8;
454
+
455
+ exports.ABRController = ABRController;
456
+ //# sourceMappingURL=ABRController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ABRController.js","sources":["../../../../src/core/ABRController.ts"],"sourcesContent":["import type { ABRMode, ABROptions, PlaybackQuality, QualityLevel } from \"../types\";\nimport { TimerManager } from \"./TimerManager\";\n\n/**\n * Default ABR options\n */\nconst DEFAULT_OPTIONS: Required<ABROptions> = {\n mode: \"auto\",\n maxResolution: { width: 1920, height: 1080 },\n maxBitrate: 8000000, // 8 Mbps\n minBufferForUpgrade: 10,\n downgradeThreshold: 60,\n};\n\nexport interface ABRControllerConfig {\n /** ABR options */\n options?: Partial<ABROptions>;\n /** Callback to get available qualities */\n getQualities: () => QualityLevel[];\n /** Callback to select a quality */\n selectQuality: (id: string | \"auto\") => void;\n /** Callback to get current quality */\n getCurrentQuality?: () => QualityLevel | null;\n /** Callback to get bandwidth estimate (bits per second) - typically from player stats */\n getBandwidthEstimate?: () => Promise<number>;\n /** Debug logging */\n debug?: boolean;\n}\n\nexport type ABRDecision = \"upgrade\" | \"downgrade\" | \"maintain\" | \"none\";\n\n/**\n * ABRController - Adaptive Bitrate Controller\n *\n * Manages automatic quality selection based on:\n * - ABR_resize: Matches video resolution to viewport size\n * - ABR_bitrate: Switches quality based on playback performance\n * - auto: Combines both modes\n * - manual: No automatic switching\n *\n * @example\n * ```ts\n * const abr = new ABRController({\n * options: { mode: 'auto' },\n * getQualities: () => player.getQualities(),\n * selectQuality: (id) => player.selectQuality(id),\n * });\n *\n * abr.start(videoElement);\n * abr.onQualityChange((quality) => console.log('Quality:', quality.score));\n * ```\n */\nexport class ABRController {\n private options: Required<ABROptions>;\n private config: ABRControllerConfig;\n private videoElement: HTMLVideoElement | null = null;\n private currentQualityId: string | \"auto\" = \"auto\";\n private lastDecision: ABRDecision = \"none\";\n private lastDecisionTime = 0;\n private resizeObserver: ResizeObserver | null = null;\n private qualityChangeCallbacks: Array<(level: QualityLevel) => void> = [];\n private debug: boolean;\n\n // Active monitoring\n private timers = new TimerManager();\n private bandwidthHistory: number[] = [];\n private static readonly BANDWIDTH_HISTORY_SIZE = 10;\n private static readonly MONITORING_INTERVAL_MS = 1000;\n\n // D3: Separate upgrade/downgrade cooldowns\n // Downgrade is immediate (0ms) for quick response to problems\n // Upgrade requires 5s stability to prevent flapping\n private static readonly UPGRADE_COOLDOWN_MS = 5000;\n private static readonly DOWNGRADE_COOLDOWN_MS = 0;\n private lastUpgradeTime = 0;\n private lastDowngradeTime = 0;\n\n // D2: Hysteresis bands to prevent oscillation at boundaries\n // Upgrade: must exceed 1.5x to upgrade, stay until drops below 1.2x\n // Downgrade: must drop below 0.8x to downgrade\n private static readonly UPGRADE_HEADROOM = 1.5;\n private static readonly UPGRADE_HOLD_THRESHOLD = 1.2;\n private static readonly DOWNGRADE_THRESHOLD = 0.8;\n private currentQualityBitrate = 0;\n\n constructor(config: ABRControllerConfig) {\n this.options = { ...DEFAULT_OPTIONS, ...config.options };\n this.config = config;\n this.debug = config.debug ?? false;\n }\n\n /**\n * Start ABR control\n */\n start(videoElement: HTMLVideoElement): void {\n this.stop();\n this.videoElement = videoElement;\n\n if (this.options.mode === \"manual\") {\n this.log(\"Manual mode - no automatic ABR\");\n return;\n }\n\n // Setup resize observer for ABR_resize mode\n if (this.options.mode === \"resize\" || this.options.mode === \"auto\") {\n this.setupResizeObserver();\n }\n\n // Start active bandwidth monitoring for bitrate mode\n if (this.options.mode === \"bitrate\" || this.options.mode === \"auto\") {\n this.startActiveMonitoring();\n }\n }\n\n /**\n * Stop ABR control\n */\n stop(): void {\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n this.timers.destroy();\n this.videoElement = null;\n this.bandwidthHistory = [];\n }\n\n /**\n * Start active bandwidth monitoring loop\n * Continuously monitors bandwidth and proactively switches quality\n */\n private startActiveMonitoring(): void {\n this.timers.startInterval(\n () => this.checkBandwidthAndSwitch(),\n ABRController.MONITORING_INTERVAL_MS,\n \"monitoring\"\n );\n\n // Initial check\n this.checkBandwidthAndSwitch();\n }\n\n /**\n * Check current bandwidth and switch quality if needed\n *\n * Uses hysteresis (D2) and separate cooldowns (D3) to prevent oscillation:\n * - Downgrade: immediate response (0ms cooldown), triggers at 0.8x\n * - Upgrade: 5s cooldown, requires 1.5x headroom, holds until 1.2x\n */\n private async checkBandwidthAndSwitch(): Promise<void> {\n if (!this.videoElement) return;\n\n const now = Date.now();\n\n // Get bandwidth estimate from player stats\n const bandwidth = await this.getBandwidthEstimate();\n if (bandwidth <= 0) return;\n\n // Add to history\n this.bandwidthHistory.push(bandwidth);\n if (this.bandwidthHistory.length > ABRController.BANDWIDTH_HISTORY_SIZE) {\n this.bandwidthHistory.shift();\n }\n\n // Use smoothed bandwidth (average of history)\n const smoothedBandwidth = this.getSmoothedBandwidth();\n if (smoothedBandwidth <= 0) return;\n\n const qualities = this.config.getQualities();\n const currentQuality = this.config.getCurrentQuality?.();\n if (!currentQuality || qualities.length === 0) return;\n\n const currentBitrate = currentQuality.bitrate || 0;\n\n // Track current quality bitrate for hysteresis\n if (this.currentQualityBitrate !== currentBitrate) {\n this.currentQualityBitrate = currentBitrate;\n }\n\n // D3: Check for downgrade (immediate, no cooldown)\n if (now - this.lastDowngradeTime >= ABRController.DOWNGRADE_COOLDOWN_MS) {\n if (smoothedBandwidth < currentBitrate * ABRController.DOWNGRADE_THRESHOLD) {\n const lowerQuality = this.findLowerQuality(qualities, currentQuality);\n if (lowerQuality) {\n this.log(\n `ABR: bandwidth ${Math.round(smoothedBandwidth / 1000)}kbps < ${Math.round((currentBitrate * ABRController.DOWNGRADE_THRESHOLD) / 1000)}kbps threshold -> downgrading to ${lowerQuality.label}`\n );\n this.lastDecision = \"downgrade\";\n this.lastDecisionTime = now;\n this.lastDowngradeTime = now;\n this.selectQuality(lowerQuality.id);\n return;\n }\n }\n }\n\n // D3: Check for upgrade (5s cooldown required)\n if (now - this.lastUpgradeTime >= ABRController.UPGRADE_COOLDOWN_MS) {\n const higherQuality = this.findHigherQuality(qualities, currentQuality);\n if (higherQuality && this.isWithinConstraints(higherQuality)) {\n const targetBitrate = higherQuality.bitrate || 0;\n\n // D2: Hysteresis - require 1.5x headroom to upgrade\n // Once at a quality level, stay until bandwidth drops below 1.2x (not 1.0x)\n const shouldUpgrade = smoothedBandwidth >= targetBitrate * ABRController.UPGRADE_HEADROOM;\n const _canHoldHigher =\n smoothedBandwidth >= targetBitrate * ABRController.UPGRADE_HOLD_THRESHOLD;\n\n if (shouldUpgrade) {\n this.log(\n `ABR: bandwidth ${Math.round(smoothedBandwidth / 1000)}kbps >= ${Math.round((targetBitrate * ABRController.UPGRADE_HEADROOM) / 1000)}kbps headroom -> upgrading to ${higherQuality.label}`\n );\n this.lastDecision = \"upgrade\";\n this.lastDecisionTime = now;\n this.lastUpgradeTime = now;\n this.selectQuality(higherQuality.id);\n return;\n }\n }\n }\n }\n\n /**\n * Get bandwidth estimate from player stats\n */\n private async getBandwidthEstimate(): Promise<number> {\n // Try to get bandwidth from player stats\n if (this.config.getBandwidthEstimate) {\n const estimate = await this.config.getBandwidthEstimate();\n if (estimate > 0) return estimate;\n }\n\n // Fallback: estimate from buffer growth (rough)\n const video = this.videoElement;\n if (!video || video.buffered.length === 0) return 0;\n\n // This is a rough fallback - prefer player-specific estimates\n return 0;\n }\n\n /**\n * Get smoothed bandwidth from history\n */\n private getSmoothedBandwidth(): number {\n if (this.bandwidthHistory.length === 0) return 0;\n if (this.bandwidthHistory.length < 3) {\n // Need at least 3 samples for reliable estimate\n return 0;\n }\n const sum = this.bandwidthHistory.reduce((a, b) => a + b, 0);\n return sum / this.bandwidthHistory.length;\n }\n\n /**\n * Get current bandwidth estimate (for external use)\n */\n getCurrentBandwidth(): number {\n return this.getSmoothedBandwidth();\n }\n\n /**\n * Setup resize observer for viewport-based quality selection\n */\n private setupResizeObserver(): void {\n const video = this.videoElement;\n if (!video) return;\n\n this.resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n this.handleResize(width, height);\n }\n });\n\n // Observe the video element's container\n const container = video.parentElement;\n if (container) {\n this.resizeObserver.observe(container);\n }\n\n // Initial resize handling\n const rect = video.getBoundingClientRect();\n this.handleResize(rect.width, rect.height);\n }\n\n /**\n * Handle viewport resize (ABR_resize mode)\n */\n private handleResize(width: number, height: number): void {\n if (this.options.mode !== \"resize\" && this.options.mode !== \"auto\") {\n return;\n }\n\n const qualities = this.config.getQualities();\n if (qualities.length === 0) return;\n\n // Find best quality for viewport size\n const targetWidth = Math.min(width * window.devicePixelRatio, this.options.maxResolution.width);\n const targetHeight = Math.min(\n height * window.devicePixelRatio,\n this.options.maxResolution.height\n );\n\n const bestQuality = this.findBestQualityForResolution(qualities, targetWidth, targetHeight);\n\n if (bestQuality && bestQuality.id !== this.currentQualityId) {\n this.log(`Resize ABR: ${width}x${height} -> selecting ${bestQuality.label}`);\n this.selectQuality(bestQuality.id);\n }\n }\n\n /**\n * Handle quality degradation (ABR_bitrate mode)\n *\n * Called by QualityMonitor when playback quality drops\n */\n handleQualityDegraded(quality: PlaybackQuality): void {\n if (this.options.mode !== \"bitrate\" && this.options.mode !== \"auto\") {\n return;\n }\n\n // D3: Downgrade should be fast (0ms default), but still respects configured cooldown\n const now = Date.now();\n if (now - this.lastDowngradeTime < ABRController.DOWNGRADE_COOLDOWN_MS) {\n return;\n }\n\n if (quality.score < this.options.downgradeThreshold) {\n const qualities = this.config.getQualities();\n const currentQuality = this.config.getCurrentQuality?.();\n\n if (currentQuality) {\n // Find a lower quality level\n const lowerQuality = this.findLowerQuality(qualities, currentQuality);\n\n if (lowerQuality) {\n this.log(`Bitrate ABR: score ${quality.score} -> downgrading to ${lowerQuality.label}`);\n this.lastDecision = \"downgrade\";\n this.lastDecisionTime = now;\n this.lastDowngradeTime = now;\n this.selectQuality(lowerQuality.id);\n }\n }\n }\n }\n\n /**\n * Handle quality improvement opportunity\n *\n * Called when conditions are good enough to try higher quality\n */\n handleQualityImproved(quality: PlaybackQuality): void {\n if (this.options.mode !== \"bitrate\" && this.options.mode !== \"auto\") {\n return;\n }\n\n // D3: Upgrade requires sustained stability (5s default) to prevent flapping\n const now = Date.now();\n if (now - this.lastUpgradeTime < ABRController.UPGRADE_COOLDOWN_MS) {\n return;\n }\n\n // Only upgrade if buffer is healthy and quality is good\n if (quality.score >= 90 && quality.bufferedAhead >= this.options.minBufferForUpgrade) {\n const qualities = this.config.getQualities();\n const currentQuality = this.config.getCurrentQuality?.();\n\n if (currentQuality) {\n // Find a higher quality level\n const higherQuality = this.findHigherQuality(qualities, currentQuality);\n\n if (higherQuality && this.isWithinConstraints(higherQuality)) {\n this.log(`Bitrate ABR: score ${quality.score} -> upgrading to ${higherQuality.label}`);\n this.lastDecision = \"upgrade\";\n this.lastDecisionTime = now;\n this.lastUpgradeTime = now;\n this.selectQuality(higherQuality.id);\n }\n }\n }\n }\n\n /**\n * Find best quality level for given resolution\n */\n private findBestQualityForResolution(\n qualities: QualityLevel[],\n targetWidth: number,\n targetHeight: number\n ): QualityLevel | null {\n // Filter out qualities that exceed constraints\n const validQualities = qualities.filter((q) => this.isWithinConstraints(q));\n\n if (validQualities.length === 0) return null;\n\n // Sort by resolution (ascending)\n const sorted = [...validQualities].sort((a, b) => {\n const aPixels = (a.width ?? 0) * (a.height ?? 0);\n const bPixels = (b.width ?? 0) * (b.height ?? 0);\n return aPixels - bPixels;\n });\n\n // Find smallest quality that is >= target resolution\n for (const q of sorted) {\n const qWidth = q.width ?? 0;\n const qHeight = q.height ?? 0;\n\n if (qWidth >= targetWidth && qHeight >= targetHeight) {\n return q;\n }\n }\n\n // If no quality is large enough, return the highest available\n return sorted[sorted.length - 1];\n }\n\n /**\n * Find a lower quality level\n */\n private findLowerQuality(qualities: QualityLevel[], current: QualityLevel): QualityLevel | null {\n const currentBitrate = current.bitrate ?? 0;\n\n // Sort by bitrate descending\n const sorted = [...qualities].sort((a, b) => (b.bitrate ?? 0) - (a.bitrate ?? 0));\n\n // Find next lower bitrate\n for (const q of sorted) {\n if ((q.bitrate ?? 0) < currentBitrate) {\n return q;\n }\n }\n\n return null;\n }\n\n /**\n * Find a higher quality level\n */\n private findHigherQuality(qualities: QualityLevel[], current: QualityLevel): QualityLevel | null {\n const currentBitrate = current.bitrate ?? 0;\n\n // Sort by bitrate ascending\n const sorted = [...qualities].sort((a, b) => (a.bitrate ?? 0) - (b.bitrate ?? 0));\n\n // Find next higher bitrate\n for (const q of sorted) {\n if ((q.bitrate ?? 0) > currentBitrate) {\n return q;\n }\n }\n\n return null;\n }\n\n /**\n * Check if quality is within configured constraints\n */\n private isWithinConstraints(quality: QualityLevel): boolean {\n const { maxResolution, maxBitrate } = this.options;\n\n if (quality.width && quality.width > maxResolution.width) return false;\n if (quality.height && quality.height > maxResolution.height) return false;\n if (quality.bitrate && quality.bitrate > maxBitrate) return false;\n\n return true;\n }\n\n /**\n * Select a quality level\n */\n private selectQuality(id: string | \"auto\"): void {\n this.currentQualityId = id;\n this.config.selectQuality(id);\n\n // Notify callbacks\n const qualities = this.config.getQualities();\n const selected = qualities.find((q) => q.id === id);\n if (selected) {\n this.qualityChangeCallbacks.forEach((cb) => cb(selected));\n }\n }\n\n /**\n * Register callback for quality changes\n */\n onQualityChange(callback: (level: QualityLevel) => void): () => void {\n this.qualityChangeCallbacks.push(callback);\n return () => {\n const idx = this.qualityChangeCallbacks.indexOf(callback);\n if (idx >= 0) {\n this.qualityChangeCallbacks.splice(idx, 1);\n }\n };\n }\n\n /**\n * Manually set quality (switches to manual mode temporarily)\n */\n setQuality(id: string | \"auto\"): void {\n this.selectQuality(id);\n }\n\n /**\n * Get current ABR mode\n */\n getMode(): ABRMode {\n return this.options.mode;\n }\n\n /**\n * Set ABR mode at runtime.\n * Restarts monitoring if video element is attached.\n */\n setMode(mode: ABRMode): void {\n if (this.options.mode === mode) return;\n\n this.options.mode = mode;\n this.log(`Mode changed to: ${mode}`);\n\n // Restart with new mode if we have a video element\n if (this.videoElement) {\n const video = this.videoElement;\n this.stop();\n this.start(video);\n }\n }\n\n /**\n * Update ABR options\n */\n updateOptions(options: Partial<ABROptions>): void {\n this.options = { ...this.options, ...options };\n }\n\n /**\n * Get last ABR decision\n */\n getLastDecision(): ABRDecision {\n return this.lastDecision;\n }\n\n /**\n * Debug logging\n */\n private log(message: string): void {\n if (this.debug) {\n console.debug(`[ABRController] ${message}`);\n }\n }\n}\n\nexport default ABRController;\n"],"names":["TimerManager"],"mappings":"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"}