@amazon/vinyl 1.2.0 → 1.2.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 (330) hide show
  1. package/dist/index.cjs +24 -6
  2. package/dist/index.cjs.map +2 -2
  3. package/dist/index.js +33 -13
  4. package/dist/index.js.map +3 -3
  5. package/dist/test/integ.es5.js +62 -62
  6. package/dist/test/integ.js +119 -6
  7. package/dist/test/integ.js.map +2 -2
  8. package/dist/types/current/ad/AdBreakInfo.d.ts +160 -0
  9. package/dist/types/current/ad/AdBreakInfo.d.ts.map +1 -0
  10. package/dist/types/current/ad/AdBreakInfo.js +5 -0
  11. package/dist/types/current/ad/AdController.d.ts +229 -0
  12. package/dist/types/current/ad/AdController.d.ts.map +1 -0
  13. package/dist/types/current/ad/AdController.js +19 -0
  14. package/dist/types/current/ad/AdControllerImpl.d.ts +162 -0
  15. package/dist/types/current/ad/AdControllerImpl.d.ts.map +1 -0
  16. package/dist/types/current/ad/AdControllerImpl.js +741 -0
  17. package/dist/types/current/ad/AdError.d.ts +6 -0
  18. package/dist/types/current/ad/AdError.d.ts.map +1 -0
  19. package/dist/types/current/ad/AdError.js +14 -0
  20. package/dist/types/current/ad/AdsProvider.d.ts +28 -0
  21. package/dist/types/current/ad/AdsProvider.d.ts.map +1 -0
  22. package/dist/types/current/ad/AdsProvider.js +5 -0
  23. package/dist/types/current/ad/defaultAdLoadOptionsResolver.d.ts +12 -0
  24. package/dist/types/current/ad/defaultAdLoadOptionsResolver.d.ts.map +1 -0
  25. package/dist/types/current/ad/defaultAdLoadOptionsResolver.js +26 -0
  26. package/dist/types/current/ad/discoverHlsInterstitials.d.ts +22 -0
  27. package/dist/types/current/ad/discoverHlsInterstitials.d.ts.map +1 -0
  28. package/dist/types/current/ad/discoverHlsInterstitials.js +248 -0
  29. package/dist/types/current/drm/DrmControllerImpl.d.ts +6 -0
  30. package/dist/types/current/drm/DrmControllerImpl.d.ts.map +1 -1
  31. package/dist/types/current/drm/DrmControllerImpl.js +23 -1
  32. package/dist/types/current/playback/PlaybackControllerImpl.d.ts +1 -1
  33. package/dist/types/current/playback/createStallDetector.d.ts +43 -0
  34. package/dist/types/current/playback/createStallDetector.d.ts.map +1 -0
  35. package/dist/types/current/playback/createStallDetector.js +101 -0
  36. package/dist/types/current/playback/createStallMonitor.d.ts +45 -0
  37. package/dist/types/current/playback/createStallMonitor.d.ts.map +1 -0
  38. package/dist/types/current/playback/createStallMonitor.js +99 -0
  39. package/dist/types/current/streaming/AudioOptions.d.ts +66 -0
  40. package/dist/types/current/streaming/AudioOptions.d.ts.map +1 -0
  41. package/dist/types/current/streaming/AudioOptions.js +19 -0
  42. package/dist/types/current/streaming/LoadMetric.d.ts +72 -0
  43. package/dist/types/current/streaming/LoadMetric.d.ts.map +1 -0
  44. package/dist/types/current/streaming/LoadMetric.js +5 -0
  45. package/dist/types/current/streaming/ManifestControllerImpl.d.ts +43 -0
  46. package/dist/types/current/streaming/ManifestControllerImpl.d.ts.map +1 -0
  47. package/dist/types/current/streaming/ManifestControllerImpl.js +104 -0
  48. package/dist/types/current/streaming/buffering/codecDenylist.d.ts +23 -0
  49. package/dist/types/current/streaming/buffering/codecDenylist.d.ts.map +1 -0
  50. package/dist/types/current/streaming/buffering/codecDenylist.js +62 -0
  51. package/dist/types/current/streaming/createAllowedContentTypesValue.d.ts +30 -0
  52. package/dist/types/current/streaming/createAllowedContentTypesValue.d.ts.map +1 -0
  53. package/dist/types/current/streaming/createAllowedContentTypesValue.js +43 -0
  54. package/dist/types/current/streaming/createTimelineContentTypesValue.d.ts +21 -0
  55. package/dist/types/current/streaming/createTimelineContentTypesValue.d.ts.map +1 -0
  56. package/dist/types/current/streaming/createTimelineContentTypesValue.js +25 -0
  57. package/dist/types/current/streaming/mediaTimelineAccessibilityFilter.d.ts +35 -0
  58. package/dist/types/current/streaming/mediaTimelineAccessibilityFilter.d.ts.map +1 -0
  59. package/dist/types/current/streaming/mediaTimelineAccessibilityFilter.js +75 -0
  60. package/dist/types/current/text/HtmlTextTrackRenderer.d.ts +60 -0
  61. package/dist/types/current/text/HtmlTextTrackRenderer.d.ts.map +1 -0
  62. package/dist/types/current/text/HtmlTextTrackRenderer.js +231 -0
  63. package/dist/types/current/text/SidecarTextTrackController.d.ts +103 -0
  64. package/dist/types/current/text/SidecarTextTrackController.d.ts.map +1 -0
  65. package/dist/types/current/text/SidecarTextTrackController.js +250 -0
  66. package/dist/types/current/text/SidecarTextTrackLoader.d.ts +65 -0
  67. package/dist/types/current/text/SidecarTextTrackLoader.d.ts.map +1 -0
  68. package/dist/types/current/text/SidecarTextTrackLoader.js +150 -0
  69. package/dist/types/current/text/TextTrack.d.ts +179 -0
  70. package/dist/types/current/text/TextTrack.d.ts.map +1 -0
  71. package/dist/types/current/text/TextTrack.js +29 -0
  72. package/dist/types/current/text/TextTrackRenderer.d.ts +24 -0
  73. package/dist/types/current/text/TextTrackRenderer.d.ts.map +1 -0
  74. package/dist/types/current/text/TextTrackRenderer.js +5 -0
  75. package/dist/types/current/text/VttCueStyle.d.ts +41 -0
  76. package/dist/types/current/text/VttCueStyle.d.ts.map +1 -0
  77. package/dist/types/current/text/VttCueStyle.js +45 -0
  78. package/dist/types/current/text/discoverDashTextTracks.d.ts +24 -0
  79. package/dist/types/current/text/discoverDashTextTracks.d.ts.map +1 -0
  80. package/dist/types/current/text/discoverDashTextTracks.js +110 -0
  81. package/dist/types/current/text/discoverHlsTextTracks.d.ts +19 -0
  82. package/dist/types/current/text/discoverHlsTextTracks.d.ts.map +1 -0
  83. package/dist/types/current/text/discoverHlsTextTracks.js +49 -0
  84. package/dist/types/current/text/mediaTextTrackProvider.d.ts +34 -0
  85. package/dist/types/current/text/mediaTextTrackProvider.d.ts.map +1 -0
  86. package/dist/types/current/text/mediaTextTrackProvider.js +42 -0
  87. package/dist/types/current/text/parseWebVtt.d.ts +60 -0
  88. package/dist/types/current/text/parseWebVtt.d.ts.map +1 -0
  89. package/dist/types/current/text/parseWebVtt.js +249 -0
  90. package/dist/types/current/text/pickPreferredTextTrack.d.ts +15 -0
  91. package/dist/types/current/text/pickPreferredTextTrack.d.ts.map +1 -0
  92. package/dist/types/current/text/pickPreferredTextTrack.js +71 -0
  93. package/dist/types/current/track/SeekRange.d.ts +9 -0
  94. package/dist/types/current/track/SeekRange.d.ts.map +1 -0
  95. package/dist/types/current/track/SeekRange.js +5 -0
  96. package/dist/types/current/track/hls/HlsManifestData.d.ts +19 -0
  97. package/dist/types/current/track/hls/HlsManifestData.d.ts.map +1 -0
  98. package/dist/types/current/track/hls/HlsManifestData.js +5 -0
  99. package/dist/types/current/track/hls/createHlsManifestProvider.d.ts +6 -0
  100. package/dist/types/current/track/hls/createHlsManifestProvider.d.ts.map +1 -0
  101. package/dist/types/current/track/hls/createHlsManifestProvider.js +9 -0
  102. package/dist/types/current/track/inferLoadOptionsFromUri.d.ts +15 -0
  103. package/dist/types/current/track/inferLoadOptionsFromUri.d.ts.map +1 -0
  104. package/dist/types/current/track/inferLoadOptionsFromUri.js +55 -0
  105. package/dist/types/current/track/mse/MseTrack.d.ts +0 -1
  106. package/dist/types/current/track/mse/MseTrack.d.ts.map +1 -1
  107. package/dist/types/current/track/mse/MseTrack.js +4 -5
  108. package/dist/types/current/tsconfig.tsbuildinfo +1 -1
  109. package/dist/types/current/util/media/codecOverrides.d.ts +33 -0
  110. package/dist/types/current/util/media/codecOverrides.d.ts.map +1 -0
  111. package/dist/types/current/util/media/codecOverrides.js +37 -0
  112. package/dist/types/current/util/media/codecSupport.d.ts +6 -0
  113. package/dist/types/current/util/media/codecSupport.d.ts.map +1 -0
  114. package/dist/types/current/util/media/codecSupport.js +17 -0
  115. package/dist/types/current/util/media/mimeType.d.ts +8 -0
  116. package/dist/types/current/util/media/mimeType.d.ts.map +1 -0
  117. package/dist/types/current/util/media/mimeType.js +13 -0
  118. package/dist/types/ts3.7/ad/AdBreakInfo.d.ts +160 -0
  119. package/dist/types/ts3.7/ad/AdController.d.ts +243 -0
  120. package/dist/types/ts3.7/ad/AdControllerImpl.d.ts +162 -0
  121. package/dist/types/ts3.7/ad/AdError.d.ts +6 -0
  122. package/dist/types/ts3.7/ad/AdsProvider.d.ts +28 -0
  123. package/dist/types/ts3.7/ad/defaultAdLoadOptionsResolver.d.ts +12 -0
  124. package/dist/types/ts3.7/ad/discoverHlsInterstitials.d.ts +22 -0
  125. package/dist/types/ts3.7/drm/DrmControllerImpl.d.ts +6 -0
  126. package/dist/types/ts3.7/playback/PlaybackControllerImpl.d.ts +1 -1
  127. package/dist/types/ts3.7/playback/createStallDetector.d.ts +43 -0
  128. package/dist/types/ts3.7/playback/createStallMonitor.d.ts +45 -0
  129. package/dist/types/ts3.7/streaming/AudioOptions.d.ts +66 -0
  130. package/dist/types/ts3.7/streaming/LoadMetric.d.ts +72 -0
  131. package/dist/types/ts3.7/streaming/ManifestControllerImpl.d.ts +40 -0
  132. package/dist/types/ts3.7/streaming/buffering/codecDenylist.d.ts +23 -0
  133. package/dist/types/ts3.7/streaming/createAllowedContentTypesValue.d.ts +30 -0
  134. package/dist/types/ts3.7/streaming/createTimelineContentTypesValue.d.ts +21 -0
  135. package/dist/types/ts3.7/streaming/mediaTimelineAccessibilityFilter.d.ts +35 -0
  136. package/dist/types/ts3.7/text/HtmlTextTrackRenderer.d.ts +60 -0
  137. package/dist/types/ts3.7/text/SidecarTextTrackController.d.ts +103 -0
  138. package/dist/types/ts3.7/text/SidecarTextTrackLoader.d.ts +65 -0
  139. package/dist/types/ts3.7/text/TextTrack.d.ts +183 -0
  140. package/dist/types/ts3.7/text/TextTrackRenderer.d.ts +24 -0
  141. package/dist/types/ts3.7/text/VttCueStyle.d.ts +41 -0
  142. package/dist/types/ts3.7/text/discoverDashTextTracks.d.ts +24 -0
  143. package/dist/types/ts3.7/text/discoverHlsTextTracks.d.ts +19 -0
  144. package/dist/types/ts3.7/text/mediaTextTrackProvider.d.ts +34 -0
  145. package/dist/types/ts3.7/text/parseWebVtt.d.ts +60 -0
  146. package/dist/types/ts3.7/text/pickPreferredTextTrack.d.ts +15 -0
  147. package/dist/types/ts3.7/track/SeekRange.d.ts +9 -0
  148. package/dist/types/ts3.7/track/hls/HlsManifestData.d.ts +19 -0
  149. package/dist/types/ts3.7/track/hls/createHlsManifestProvider.d.ts +6 -0
  150. package/dist/types/ts3.7/track/inferLoadOptionsFromUri.d.ts +15 -0
  151. package/dist/types/ts3.7/track/mse/MseTrack.d.ts +0 -1
  152. package/dist/types/ts3.7/util/media/codecOverrides.d.ts +33 -0
  153. package/dist/types/ts3.7/util/media/codecSupport.d.ts +6 -0
  154. package/dist/types/ts3.7/util/media/mimeType.d.ts +8 -0
  155. package/dist/types/ts4.1/ad/AdBreakInfo.d.ts +160 -0
  156. package/dist/types/ts4.1/ad/AdController.d.ts +243 -0
  157. package/dist/types/ts4.1/ad/AdControllerImpl.d.ts +162 -0
  158. package/dist/types/ts4.1/ad/AdError.d.ts +6 -0
  159. package/dist/types/ts4.1/ad/AdsProvider.d.ts +28 -0
  160. package/dist/types/ts4.1/ad/defaultAdLoadOptionsResolver.d.ts +12 -0
  161. package/dist/types/ts4.1/ad/discoverHlsInterstitials.d.ts +22 -0
  162. package/dist/types/ts4.1/drm/DrmControllerImpl.d.ts +6 -0
  163. package/dist/types/ts4.1/playback/PlaybackControllerImpl.d.ts +1 -1
  164. package/dist/types/ts4.1/playback/createStallDetector.d.ts +43 -0
  165. package/dist/types/ts4.1/playback/createStallMonitor.d.ts +45 -0
  166. package/dist/types/ts4.1/streaming/AudioOptions.d.ts +66 -0
  167. package/dist/types/ts4.1/streaming/LoadMetric.d.ts +72 -0
  168. package/dist/types/ts4.1/streaming/ManifestControllerImpl.d.ts +40 -0
  169. package/dist/types/ts4.1/streaming/buffering/codecDenylist.d.ts +23 -0
  170. package/dist/types/ts4.1/streaming/createAllowedContentTypesValue.d.ts +30 -0
  171. package/dist/types/ts4.1/streaming/createTimelineContentTypesValue.d.ts +21 -0
  172. package/dist/types/ts4.1/streaming/mediaTimelineAccessibilityFilter.d.ts +35 -0
  173. package/dist/types/ts4.1/text/HtmlTextTrackRenderer.d.ts +60 -0
  174. package/dist/types/ts4.1/text/SidecarTextTrackController.d.ts +104 -0
  175. package/dist/types/ts4.1/text/SidecarTextTrackLoader.d.ts +65 -0
  176. package/dist/types/ts4.1/text/TextTrack.d.ts +183 -0
  177. package/dist/types/ts4.1/text/TextTrackRenderer.d.ts +24 -0
  178. package/dist/types/ts4.1/text/VttCueStyle.d.ts +41 -0
  179. package/dist/types/ts4.1/text/discoverDashTextTracks.d.ts +24 -0
  180. package/dist/types/ts4.1/text/discoverHlsTextTracks.d.ts +19 -0
  181. package/dist/types/ts4.1/text/mediaTextTrackProvider.d.ts +34 -0
  182. package/dist/types/ts4.1/text/parseWebVtt.d.ts +60 -0
  183. package/dist/types/ts4.1/text/pickPreferredTextTrack.d.ts +15 -0
  184. package/dist/types/ts4.1/track/SeekRange.d.ts +9 -0
  185. package/dist/types/ts4.1/track/hls/HlsManifestData.d.ts +19 -0
  186. package/dist/types/ts4.1/track/hls/createHlsManifestProvider.d.ts +6 -0
  187. package/dist/types/ts4.1/track/inferLoadOptionsFromUri.d.ts +15 -0
  188. package/dist/types/ts4.1/track/mse/MseTrack.d.ts +0 -1
  189. package/dist/types/ts4.1/util/media/codecOverrides.d.ts +33 -0
  190. package/dist/types/ts4.1/util/media/codecSupport.d.ts +6 -0
  191. package/dist/types/ts4.1/util/media/mimeType.d.ts +8 -0
  192. package/dist/types/ts4.7/ad/AdBreakInfo.d.ts +160 -0
  193. package/dist/types/ts4.7/ad/AdController.d.ts +243 -0
  194. package/dist/types/ts4.7/ad/AdControllerImpl.d.ts +162 -0
  195. package/dist/types/ts4.7/ad/AdError.d.ts +6 -0
  196. package/dist/types/ts4.7/ad/AdsProvider.d.ts +28 -0
  197. package/dist/types/ts4.7/ad/defaultAdLoadOptionsResolver.d.ts +12 -0
  198. package/dist/types/ts4.7/ad/discoverHlsInterstitials.d.ts +22 -0
  199. package/dist/types/ts4.7/drm/DrmControllerImpl.d.ts +6 -0
  200. package/dist/types/ts4.7/playback/PlaybackControllerImpl.d.ts +1 -1
  201. package/dist/types/ts4.7/playback/createStallDetector.d.ts +43 -0
  202. package/dist/types/ts4.7/playback/createStallMonitor.d.ts +45 -0
  203. package/dist/types/ts4.7/streaming/AudioOptions.d.ts +66 -0
  204. package/dist/types/ts4.7/streaming/LoadMetric.d.ts +72 -0
  205. package/dist/types/ts4.7/streaming/ManifestControllerImpl.d.ts +43 -0
  206. package/dist/types/ts4.7/streaming/buffering/codecDenylist.d.ts +23 -0
  207. package/dist/types/ts4.7/streaming/createAllowedContentTypesValue.d.ts +30 -0
  208. package/dist/types/ts4.7/streaming/createTimelineContentTypesValue.d.ts +21 -0
  209. package/dist/types/ts4.7/streaming/mediaTimelineAccessibilityFilter.d.ts +35 -0
  210. package/dist/types/ts4.7/text/HtmlTextTrackRenderer.d.ts +60 -0
  211. package/dist/types/ts4.7/text/SidecarTextTrackController.d.ts +103 -0
  212. package/dist/types/ts4.7/text/SidecarTextTrackLoader.d.ts +65 -0
  213. package/dist/types/ts4.7/text/TextTrack.d.ts +183 -0
  214. package/dist/types/ts4.7/text/TextTrackRenderer.d.ts +24 -0
  215. package/dist/types/ts4.7/text/VttCueStyle.d.ts +41 -0
  216. package/dist/types/ts4.7/text/discoverDashTextTracks.d.ts +24 -0
  217. package/dist/types/ts4.7/text/discoverHlsTextTracks.d.ts +19 -0
  218. package/dist/types/ts4.7/text/mediaTextTrackProvider.d.ts +34 -0
  219. package/dist/types/ts4.7/text/parseWebVtt.d.ts +60 -0
  220. package/dist/types/ts4.7/text/pickPreferredTextTrack.d.ts +15 -0
  221. package/dist/types/ts4.7/track/SeekRange.d.ts +9 -0
  222. package/dist/types/ts4.7/track/hls/HlsManifestData.d.ts +19 -0
  223. package/dist/types/ts4.7/track/hls/createHlsManifestProvider.d.ts +6 -0
  224. package/dist/types/ts4.7/track/inferLoadOptionsFromUri.d.ts +15 -0
  225. package/dist/types/ts4.7/track/mse/MseTrack.d.ts +0 -1
  226. package/dist/types/ts4.7/util/media/codecOverrides.d.ts +33 -0
  227. package/dist/types/ts4.7/util/media/codecSupport.d.ts +6 -0
  228. package/dist/types/ts4.7/util/media/mimeType.d.ts +8 -0
  229. package/dist/unit/types/current/ad/AdController.test.d.ts +2 -0
  230. package/dist/unit/types/current/ad/AdController.test.d.ts.map +1 -0
  231. package/dist/unit/types/current/ad/AdController.test.js +10 -0
  232. package/dist/unit/types/current/ad/AdControllerImpl.test.d.ts +2 -0
  233. package/dist/unit/types/current/ad/AdControllerImpl.test.d.ts.map +1 -0
  234. package/dist/unit/types/current/ad/AdControllerImpl.test.js +1654 -0
  235. package/dist/unit/types/current/ad/defaultAdLoadOptionsResolver.test.d.ts +2 -0
  236. package/dist/unit/types/current/ad/defaultAdLoadOptionsResolver.test.d.ts.map +1 -0
  237. package/dist/unit/types/current/ad/defaultAdLoadOptionsResolver.test.js +56 -0
  238. package/dist/unit/types/current/ad/discoverHlsInterstitials.test.d.ts +2 -0
  239. package/dist/unit/types/current/ad/discoverHlsInterstitials.test.d.ts.map +1 -0
  240. package/dist/unit/types/current/ad/discoverHlsInterstitials.test.js +757 -0
  241. package/dist/unit/types/current/drm/DrmControllerImpl.test.js +96 -2
  242. package/dist/unit/types/current/playback/createStallDetector.test.d.ts +2 -0
  243. package/dist/unit/types/current/playback/createStallDetector.test.d.ts.map +1 -0
  244. package/dist/unit/types/current/playback/createStallDetector.test.js +163 -0
  245. package/dist/unit/types/current/playback/createStallMonitor.test.d.ts +2 -0
  246. package/dist/unit/types/current/playback/createStallMonitor.test.d.ts.map +1 -0
  247. package/dist/unit/types/current/playback/createStallMonitor.test.js +163 -0
  248. package/dist/unit/types/current/streaming/ManifestControllerImpl.test.d.ts +2 -0
  249. package/dist/unit/types/current/streaming/ManifestControllerImpl.test.d.ts.map +1 -0
  250. package/dist/unit/types/current/streaming/ManifestControllerImpl.test.js +197 -0
  251. package/dist/unit/types/current/streaming/MseTrack.test.js +15 -0
  252. package/dist/unit/types/current/streaming/buffering/codecDenylist.test.d.ts +2 -0
  253. package/dist/unit/types/current/streaming/buffering/codecDenylist.test.d.ts.map +1 -0
  254. package/dist/unit/types/current/streaming/buffering/codecDenylist.test.js +56 -0
  255. package/dist/unit/types/current/streaming/createAllowedContentTypesValue.test.d.ts +2 -0
  256. package/dist/unit/types/current/streaming/createAllowedContentTypesValue.test.d.ts.map +1 -0
  257. package/dist/unit/types/current/streaming/createAllowedContentTypesValue.test.js +77 -0
  258. package/dist/unit/types/current/streaming/createTimelineContentTypesValue.test.d.ts +2 -0
  259. package/dist/unit/types/current/streaming/createTimelineContentTypesValue.test.d.ts.map +1 -0
  260. package/dist/unit/types/current/streaming/createTimelineContentTypesValue.test.js +57 -0
  261. package/dist/unit/types/current/streaming/mediaTimelineAccessibilityFilter.test.d.ts +2 -0
  262. package/dist/unit/types/current/streaming/mediaTimelineAccessibilityFilter.test.d.ts.map +1 -0
  263. package/dist/unit/types/current/streaming/mediaTimelineAccessibilityFilter.test.js +99 -0
  264. package/dist/unit/types/current/text/HtmlTextTrackRenderer.test.d.ts +2 -0
  265. package/dist/unit/types/current/text/HtmlTextTrackRenderer.test.d.ts.map +1 -0
  266. package/dist/unit/types/current/text/HtmlTextTrackRenderer.test.js +231 -0
  267. package/dist/unit/types/current/text/SidecarTextTrackController.test.d.ts +2 -0
  268. package/dist/unit/types/current/text/SidecarTextTrackController.test.d.ts.map +1 -0
  269. package/dist/unit/types/current/text/SidecarTextTrackController.test.js +686 -0
  270. package/dist/unit/types/current/text/SidecarTextTrackLoader.test.d.ts +2 -0
  271. package/dist/unit/types/current/text/SidecarTextTrackLoader.test.d.ts.map +1 -0
  272. package/dist/unit/types/current/text/SidecarTextTrackLoader.test.js +365 -0
  273. package/dist/unit/types/current/text/TextTrack.test.d.ts +2 -0
  274. package/dist/unit/types/current/text/TextTrack.test.d.ts.map +1 -0
  275. package/dist/unit/types/current/text/TextTrack.test.js +12 -0
  276. package/dist/unit/types/current/text/VttCueStyle.test.d.ts +2 -0
  277. package/dist/unit/types/current/text/VttCueStyle.test.d.ts.map +1 -0
  278. package/dist/unit/types/current/text/VttCueStyle.test.js +76 -0
  279. package/dist/unit/types/current/text/discoverDashTextTracks.test.d.ts +2 -0
  280. package/dist/unit/types/current/text/discoverDashTextTracks.test.d.ts.map +1 -0
  281. package/dist/unit/types/current/text/discoverDashTextTracks.test.js +216 -0
  282. package/dist/unit/types/current/text/discoverHlsTextTracks.test.d.ts +2 -0
  283. package/dist/unit/types/current/text/discoverHlsTextTracks.test.d.ts.map +1 -0
  284. package/dist/unit/types/current/text/discoverHlsTextTracks.test.js +177 -0
  285. package/dist/unit/types/current/text/mediaTextTrackProvider.test.d.ts +2 -0
  286. package/dist/unit/types/current/text/mediaTextTrackProvider.test.d.ts.map +1 -0
  287. package/dist/unit/types/current/text/mediaTextTrackProvider.test.js +86 -0
  288. package/dist/unit/types/current/text/parseWebVtt.test.d.ts +2 -0
  289. package/dist/unit/types/current/text/parseWebVtt.test.d.ts.map +1 -0
  290. package/dist/unit/types/current/text/parseWebVtt.test.js +419 -0
  291. package/dist/unit/types/current/text/pickPreferredTextTrack.test.d.ts +2 -0
  292. package/dist/unit/types/current/text/pickPreferredTextTrack.test.d.ts.map +1 -0
  293. package/dist/unit/types/current/text/pickPreferredTextTrack.test.js +78 -0
  294. package/dist/unit/types/current/track/inferLoadOptionsFromUri.test.d.ts +2 -0
  295. package/dist/unit/types/current/track/inferLoadOptionsFromUri.test.d.ts.map +1 -0
  296. package/dist/unit/types/current/track/inferLoadOptionsFromUri.test.js +165 -0
  297. package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -1
  298. package/dist/unit/types/current/util/media/codecOverrides.test.d.ts +2 -0
  299. package/dist/unit/types/current/util/media/codecOverrides.test.d.ts.map +1 -0
  300. package/dist/unit/types/current/util/media/codecOverrides.test.js +42 -0
  301. package/dist/unit/types/current/util/media/codecSupport.test.d.ts +2 -0
  302. package/dist/unit/types/current/util/media/codecSupport.test.d.ts.map +1 -0
  303. package/dist/unit/types/current/util/media/codecSupport.test.js +26 -0
  304. package/dist/unit/types/current/util/media/mimeType.test.d.ts +2 -0
  305. package/dist/unit/types/current/util/media/mimeType.test.d.ts.map +1 -0
  306. package/dist/unit/types/current/util/media/mimeType.test.js +22 -0
  307. package/dist/unit/types/current/vinyl/VinylPlayerAdBreaks.test.d.ts +2 -0
  308. package/dist/unit/types/current/vinyl/VinylPlayerAdBreaks.test.d.ts.map +1 -0
  309. package/dist/unit/types/current/vinyl/VinylPlayerAdBreaks.test.js +142 -0
  310. package/dist/unit/types/current/vinyl/VinylPlayerTextTracks.test.d.ts +2 -0
  311. package/dist/unit/types/current/vinyl/VinylPlayerTextTracks.test.d.ts.map +1 -0
  312. package/dist/unit/types/current/vinyl/VinylPlayerTextTracks.test.js +188 -0
  313. package/dist/vinylTestUtil/types/current/mock/ad/MockAdController.d.ts +15 -0
  314. package/dist/vinylTestUtil/types/current/mock/ad/MockAdController.d.ts.map +1 -0
  315. package/dist/vinylTestUtil/types/current/mock/ad/MockAdController.js +26 -0
  316. package/dist/vinylTestUtil/types/current/mock/dash/mockDashManifest.d.ts +84 -84
  317. package/dist/vinylTestUtil/types/current/mock/text/MockTextTrackController.d.ts +10 -0
  318. package/dist/vinylTestUtil/types/current/mock/text/MockTextTrackController.d.ts.map +1 -0
  319. package/dist/vinylTestUtil/types/current/mock/text/MockTextTrackController.js +14 -0
  320. package/dist/vinylTestUtil/types/current/tsconfig.tsbuildinfo +1 -1
  321. package/dist/vinylTestUtil/types/ts3.7/mock/ad/MockAdController.d.ts +15 -0
  322. package/dist/vinylTestUtil/types/ts3.7/mock/dash/mockDashManifest.d.ts +84 -84
  323. package/dist/vinylTestUtil/types/ts3.7/mock/text/MockTextTrackController.d.ts +10 -0
  324. package/dist/vinylTestUtil/types/ts4.1/mock/ad/MockAdController.d.ts +15 -0
  325. package/dist/vinylTestUtil/types/ts4.1/mock/dash/mockDashManifest.d.ts +84 -84
  326. package/dist/vinylTestUtil/types/ts4.1/mock/text/MockTextTrackController.d.ts +10 -0
  327. package/dist/vinylTestUtil/types/ts4.7/mock/ad/MockAdController.d.ts +15 -0
  328. package/dist/vinylTestUtil/types/ts4.7/mock/dash/mockDashManifest.d.ts +84 -84
  329. package/dist/vinylTestUtil/types/ts4.7/mock/text/MockTextTrackController.d.ts +10 -0
  330. package/package.json +10 -11
@@ -0,0 +1,741 @@
1
+ /*
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { createDisposer, createLogPrefix, EventHostImpl, getElementOrDefault, lerp, logDebug, logError, logVerbose, memoize, noop, resolveValueProvider, roundToNearest, sleep, sortedInsertionIndex, } from '@amazon/vinyl-util';
6
+ import { AdError } from './AdError';
7
+ /**
8
+ * The % playhead start tolerance for playback progress when emitting ad progress events.
9
+ */
10
+ export const AD_START_TOLERANCE = 0.05;
11
+ /**
12
+ * When a break's X-PLAYOUT-LIMIT budget is reached, an ad whose real media end is
13
+ * within this many seconds is allowed to finish on its own `ended` rather than
14
+ * being cut. The limit is a coarse, often whole-second budget while the media's
15
+ * true length is fractional, so without this grace an ad effectively as long as
16
+ * its budget would be clipped a fraction short. The tolerance is measured against
17
+ * the playback-reported (media) duration, not the ad's declared duration.
18
+ */
19
+ export const PLAYOUT_LIMIT_TOLERANCE = 1;
20
+ export const defaultAdControllerImplOptions = {
21
+ adLoadTimeout: 15,
22
+ preloadAheadTime: 10,
23
+ };
24
+ /**
25
+ * Provider-agnostic {@link AdController}. Holds the discovered ad breaks and
26
+ * derives enter/exit region events from playhead time updates.
27
+ *
28
+ * This controller is the *model* for ad playback: it knows which breaks exist,
29
+ * which break contains the playhead, and which ad within that break is current.
30
+ * It does NOT create, preload, or activate any tracks — that is the
31
+ * responsibility of the {@link TrackController}.
32
+ *
33
+ * A break is considered active while `startTime <= currentTime < endTime`,
34
+ * where `endTime` is `startTime + duration`. Breaks whose duration is unknown
35
+ * (null) or breaks which restrict `jump` will become active at
36
+ * `currentTime > startTime`
37
+ *
38
+ * This class contains no HLS- or DASH-specific logic; discovery code maps its
39
+ * protocol's signals to {@link AdBreakInfo} exposed by an
40
+ * {@link AdsProvider.getAds}, which this controller reads once the provider is
41
+ * set via {@link AdController.setAdsProvider} (and re-reads on `adsChange`).
42
+ */
43
+ export class AdControllerImpl extends EventHostImpl {
44
+ deps;
45
+ get [Symbol.toStringTag]() {
46
+ return 'AdControllerImpl';
47
+ }
48
+ options;
49
+ _trackAds = null;
50
+ adsProviderSub = null;
51
+ adsProvider = null;
52
+ // The start times of the midroll ads, used for fast midroll break find
53
+ midrollAds = [];
54
+ // Midroll and postroll breaks, sorted by start time — the breaks eligible
55
+ // for the ahead-of-time `adPreload` signal (prerolls are preloaded up front).
56
+ preloadableBreaks = [];
57
+ // Breaks for which `adPreload` has already been emitted on the current
58
+ // approach; cleared on content change and when a break is re-armed by a
59
+ // seek back, so a re-approached break preloads again.
60
+ preloadedBreakIds = new Set();
61
+ lastPlaybackTime = 0;
62
+ pendingAdBreaks = [];
63
+ // Breaks permanently suppressed for this presentation (play-once breaks and
64
+ // prerolls). Cleared only on a content change (clearCompletedAds).
65
+ completeAdBreakIds = new Set();
66
+ // Replayable (non-play-once) midroll breaks that have played and are "spent"
67
+ // until the playhead moves back before their start, at which point they are
68
+ // re-armed and replay on the next forward crossing.
69
+ spentBreakIds = new Set();
70
+ disposer = createDisposer();
71
+ adBreakState = null;
72
+ loadingNext = false;
73
+ constructor(deps, options) {
74
+ super();
75
+ this.deps = deps;
76
+ this.options = { ...defaultAdControllerImplOptions, ...options };
77
+ const { add } = this.disposer;
78
+ const { playbackController } = this.deps;
79
+ add(playbackController.on('playing', () => {
80
+ if (this.adState) {
81
+ const adState = this.adState;
82
+ if (!adState.started) {
83
+ // The ad has started playing, initialize the state.
84
+ adState.started = true;
85
+ adState.timeStart = playbackController.currentTime;
86
+ adState.playbackRateAvg =
87
+ playbackController.playbackRate;
88
+ adState.dataPoints = 1;
89
+ }
90
+ this.dispatch('adPlaying', {
91
+ adBreak: adState.parentBreak.adBreak,
92
+ ad: adState.ad,
93
+ index: adState.index,
94
+ totalAds: adState.totalAds,
95
+ });
96
+ }
97
+ }));
98
+ add(playbackController.on('seeked', (event) => {
99
+ if (this.adState) {
100
+ this.adState.timeStart = playbackController.currentTime;
101
+ return;
102
+ }
103
+ // A genuine seek back before a break re-arms it: a spent
104
+ // (replayable) break fires again on the next forward crossing,
105
+ // and its preload signal re-arms so it warms again on approach.
106
+ if (event.reason !== 'seeked')
107
+ return;
108
+ const time = playbackController.currentTime;
109
+ for (const adBreak of this.preloadableBreaks) {
110
+ if (time < adBreak.startTime) {
111
+ const key = adBreakKey(adBreak);
112
+ this.spentBreakIds.delete(key);
113
+ this.preloadedBreakIds.delete(key);
114
+ }
115
+ }
116
+ }));
117
+ add(playbackController.on('timeUpdate', this.onTimeUpdate));
118
+ add(playbackController.on('ended', () => {
119
+ if (this.adState)
120
+ this.endAd(this.adState);
121
+ }));
122
+ }
123
+ clearCompletedAds() {
124
+ this.completeAdBreakIds.clear();
125
+ this.spentBreakIds.clear();
126
+ this.preloadedBreakIds.clear();
127
+ }
128
+ isBreakSuppressed(adBreak) {
129
+ const key = adBreakKey(adBreak);
130
+ return this.completeAdBreakIds.has(key) || this.spentBreakIds.has(key);
131
+ }
132
+ /** The media-time the current ad has actually played, or 0 if not playing. */
133
+ adElapsed() {
134
+ const adState = this.adState;
135
+ return adState?.started
136
+ ? Math.max(0, this.deps.playbackController.currentTime - adState.timeStart)
137
+ : 0;
138
+ }
139
+ /**
140
+ * Computes whether the current ad may be skipped and, when not yet, how many
141
+ * seconds remain until it can. A `skip` restriction blocks it outright;
142
+ * otherwise a resolved skip window gates it by the elapsed break playout, and
143
+ * with no window the ad is freely skippable.
144
+ */
145
+ async resolveSkipState(adBreakState, breakPlayed) {
146
+ const { adBreak } = adBreakState;
147
+ if (adBreak.restrict.skip === true) {
148
+ return { canSkip: false, skipIn: null };
149
+ }
150
+ const skipControl = await resolveValueProvider(adBreak.skipControl).catch((_v) => null);
151
+ if (!skipControl) {
152
+ return { canSkip: true, skipIn: null };
153
+ }
154
+ if (breakPlayed < skipControl.offset) {
155
+ return { canSkip: false, skipIn: skipControl.offset - breakPlayed };
156
+ }
157
+ const end = skipControl.duration != null
158
+ ? skipControl.offset + skipControl.duration
159
+ : Infinity;
160
+ return { canSkip: breakPlayed < end, skipIn: null };
161
+ }
162
+ get currentTrackAds() {
163
+ return this._trackAds;
164
+ }
165
+ setTrackAds(value) {
166
+ const previous = this._trackAds;
167
+ const current = value ?? null;
168
+ this._trackAds = current;
169
+ this.midrollAds = (value?.adBreaks ?? []).filter((adBreak) => adBreak.placement === 'midroll');
170
+ // Midroll + postroll breaks are eligible for the ahead-of-time preload
171
+ // signal. adBreaks are already sorted by start time, so this stays sorted.
172
+ this.preloadableBreaks = (value?.adBreaks ?? []).filter((adBreak) => adBreak.placement !== 'preroll');
173
+ logDebug(this, 'setTrackAds', value);
174
+ this.dispatch('currentTrackAdsChange', {
175
+ previous,
176
+ current,
177
+ });
178
+ }
179
+ /**
180
+ * Returns a function that returns true if the ads provider has changed
181
+ * since the callback was created.
182
+ */
183
+ providerInterrupted() {
184
+ const provider = this.adsProvider;
185
+ return () => this.disposed || provider !== this.adsProvider;
186
+ }
187
+ setAdsProvider(provider) {
188
+ if (this.adsProvider === provider)
189
+ return;
190
+ this.pendingAdBreaks = [];
191
+ this.completeAdBreak(this.adBreakState, 'contentChange');
192
+ this.adsProviderSub?.();
193
+ const { add, dispose } = createDisposer();
194
+ this.adsProviderSub = dispose;
195
+ this.adsProvider = provider;
196
+ const interrupted = this.providerInterrupted();
197
+ this.clearCompletedAds();
198
+ this.setTrackAds(null);
199
+ if (!provider)
200
+ return;
201
+ const refreshAds = () => {
202
+ provider
203
+ .getAds()
204
+ .then((ads) => {
205
+ if (interrupted())
206
+ return;
207
+ this.setTrackAds(ads);
208
+ })
209
+ .catch((error) => {
210
+ // Ad discovery failed for the provider. There is no active
211
+ // break to surface an adError against, so log it rather
212
+ // than routing through failAd (which would no-op with no
213
+ // active ad and swallow the failure silently).
214
+ if (interrupted())
215
+ return;
216
+ logError(this, 'ad discovery failed', error);
217
+ });
218
+ };
219
+ add(provider.on('adsChange', refreshAds));
220
+ refreshAds();
221
+ }
222
+ async enterPreroll() {
223
+ return this.enterRoll('preroll');
224
+ }
225
+ async enterPostroll() {
226
+ return this.enterRoll('postroll');
227
+ }
228
+ async enterRoll(placement) {
229
+ if (!this.adsProvider)
230
+ return null;
231
+ logVerbose(this, `checking for ${placement} ads`);
232
+ this.lastPlaybackTime = this.deps.playbackController.currentTime;
233
+ const interrupted = this.providerInterrupted();
234
+ return this.adsProvider
235
+ .getAds()
236
+ .then((ads) => {
237
+ if (interrupted()) {
238
+ logVerbose(this, `interrupted, no pending breaks set for ${placement}`);
239
+ return null;
240
+ }
241
+ this.setPendingBreaks(ads.adBreaks.filter((adBreak) => adBreak.placement === placement));
242
+ return this.currentAdBreak;
243
+ })
244
+ .catch(() => {
245
+ return null;
246
+ });
247
+ }
248
+ // True when we have an ads provider set. Callers gate off this AND their
249
+ // own "no ad break in progress" checks (currentAdBreak / pendingAdBreaks),
250
+ // so this is only about "a provider has committed", not track activation.
251
+ get hasProvider() {
252
+ return this.adsProvider != null;
253
+ }
254
+ skipAdBreak() {
255
+ const adBreakState = this.adBreakState;
256
+ if (!adBreakState) {
257
+ logDebug(this, 'skipAdBreak, no-op');
258
+ return;
259
+ }
260
+ logDebug(this, 'skipAdBreak, active break id:', adBreakState.adBreak.id);
261
+ this.completeAdBreak(adBreakState, 'skipped');
262
+ this.nextAdOrBreak();
263
+ }
264
+ /**
265
+ * Marks an ad break as completed (or 'spent' and replayable), emits an `adBreakCompleted` event.
266
+ */
267
+ completeAdBreak(adBreakState, reason) {
268
+ if (!adBreakState || adBreakState.completedReason) {
269
+ logDebug(this, 'completeAdBreak, no-op');
270
+ return;
271
+ }
272
+ const { adBreak } = adBreakState;
273
+ adBreakState.completedReason = reason;
274
+ const key = adBreakKey(adBreak);
275
+ // A non-once midroll ad may be replayed if the region is re-entered
276
+ // due to a back-seek.
277
+ if (adBreak.once ||
278
+ adBreak.placement === 'preroll' ||
279
+ adBreak.placement === 'postroll') {
280
+ this.completeAdBreakIds.add(key);
281
+ }
282
+ else {
283
+ // Non-once midroll
284
+ this.spentBreakIds.add(key);
285
+ }
286
+ // Interstitials play on a separate track, so the content timeline never
287
+ // advances during the break: content resumes at the cue point plus any
288
+ // explicit offset (default 0). max() keeps a forward seek from being
289
+ // rewound.
290
+ const resumePosition = Math.max(this.lastPlaybackTime, adBreak.startTime + (adBreak.resumeOffset ?? 0));
291
+ this.completeAd(adBreakState.adState, reason); // does nothing if no current ad
292
+ logDebug(this, `adBreakCompleted, active break id:${adBreak.id} reason:${reason} resumePosition:${resumePosition}`);
293
+ if (adBreakState === this.adBreakState) {
294
+ this.adBreakState = null;
295
+ }
296
+ this.dispatch('adBreakCompleted', { adBreak, resumePosition, reason });
297
+ }
298
+ get currentAdBreak() {
299
+ return this.adBreakState?.adBreak ?? null;
300
+ }
301
+ /**
302
+ * Marks an ad as completed and emits an `adCompleted` event.
303
+ */
304
+ completeAd(adState, reason) {
305
+ if (!adState || adState.completedReason)
306
+ return; // no-op
307
+ logDebug(this, `adCompleted id=${adState.ad.id} reason=${reason} index=${adState.index} totalAds=${adState.totalAds}`);
308
+ // Fold this ad's actual playout into the break total before clearing it.
309
+ adState.parentBreak.playoutElapsed += this.adElapsed();
310
+ adState.completedReason = reason;
311
+ this.dispatch('adCompleted', {
312
+ adBreak: adState.parentBreak.adBreak,
313
+ ad: adState.ad,
314
+ reason,
315
+ index: adState.index,
316
+ totalAds: adState.totalAds,
317
+ });
318
+ if (adState.index >= adState.totalAds - 1) {
319
+ this.completeAdBreak(adState.parentBreak, reason);
320
+ }
321
+ }
322
+ /**
323
+ * Polls the next pending ad and activates it.
324
+ * When there are no remaining ads, activates the next ad break (if any).
325
+ */
326
+ nextAdOrBreak() {
327
+ if (this.disposed || this.loadingNext)
328
+ return;
329
+ const adBreakState = this.adBreakState;
330
+ if (!adBreakState && !this.pendingAdBreaks.length) {
331
+ logDebug(this, 'nextAdOrBreak no-op');
332
+ return;
333
+ }
334
+ logDebug(this, 'nextAdOrBreak');
335
+ this.loadingNext = true;
336
+ const nextAd = async (adBreakState) => {
337
+ logVerbose(this, 'nextAd');
338
+ try {
339
+ const ad = await adBreakState.nextAd();
340
+ // The break may have been completed or swapped out (a content
341
+ // change, skip, or playout-limit) while its ads were resolving;
342
+ // don't start an ad for an abandoned break.
343
+ if (this.disposed)
344
+ return;
345
+ if (adBreakState.completedReason) {
346
+ // Whoever completed it could not advance (this call still
347
+ // holds `loadingNext`), and nothing else drains the pending
348
+ // list — a non-empty list blocks midroll ingress outright.
349
+ if (!this.adBreakState)
350
+ await nextBreak();
351
+ return;
352
+ }
353
+ if (ad) {
354
+ this.startAd(ad);
355
+ }
356
+ else {
357
+ // No remaining ads in this break
358
+ logVerbose(this, 'no remaining ads');
359
+ this.completeAdBreak(adBreakState, 'ended');
360
+ await nextBreak();
361
+ }
362
+ }
363
+ catch (error) {
364
+ if (this.disposed)
365
+ return;
366
+ // The ad list failed to resolve: surface the error, complete
367
+ // this break so content can resume, then advance to any pending
368
+ // break. Re-calling nextAdOrBreak() here would no-op (loadingNext
369
+ // is still held by this in-flight call) AND would leave the break
370
+ // stuck non-null, permanently blocking midroll ingress.
371
+ this.dispatch('adError', {
372
+ adBreak: adBreakState.adBreak,
373
+ currentAd: null,
374
+ error,
375
+ });
376
+ this.completeAdBreak(adBreakState, 'error');
377
+ await nextBreak();
378
+ }
379
+ };
380
+ const nextBreak = async () => {
381
+ logVerbose(this, 'nextBreak');
382
+ if (this.pendingAdBreaks.length) {
383
+ // There are pending breaks, take the next one and start its first ad.
384
+ const adBreak = this.pendingAdBreaks.shift();
385
+ this.adBreakState = createAdBreakState(adBreak);
386
+ logDebug(this, 'adBreakEntered', adBreak);
387
+ this.dispatch('adBreakEntered', { adBreak });
388
+ await nextAd(this.adBreakState);
389
+ }
390
+ else {
391
+ logDebug(this, 'no remaining breaks');
392
+ }
393
+ };
394
+ (async () => {
395
+ if (adBreakState) {
396
+ await nextAd(adBreakState);
397
+ }
398
+ else {
399
+ await nextBreak().catch(noop);
400
+ }
401
+ })()
402
+ .catch(noop)
403
+ .finally(() => {
404
+ this.loadingNext = false;
405
+ });
406
+ }
407
+ get currentAd() {
408
+ return this.adState?.ad ?? null;
409
+ }
410
+ get adState() {
411
+ return this.adBreakState?.adState ?? null;
412
+ }
413
+ startAd(adState) {
414
+ const { ad, index, totalAds } = adState;
415
+ logDebug(this, 'adEntered', adState.ad);
416
+ this.dispatch('adEntered', {
417
+ adBreak: adState.parentBreak.adBreak,
418
+ ad,
419
+ index,
420
+ totalAds,
421
+ });
422
+ this.emitTimeUpdate(adState).catch(noop);
423
+ sleep(this.options.adLoadTimeout)
424
+ .then(() => {
425
+ if (this.disposed)
426
+ return;
427
+ if (this.adState === adState && !adState.started) {
428
+ this.failAd(new AdError(`Ad failed to start after ${this.options.adLoadTimeout} seconds`));
429
+ }
430
+ })
431
+ .catch(noop);
432
+ }
433
+ /**
434
+ * Checks if the playhead has entered a time to activate a midroll ad.
435
+ */
436
+ onTimeUpdate = () => {
437
+ const adBreak = this.currentAdBreak;
438
+ const adState = this.adState;
439
+ if (adBreak) {
440
+ // Ad progress events
441
+ if (adState && adState.completedReason == null) {
442
+ this.emitAdProgressEvents(adState).catch(noop);
443
+ this.enforcePlayoutLimits(adState);
444
+ }
445
+ return;
446
+ }
447
+ const pC = this.deps.playbackController;
448
+ if (this.hasProvider && pC.playing && !this.pendingAdBreaks.length) {
449
+ // Not an ad playing, main content.
450
+ this.lastPlaybackTime = pC.currentTime;
451
+ this.checkAdPreload(pC.currentTime);
452
+ this.checkMidrollIngress();
453
+ }
454
+ };
455
+ /**
456
+ * Emits `adPreload` once for each midroll/postroll break the playhead is
457
+ * approaching — within (the break's {@link AdBreakInfo.resolutionTimeOffset}
458
+ * or, when absent, the `preloadAheadTime` option) seconds before its start —
459
+ * so a consumer can resolve and warm the break's assets before entry.
460
+ * Suppressed (played-once/spent) breaks are skipped.
461
+ */
462
+ checkAdPreload(time) {
463
+ for (const adBreak of this.preloadableBreaks) {
464
+ const key = adBreakKey(adBreak);
465
+ if (this.preloadedBreakIds.has(key))
466
+ continue;
467
+ if (this.isBreakSuppressed(adBreak))
468
+ continue;
469
+ const offset = adBreak.resolutionTimeOffset ?? this.options.preloadAheadTime;
470
+ // Only ahead of the break; at/after its start, ingress takes over.
471
+ if (time >= adBreak.startTime - offset &&
472
+ time < adBreak.startTime) {
473
+ this.preloadedBreakIds.add(key);
474
+ logDebug(this, 'adPreload', adBreak.id);
475
+ this.dispatch('adPreload', { adBreak });
476
+ }
477
+ }
478
+ }
479
+ /**
480
+ * Main content with ad breaks is playing, check if we have entered a midroll region.
481
+ */
482
+ checkMidrollIngress() {
483
+ const time = this.deps.playbackController.currentTime;
484
+ const midrolls = this.midrollAds;
485
+ // Upper bound: the first midroll whose startTime is strictly after the
486
+ // playhead. Every candidate break is at an index before it.
487
+ const upper = sortedInsertionIndex(midrolls, time, (time, ad) => time - ad.startTime);
488
+ const newPending = [];
489
+ // Scan every break at or before the playhead, ascending (timeline
490
+ // order), so tied start times and an earlier still-open break that
491
+ // contains the playhead (e.g. after a seek into or over it) are all
492
+ // considered — not just the single nearest preceding break.
493
+ for (let i = 0; i < upper; i++) {
494
+ const midroll = midrolls[i];
495
+ if (this.isBreakSuppressed(midroll))
496
+ continue;
497
+ const duration = midroll.duration == null || midroll.restrict.jump
498
+ ? Number.MAX_VALUE
499
+ : midroll.duration;
500
+ if (time < midroll.startTime + duration) {
501
+ newPending.push(midroll);
502
+ }
503
+ }
504
+ if (newPending.length) {
505
+ logVerbose(this, 'setting midrolls');
506
+ this.setPendingBreaks(newPending);
507
+ }
508
+ }
509
+ /**
510
+ * Emits events for `adTimeUpdate`, `adFirstQuartile`, `adMidpoint`, and
511
+ * `adThirdQuartile`.
512
+ * (Does not emit `adCompleted`)
513
+ */
514
+ async emitAdProgressEvents(adState) {
515
+ const pC = this.deps.playbackController;
516
+ await this.emitTimeUpdate(adState);
517
+ if (isFinite(pC.duration) && pC.duration > 0) {
518
+ // Take a running average of the playback rate. Applications can
519
+ // use this to detect tampering when emitting metrics.
520
+ adState.dataPoints++;
521
+ adState.playbackRateAvg = lerp(adState.playbackRateAvg, pC.playbackRate, 1 / adState.dataPoints);
522
+ // If the ad's duration is set, take the shorter of the ad duration
523
+ const currProgress = pC.currentTimePercent;
524
+ const progressStart = adState.timeStart / pC.duration;
525
+ if (!adState.quartile.first &&
526
+ currProgress > 0.25 &&
527
+ progressStart < AD_START_TOLERANCE) {
528
+ adState.quartile.first = true;
529
+ this.dispatch('adFirstQuartile', createAdProgressEvent(adState));
530
+ }
531
+ if (!adState.quartile.midpoint &&
532
+ currProgress > 0.5 &&
533
+ progressStart < 0.25 + AD_START_TOLERANCE) {
534
+ adState.quartile.midpoint = true;
535
+ this.dispatch('adMidpoint', createAdProgressEvent(adState));
536
+ }
537
+ if (!adState.quartile.third &&
538
+ currProgress > 0.75 &&
539
+ progressStart < 0.5 + AD_START_TOLERANCE) {
540
+ adState.quartile.third = true;
541
+ this.dispatch('adThirdQuartile', createAdProgressEvent(adState));
542
+ }
543
+ // adEnded is not on progress but on a call to `endAd()`.
544
+ }
545
+ }
546
+ async emitTimeUpdate(adState) {
547
+ const pC = this.deps.playbackController;
548
+ const { ad, parentBreak } = adState;
549
+ // Surface elapsed/remaining time for the ad and the break as a
550
+ // whole so applications don't derive it from the media duration.
551
+ const adPlayed = this.adElapsed();
552
+ const adBreak = parentBreak.adBreak;
553
+ const naturalAdTotal = ad.duration ?? (isFinite(pC.duration) ? pC.duration : null);
554
+ // The break's playout limit is a budget shared across all its ads, so
555
+ // the current ad can run no longer than the budget left after the ads
556
+ // that already played. Cap its reported total by that remainder —
557
+ // matching enforcePlayoutLimits, which cuts the ad (and break) off at
558
+ // exactly this point. Without the cap adTimeRemaining over-reports (the
559
+ // full asset duration) while the ad is actually stopped at the limit.
560
+ const limit = adBreak.playoutLimit;
561
+ const adTotal = limit != null
562
+ ? Math.min(naturalAdTotal ?? Infinity, Math.max(0, limit - parentBreak.playoutElapsed))
563
+ : naturalAdTotal;
564
+ const breakPlayed = parentBreak.playoutElapsed + adPlayed;
565
+ const breakTotal = limit ?? adBreak.duration;
566
+ const { canSkip, skipIn } = await this.resolveSkipState(parentBreak, breakPlayed);
567
+ this.dispatch('adTimeUpdate', {
568
+ adBreak: adState.parentBreak.adBreak,
569
+ ad,
570
+ index: adState.index,
571
+ totalAds: adState.totalAds,
572
+ adCurrentTime: adPlayed,
573
+ adTimeRemaining: adTotal != null ? Math.max(0, adTotal - adPlayed) : null,
574
+ breakCurrentTime: breakPlayed,
575
+ breakTimeRemaining: breakTotal != null
576
+ ? Math.max(0, breakTotal - breakPlayed)
577
+ : null,
578
+ canSkip,
579
+ skipIn,
580
+ });
581
+ }
582
+ /**
583
+ * Enforces the break-level playout limit (X-PLAYOUT-LIMIT): a budget shared
584
+ * across all of the break's ads. When cumulative playout reaches it, the
585
+ * whole break ends, dropping any ads that have not started.
586
+ *
587
+ * This is deliberately NOT a per-ad cap. Each ad asset is its own source and
588
+ * ends on its media `ended` (see the 'ended' handler), which is what advances
589
+ * a multi-ad break. Ending an ad at its declared per-ad DURATION instead would
590
+ * truncate the real asset whenever a packager under-declares it — e.g. rounds
591
+ * a 6.732s asset down to a whole-second 6 — cutting off the fractional tail.
592
+ */
593
+ enforcePlayoutLimits(adState) {
594
+ if (!adState.started)
595
+ return;
596
+ const { parentBreak } = adState;
597
+ // Enforce independent of a finite content duration so live ads with a
598
+ // declared playout limit are still bounded.
599
+ const limit = parentBreak.adBreak.playoutLimit;
600
+ if (limit == null)
601
+ return;
602
+ const pC = this.deps.playbackController;
603
+ const elapsed = Math.max(0, pC.currentTime - adState.timeStart);
604
+ if (parentBreak.playoutElapsed + elapsed < limit)
605
+ return;
606
+ // Budget reached — but if the current ad is essentially at its natural
607
+ // media end (within PLAYOUT_LIMIT_TOLERANCE of the playback-reported
608
+ // duration), let it finish on its own `ended` rather than clipping the
609
+ // tail. A known finite, positive duration is required; an unknown (0) or
610
+ // non-finite duration (e.g. live) enforces the limit strictly.
611
+ if (isFinite(pC.duration) &&
612
+ pC.duration > 0 &&
613
+ pC.duration - pC.currentTime <= PLAYOUT_LIMIT_TOLERANCE) {
614
+ return;
615
+ }
616
+ // The break's total playout limit is reached: end the whole break,
617
+ // dropping any ads that have not started.
618
+ parentBreak.clear();
619
+ this.endAd(adState);
620
+ }
621
+ setPendingBreaks(newPending) {
622
+ this.pendingAdBreaks = newPending.filter((adBreak) => !this.isBreakSuppressed(adBreak));
623
+ const n = this.pendingAdBreaks.length;
624
+ logDebug(this, `setPendingBreaks len=${n}, suppressed=${newPending.length - n}`);
625
+ this.nextAdOrBreak();
626
+ }
627
+ skipAd() {
628
+ this.completeAd(this.adState, 'skipped');
629
+ this.nextAdOrBreak();
630
+ }
631
+ failAd(error) {
632
+ const adState = this.adState;
633
+ if (adState) {
634
+ // Capture the failing ad before completeAd() clears it, so the
635
+ // adError event can distinguish an individual-ad failure from an
636
+ // ad-list load failure (currentAd == null).
637
+ this.completeAd(adState, 'error');
638
+ this.dispatch('adError', {
639
+ error,
640
+ adBreak: adState.parentBreak.adBreak,
641
+ currentAd: adState.ad,
642
+ });
643
+ }
644
+ this.nextAdOrBreak();
645
+ }
646
+ endAd(adState) {
647
+ this.completeAd(adState, 'ended');
648
+ this.dispatch('adEnded', createAdProgressEvent(adState));
649
+ this.nextAdOrBreak();
650
+ }
651
+ get disposed() {
652
+ return this.disposer.disposed;
653
+ }
654
+ /**
655
+ * Disposes this controller, removes all listeners.
656
+ */
657
+ dispose() {
658
+ super.dispose();
659
+ // Tear down the ads-provider subscription so a late adsChange can't
660
+ // re-run ad discovery (and log) after dispose.
661
+ this.adsProviderSub?.();
662
+ this.disposer.dispose();
663
+ // Detach any active break so currentAd/currentAdBreak read null after
664
+ // dispose, even if a break's ad list resolves late (startAd is already
665
+ // guarded by the disposed check, so no adEntered/adPlaying fires).
666
+ this.adBreakState = null;
667
+ }
668
+ }
669
+ function createAdProgressEvent(adState) {
670
+ return {
671
+ adBreak: adState.parentBreak.adBreak,
672
+ ad: adState.ad,
673
+ // Snapped to nearest 0.1 to avoid ~1.0
674
+ playbackRateAvg: roundToNearest(adState.playbackRateAvg, 0.1),
675
+ index: adState.index,
676
+ totalAds: adState.totalAds,
677
+ };
678
+ }
679
+ function createAdBreakState(adBreak) {
680
+ let _currentIndex = -1;
681
+ let _adState = null;
682
+ const logTarget = {
683
+ logPrefix: createLogPrefix('AdBreakState'),
684
+ };
685
+ const adBreakState = {
686
+ adBreak,
687
+ playoutElapsed: 0,
688
+ completedReason: null,
689
+ get adState() {
690
+ return _adState;
691
+ },
692
+ async nextAd() {
693
+ const ads = await getAds();
694
+ if (_currentIndex >= ads.length)
695
+ return null;
696
+ _adState = getElementOrDefault(ads, ++_currentIndex, null);
697
+ return _adState;
698
+ },
699
+ clear() {
700
+ _adState = null;
701
+ _currentIndex = Number.MAX_VALUE;
702
+ },
703
+ };
704
+ const getAds = memoize(() => {
705
+ logVerbose(logTarget, `requesting ads for break ${adBreak.placement} ${adBreak.id}`);
706
+ return resolveValueProvider(adBreak.ads).then((ads) => {
707
+ logVerbose(logTarget, 'ads resolved', ads);
708
+ return ads.map((adInfo, index) => {
709
+ return createAdState({
710
+ adBreakState: adBreakState,
711
+ ad: adInfo,
712
+ totalAds: ads.length,
713
+ index: index,
714
+ });
715
+ });
716
+ });
717
+ });
718
+ return adBreakState;
719
+ }
720
+ function createAdState({ adBreakState, ad, totalAds, index, }) {
721
+ return {
722
+ parentBreak: adBreakState,
723
+ ad,
724
+ index,
725
+ totalAds,
726
+ started: false,
727
+ timeStart: 0,
728
+ playbackRateAvg: 0,
729
+ dataPoints: 0,
730
+ quartile: {
731
+ first: false,
732
+ midpoint: false,
733
+ third: false,
734
+ },
735
+ completedReason: null,
736
+ };
737
+ }
738
+ /** Combines the placement and id of the break for unique reference by placement */
739
+ function adBreakKey(adBreak) {
740
+ return `${adBreak.placement}_${adBreak.id}`;
741
+ }