@amazon/vinyl 3.0.1 → 3.2.0

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 (268) hide show
  1. package/dist/index.cjs +1103 -1042
  2. package/dist/index.cjs.map +4 -4
  3. package/dist/index.js +810 -739
  4. package/dist/index.js.map +4 -4
  5. package/dist/test/benchmark.js.map +2 -2
  6. package/dist/test/integ.es5.js +394 -388
  7. package/dist/test/integ.js +2626 -2032
  8. package/dist/test/integ.js.map +4 -4
  9. package/dist/test/jasmine.css +50 -3
  10. package/dist/test/jasmineHtml.es5.js +195 -155
  11. package/dist/test/jasmineHtml.js +2938 -1833
  12. package/dist/test/jasmineHtml.js.map +3 -3
  13. package/dist/types/current/ad/AdControllerImpl.d.ts.map +1 -1
  14. package/dist/types/current/ad/AdControllerImpl.js +4 -1
  15. package/dist/types/current/ad/discoverHlsInterstitials.d.ts.map +1 -1
  16. package/dist/types/current/ad/discoverHlsInterstitials.js +2 -2
  17. package/dist/types/current/drm/DrmControllerImpl.d.ts +19 -1
  18. package/dist/types/current/drm/DrmControllerImpl.d.ts.map +1 -1
  19. package/dist/types/current/drm/DrmControllerImpl.js +101 -58
  20. package/dist/types/current/drm/licenseProvider/defaultLicenseProvider.d.ts.map +1 -1
  21. package/dist/types/current/drm/licenseProvider/defaultLicenseProvider.js +2 -2
  22. package/dist/types/current/index.d.ts +3 -6
  23. package/dist/types/current/index.d.ts.map +1 -1
  24. package/dist/types/current/index.js +3 -6
  25. package/dist/types/current/playback/PlaybackControllerImpl.d.ts +15 -0
  26. package/dist/types/current/playback/PlaybackControllerImpl.d.ts.map +1 -1
  27. package/dist/types/current/playback/PlaybackControllerImpl.js +100 -9
  28. package/dist/types/current/playback/ReadonlyPlaybackController.d.ts +27 -1
  29. package/dist/types/current/playback/ReadonlyPlaybackController.d.ts.map +1 -1
  30. package/dist/types/current/playback/ReadonlyPlaybackController.js +16 -0
  31. package/dist/types/current/playback/createStallDetector.d.ts +43 -0
  32. package/dist/types/current/playback/createStallDetector.d.ts.map +1 -0
  33. package/dist/types/current/playback/createStallDetector.js +101 -0
  34. package/dist/types/current/playback/createStallMonitor.d.ts +45 -0
  35. package/dist/types/current/playback/createStallMonitor.d.ts.map +1 -0
  36. package/dist/types/current/playback/createStallMonitor.js +94 -0
  37. package/dist/types/current/streaming/AudioOptions.d.ts +27 -0
  38. package/dist/types/current/streaming/AudioOptions.d.ts.map +1 -1
  39. package/dist/types/current/streaming/AudioOptions.js +5 -1
  40. package/dist/types/current/streaming/ContentStream.d.ts +0 -5
  41. package/dist/types/current/streaming/ContentStream.d.ts.map +1 -1
  42. package/dist/types/current/streaming/ContentStream.js +0 -4
  43. package/dist/types/current/streaming/LoadMetric.d.ts +15 -1
  44. package/dist/types/current/streaming/LoadMetric.d.ts.map +1 -1
  45. package/dist/types/current/streaming/StreamingEventMap.d.ts +1 -5
  46. package/dist/types/current/streaming/StreamingEventMap.d.ts.map +1 -1
  47. package/dist/types/current/streaming/StreamingEventMap.js +0 -1
  48. package/dist/types/current/streaming/buffering/BufferingController.d.ts +0 -11
  49. package/dist/types/current/streaming/buffering/BufferingController.d.ts.map +1 -1
  50. package/dist/types/current/streaming/buffering/BufferingController.js +0 -13
  51. package/dist/types/current/streaming/createDefaultMediaTimelineTransformer.d.ts.map +1 -1
  52. package/dist/types/current/streaming/createDefaultMediaTimelineTransformer.js +13 -4
  53. package/dist/types/current/streaming/mediaTimelineFilter.d.ts +4 -2
  54. package/dist/types/current/streaming/mediaTimelineFilter.d.ts.map +1 -1
  55. package/dist/types/current/streaming/mediaTimelineFilter.js +23 -8
  56. package/dist/types/current/text/SidecarTextTrackLoader.d.ts.map +1 -1
  57. package/dist/types/current/text/SidecarTextTrackLoader.js +4 -4
  58. package/dist/types/current/text/TextTrack.d.ts.map +1 -1
  59. package/dist/types/current/track/TrackController.d.ts.map +1 -1
  60. package/dist/types/current/track/TrackController.js +8 -2
  61. package/dist/types/current/track/createSegmentDataProvider.d.ts.map +1 -1
  62. package/dist/types/current/track/createSegmentDataProvider.js +6 -3
  63. package/dist/types/current/track/dash/DashMediaQualityMetadataResolver.d.ts +10 -6
  64. package/dist/types/current/track/dash/DashMediaQualityMetadataResolver.d.ts.map +1 -1
  65. package/dist/types/current/track/dash/DashMediaQualityMetadataResolver.js +13 -8
  66. package/dist/types/current/track/dash/createDashFactories.d.ts +1 -1
  67. package/dist/types/current/track/dash/timeline/DashRepresentationSegmentProvider.d.ts.map +1 -1
  68. package/dist/types/current/track/dash/timeline/DashRepresentationSegmentProvider.js +71 -3
  69. package/dist/types/current/track/dash/urlDashManifestProvider.js +2 -2
  70. package/dist/types/current/track/dash/util/mpd.d.ts +6 -0
  71. package/dist/types/current/track/dash/util/mpd.d.ts.map +1 -1
  72. package/dist/types/current/track/dash/util/mpd.js +24 -3
  73. package/dist/types/current/track/filters/resourceTypeFilter.d.ts +4 -0
  74. package/dist/types/current/track/filters/resourceTypeFilter.d.ts.map +1 -1
  75. package/dist/types/current/track/filters/resourceTypeFilter.js +4 -0
  76. package/dist/types/current/track/filters/sampleRateFilter.d.ts +25 -7
  77. package/dist/types/current/track/filters/sampleRateFilter.d.ts.map +1 -1
  78. package/dist/types/current/track/filters/sampleRateFilter.js +52 -24
  79. package/dist/types/current/track/hls/createHlsFactories.d.ts +1 -1
  80. package/dist/types/current/track/hls/createUrlHlsManifestProvider.d.ts.map +1 -1
  81. package/dist/types/current/track/hls/createUrlHlsManifestProvider.js +3 -3
  82. package/dist/types/current/track/mse/MseTrack.d.ts +0 -17
  83. package/dist/types/current/track/mse/MseTrack.d.ts.map +1 -1
  84. package/dist/types/current/track/mse/MseTrack.js +1 -45
  85. package/dist/types/current/tsconfig.tsbuildinfo +1 -1
  86. package/dist/types/current/util/media/mimeType.d.ts +8 -0
  87. package/dist/types/current/util/media/mimeType.d.ts.map +1 -0
  88. package/dist/types/current/util/media/mimeType.js +13 -0
  89. package/dist/types/current/vinyl/VinylPlayer.d.ts +5 -0
  90. package/dist/types/current/vinyl/VinylPlayer.d.ts.map +1 -1
  91. package/dist/types/current/vinyl/VinylPlayer.js +23 -1
  92. package/dist/types/current/vinyl/createVinylFactories.d.ts +7 -16
  93. package/dist/types/current/vinyl/createVinylFactories.d.ts.map +1 -1
  94. package/dist/types/current/vinyl/createVinylFactories.js +2 -12
  95. package/dist/types/ts3.7/drm/DrmControllerImpl.d.ts +19 -1
  96. package/dist/types/ts3.7/index.d.ts +3 -6
  97. package/dist/types/ts3.7/playback/PlaybackControllerImpl.d.ts +15 -0
  98. package/dist/types/ts3.7/playback/ReadonlyPlaybackController.d.ts +28 -0
  99. package/dist/types/ts3.7/playback/createStallDetector.d.ts +43 -0
  100. package/dist/types/ts3.7/playback/createStallMonitor.d.ts +45 -0
  101. package/dist/types/ts3.7/streaming/AudioOptions.d.ts +27 -0
  102. package/dist/types/ts3.7/streaming/ContentStream.d.ts +0 -5
  103. package/dist/types/ts3.7/streaming/LoadMetric.d.ts +15 -1
  104. package/dist/types/ts3.7/streaming/StreamingEventMap.d.ts +0 -5
  105. package/dist/types/ts3.7/streaming/buffering/BufferingController.d.ts +0 -11
  106. package/dist/types/ts3.7/streaming/mediaTimelineFilter.d.ts +4 -2
  107. package/dist/types/ts3.7/track/dash/DashMediaQualityMetadataResolver.d.ts +10 -6
  108. package/dist/types/ts3.7/track/dash/createDashFactories.d.ts +1 -1
  109. package/dist/types/ts3.7/track/dash/util/mpd.d.ts +6 -0
  110. package/dist/types/ts3.7/track/filters/resourceTypeFilter.d.ts +4 -0
  111. package/dist/types/ts3.7/track/filters/sampleRateFilter.d.ts +25 -7
  112. package/dist/types/ts3.7/track/hls/createHlsFactories.d.ts +1 -1
  113. package/dist/types/ts3.7/track/mse/MseTrack.d.ts +0 -17
  114. package/dist/types/ts3.7/util/media/mimeType.d.ts +8 -0
  115. package/dist/types/ts3.7/vinyl/VinylPlayer.d.ts +5 -0
  116. package/dist/types/ts3.7/vinyl/createVinylFactories.d.ts +7 -16
  117. package/dist/types/ts4.1/drm/DrmControllerImpl.d.ts +19 -1
  118. package/dist/types/ts4.1/index.d.ts +3 -6
  119. package/dist/types/ts4.1/playback/PlaybackControllerImpl.d.ts +15 -0
  120. package/dist/types/ts4.1/playback/ReadonlyPlaybackController.d.ts +28 -0
  121. package/dist/types/ts4.1/playback/createStallDetector.d.ts +43 -0
  122. package/dist/types/ts4.1/playback/createStallMonitor.d.ts +45 -0
  123. package/dist/types/ts4.1/streaming/AudioOptions.d.ts +27 -0
  124. package/dist/types/ts4.1/streaming/ContentStream.d.ts +0 -5
  125. package/dist/types/ts4.1/streaming/LoadMetric.d.ts +15 -1
  126. package/dist/types/ts4.1/streaming/StreamingEventMap.d.ts +0 -5
  127. package/dist/types/ts4.1/streaming/buffering/BufferingController.d.ts +0 -11
  128. package/dist/types/ts4.1/streaming/mediaTimelineFilter.d.ts +4 -2
  129. package/dist/types/ts4.1/track/dash/DashMediaQualityMetadataResolver.d.ts +10 -6
  130. package/dist/types/ts4.1/track/dash/createDashFactories.d.ts +1 -1
  131. package/dist/types/ts4.1/track/dash/util/mpd.d.ts +6 -0
  132. package/dist/types/ts4.1/track/filters/resourceTypeFilter.d.ts +4 -0
  133. package/dist/types/ts4.1/track/filters/sampleRateFilter.d.ts +25 -7
  134. package/dist/types/ts4.1/track/hls/createHlsFactories.d.ts +1 -1
  135. package/dist/types/ts4.1/track/mse/MseTrack.d.ts +0 -17
  136. package/dist/types/ts4.1/util/media/mimeType.d.ts +8 -0
  137. package/dist/types/ts4.1/vinyl/VinylPlayer.d.ts +5 -0
  138. package/dist/types/ts4.1/vinyl/createVinylFactories.d.ts +7 -16
  139. package/dist/types/ts4.7/drm/DrmControllerImpl.d.ts +19 -1
  140. package/dist/types/ts4.7/index.d.ts +3 -6
  141. package/dist/types/ts4.7/playback/PlaybackControllerImpl.d.ts +15 -0
  142. package/dist/types/ts4.7/playback/ReadonlyPlaybackController.d.ts +28 -0
  143. package/dist/types/ts4.7/playback/createStallDetector.d.ts +43 -0
  144. package/dist/types/ts4.7/playback/createStallMonitor.d.ts +45 -0
  145. package/dist/types/ts4.7/streaming/AudioOptions.d.ts +27 -0
  146. package/dist/types/ts4.7/streaming/ContentStream.d.ts +0 -5
  147. package/dist/types/ts4.7/streaming/LoadMetric.d.ts +15 -1
  148. package/dist/types/ts4.7/streaming/StreamingEventMap.d.ts +0 -5
  149. package/dist/types/ts4.7/streaming/buffering/BufferingController.d.ts +0 -11
  150. package/dist/types/ts4.7/streaming/mediaTimelineFilter.d.ts +4 -2
  151. package/dist/types/ts4.7/track/dash/DashMediaQualityMetadataResolver.d.ts +10 -6
  152. package/dist/types/ts4.7/track/dash/createDashFactories.d.ts +1 -1
  153. package/dist/types/ts4.7/track/dash/util/mpd.d.ts +6 -0
  154. package/dist/types/ts4.7/track/filters/resourceTypeFilter.d.ts +4 -0
  155. package/dist/types/ts4.7/track/filters/sampleRateFilter.d.ts +25 -7
  156. package/dist/types/ts4.7/track/hls/createHlsFactories.d.ts +1 -1
  157. package/dist/types/ts4.7/track/mse/MseTrack.d.ts +0 -17
  158. package/dist/types/ts4.7/util/media/mimeType.d.ts +8 -0
  159. package/dist/types/ts4.7/vinyl/VinylPlayer.d.ts +5 -0
  160. package/dist/types/ts4.7/vinyl/createVinylFactories.d.ts +7 -16
  161. package/dist/unit/types/current/ad/AdControllerImpl.test.js +27 -1
  162. package/dist/unit/types/current/drm/DrmControllerImpl.test.js +146 -9
  163. package/dist/unit/types/current/index.d.ts +3 -4
  164. package/dist/unit/types/current/index.d.ts.map +1 -1
  165. package/dist/unit/types/current/index.js +3 -4
  166. package/dist/unit/types/current/playback/PlaybackControllerImpl.test.js +165 -0
  167. package/dist/unit/types/current/playback/createStallDetector.test.d.ts +2 -0
  168. package/dist/unit/types/current/playback/createStallDetector.test.d.ts.map +1 -0
  169. package/dist/unit/types/current/playback/createStallDetector.test.js +163 -0
  170. package/dist/unit/types/current/playback/createStallMonitor.test.d.ts +2 -0
  171. package/dist/unit/types/current/playback/createStallMonitor.test.d.ts.map +1 -0
  172. package/dist/unit/types/current/playback/createStallMonitor.test.js +125 -0
  173. package/dist/unit/types/current/streaming/ContentStream.test.js +0 -11
  174. package/dist/unit/types/current/streaming/MseTrack.test.js +49 -73
  175. package/dist/unit/types/current/streaming/abr/QualitySelectorImpl.test.js +1 -1
  176. package/dist/unit/types/current/streaming/buffering/BufferingController.test.js +0 -21
  177. package/dist/unit/types/current/streaming/createDefaultMediaTimelineTransformer.test.js +133 -0
  178. package/dist/unit/types/current/streaming/mediaTimelineFilter.test.js +60 -54
  179. package/dist/unit/types/current/track/TrackController.test.js +61 -1
  180. package/dist/unit/types/current/track/createSegmentDataProvider.test.js +18 -0
  181. package/dist/unit/types/current/track/dash/DashMediaQualityMetadataResolver.test.js +46 -14
  182. package/dist/unit/types/current/track/dash/createSegmentControllerFactory.test.js +1 -0
  183. package/dist/unit/types/current/track/dash/timeline/DashRepresentationSegmentProvider.test.js +114 -0
  184. package/dist/unit/types/current/track/dash/util/mpd.test.js +37 -0
  185. package/dist/unit/types/current/track/filters/resourceTypeFilter.test.js +7 -0
  186. package/dist/unit/types/current/track/filters/sampleRateFilter.test.js +211 -34
  187. package/dist/unit/types/current/track/source/SourceObjectTrack.test.js +1 -1
  188. package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -1
  189. package/dist/unit/types/current/util/media/mimeType.test.d.ts +2 -0
  190. package/dist/unit/types/current/util/media/mimeType.test.d.ts.map +1 -0
  191. package/dist/unit/types/current/util/media/mimeType.test.js +22 -0
  192. package/dist/unit/types/current/vinyl/VinylPlayer.test.js +33 -2
  193. package/dist/unit/types/current/vinyl/createVinylFactories.test.js +2 -36
  194. package/dist/vinylTestUtil/index.js +6 -4
  195. package/dist/vinylTestUtil/index.js.map +2 -2
  196. package/dist/vinylTestUtil/types/current/assets/vinylTestAssets.d.ts +1 -0
  197. package/dist/vinylTestUtil/types/current/assets/vinylTestAssets.d.ts.map +1 -1
  198. package/dist/vinylTestUtil/types/current/assets/vinylTestAssets.js +1 -0
  199. package/dist/vinylTestUtil/types/current/media/FrequencyAnalyzer.d.ts.map +1 -1
  200. package/dist/vinylTestUtil/types/current/mock/streaming/MockContentStream.d.ts +0 -1
  201. package/dist/vinylTestUtil/types/current/mock/streaming/MockContentStream.d.ts.map +1 -1
  202. package/dist/vinylTestUtil/types/current/mock/streaming/MockContentStream.js +0 -1
  203. package/dist/vinylTestUtil/types/current/mock/streaming/buffering/MockBufferingController.d.ts +0 -1
  204. package/dist/vinylTestUtil/types/current/mock/streaming/buffering/MockBufferingController.d.ts.map +1 -1
  205. package/dist/vinylTestUtil/types/current/mock/streaming/buffering/MockBufferingController.js +0 -1
  206. package/dist/vinylTestUtil/types/current/tsconfig.tsbuildinfo +1 -1
  207. package/dist/vinylTestUtil/types/current/util/playback/eventPromises.js +1 -1
  208. package/dist/vinylTestUtil/types/current/util/playback/expectTrackCanSeek.d.ts.map +1 -1
  209. package/dist/vinylTestUtil/types/current/util/playback/expectTrackCanSeek.js +9 -1
  210. package/dist/vinylTestUtil/types/ts3.7/assets/vinylTestAssets.d.ts +1 -0
  211. package/dist/vinylTestUtil/types/ts3.7/mock/streaming/MockContentStream.d.ts +0 -1
  212. package/dist/vinylTestUtil/types/ts3.7/mock/streaming/buffering/MockBufferingController.d.ts +0 -1
  213. package/dist/vinylTestUtil/types/ts4.1/assets/vinylTestAssets.d.ts +1 -0
  214. package/dist/vinylTestUtil/types/ts4.1/mock/streaming/MockContentStream.d.ts +0 -1
  215. package/dist/vinylTestUtil/types/ts4.1/mock/streaming/buffering/MockBufferingController.d.ts +0 -1
  216. package/dist/vinylTestUtil/types/ts4.7/assets/vinylTestAssets.d.ts +1 -0
  217. package/dist/vinylTestUtil/types/ts4.7/mock/streaming/MockContentStream.d.ts +0 -1
  218. package/dist/vinylTestUtil/types/ts4.7/mock/streaming/buffering/MockBufferingController.d.ts +0 -1
  219. package/docs/USAGE.md +29 -0
  220. package/package.json +11 -10
  221. package/dist/types/current/patch/media/HtmlMediaElementPatch.d.ts +0 -3
  222. package/dist/types/current/patch/media/HtmlMediaElementPatch.d.ts.map +0 -1
  223. package/dist/types/current/patch/media/HtmlMediaElementPatch.js +0 -5
  224. package/dist/types/current/patch/media/MediaElementPatchOptions.d.ts +0 -19
  225. package/dist/types/current/patch/media/MediaElementPatchOptions.d.ts.map +0 -1
  226. package/dist/types/current/patch/media/MediaElementPatchOptions.js +0 -16
  227. package/dist/types/current/patch/media/patchMediaElement.d.ts +0 -9
  228. package/dist/types/current/patch/media/patchMediaElement.d.ts.map +0 -1
  229. package/dist/types/current/patch/media/patchMediaElement.js +0 -15
  230. package/dist/types/current/patch/media/patches/createPreventStallsPatch.d.ts +0 -17
  231. package/dist/types/current/patch/media/patches/createPreventStallsPatch.d.ts.map +0 -1
  232. package/dist/types/current/patch/media/patches/createPreventStallsPatch.js +0 -55
  233. package/dist/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.d.ts +0 -26
  234. package/dist/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.d.ts.map +0 -1
  235. package/dist/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.js +0 -218
  236. package/dist/types/current/vinyl/VinylPatchOptions.d.ts +0 -10
  237. package/dist/types/current/vinyl/VinylPatchOptions.d.ts.map +0 -1
  238. package/dist/types/current/vinyl/VinylPatchOptions.js +0 -11
  239. package/dist/types/ts3.7/patch/media/HtmlMediaElementPatch.d.ts +0 -3
  240. package/dist/types/ts3.7/patch/media/MediaElementPatchOptions.d.ts +0 -19
  241. package/dist/types/ts3.7/patch/media/patchMediaElement.d.ts +0 -9
  242. package/dist/types/ts3.7/patch/media/patches/createPreventStallsPatch.d.ts +0 -17
  243. package/dist/types/ts3.7/patch/media/patches/createUnreliablePlaybackEventsPatch.d.ts +0 -26
  244. package/dist/types/ts3.7/vinyl/VinylPatchOptions.d.ts +0 -10
  245. package/dist/types/ts4.1/patch/media/HtmlMediaElementPatch.d.ts +0 -3
  246. package/dist/types/ts4.1/patch/media/MediaElementPatchOptions.d.ts +0 -19
  247. package/dist/types/ts4.1/patch/media/patchMediaElement.d.ts +0 -9
  248. package/dist/types/ts4.1/patch/media/patches/createPreventStallsPatch.d.ts +0 -17
  249. package/dist/types/ts4.1/patch/media/patches/createUnreliablePlaybackEventsPatch.d.ts +0 -26
  250. package/dist/types/ts4.1/vinyl/VinylPatchOptions.d.ts +0 -10
  251. package/dist/types/ts4.7/patch/media/HtmlMediaElementPatch.d.ts +0 -3
  252. package/dist/types/ts4.7/patch/media/MediaElementPatchOptions.d.ts +0 -19
  253. package/dist/types/ts4.7/patch/media/patchMediaElement.d.ts +0 -9
  254. package/dist/types/ts4.7/patch/media/patches/createPreventStallsPatch.d.ts +0 -17
  255. package/dist/types/ts4.7/patch/media/patches/createUnreliablePlaybackEventsPatch.d.ts +0 -26
  256. package/dist/types/ts4.7/vinyl/VinylPatchOptions.d.ts +0 -10
  257. package/dist/unit/types/current/patch/media/MediaElementPatchOptions.test.d.ts +0 -2
  258. package/dist/unit/types/current/patch/media/MediaElementPatchOptions.test.d.ts.map +0 -1
  259. package/dist/unit/types/current/patch/media/MediaElementPatchOptions.test.js +0 -17
  260. package/dist/unit/types/current/patch/media/patchMediaElement.test.d.ts +0 -2
  261. package/dist/unit/types/current/patch/media/patchMediaElement.test.d.ts.map +0 -1
  262. package/dist/unit/types/current/patch/media/patchMediaElement.test.js +0 -36
  263. package/dist/unit/types/current/patch/media/patches/createPreventStallsPatch.test.d.ts +0 -2
  264. package/dist/unit/types/current/patch/media/patches/createPreventStallsPatch.test.d.ts.map +0 -1
  265. package/dist/unit/types/current/patch/media/patches/createPreventStallsPatch.test.js +0 -93
  266. package/dist/unit/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.test.d.ts +0 -2
  267. package/dist/unit/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.test.d.ts.map +0 -1
  268. package/dist/unit/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.test.js +0 -423
@@ -389,6 +389,58 @@ describe('DrmControllerImpl', () => {
389
389
  expect(errorSpy).not.toHaveBeenCalled();
390
390
  expect(mediaKeys.createSession).toHaveBeenCalledTimes(1); // reused
391
391
  });
392
+ it('reuses the session when a transformer alters the CDM init data', async () => {
393
+ // A non-identity initDataTransformer changes the bytes handed to the
394
+ // CDM (always the case for FairPlay, or any custom transformer). The
395
+ // reuse check must compare the ORIGINAL init data, not the
396
+ // transformed bytes — otherwise every re-appended init segment fires
397
+ // `encrypted` and spins up a brand-new session instead of recycling.
398
+ const transformed = new Uint8Array([9, 9, 9]);
399
+ const controller = new DrmControllerImpl(deps, {
400
+ licenseProvider,
401
+ keySystems: {
402
+ [DrmKeySystem.WIDEVINE]: {
403
+ initDataTransformer: () => transformed,
404
+ },
405
+ },
406
+ });
407
+ const localErrors = createEventSpy(controller, 'error');
408
+ const encryptedCb = commonEme.addEncryptedListener.calls.mostRecent().args[1];
409
+ controller.setBufferingDrmInfo(drmInfo);
410
+ encryptedCb({
411
+ initData: new Uint8Array([1, 2, 3]),
412
+ initDataType: 'cenc',
413
+ });
414
+ await flushPromises();
415
+ expect(mediaKeys.createSession).toHaveBeenCalledTimes(1);
416
+ // The session stored the transformed bytes handed to the CDM.
417
+ expect(getSession(0).initData).toEqual(transformed);
418
+ // The same raw init data fires again (e.g. a quality switch
419
+ // re-appends the init segment) — the session must be reused.
420
+ encryptedCb({
421
+ initData: new Uint8Array([1, 2, 3]),
422
+ initDataType: 'cenc',
423
+ });
424
+ await flushPromises();
425
+ expect(localErrors).not.toHaveBeenCalled();
426
+ expect(mediaKeys.createSession).toHaveBeenCalledTimes(1); // reused
427
+ controller.dispose();
428
+ });
429
+ it('ignores encrypted events when the manifest supplies pssh', async () => {
430
+ // The proactive manifest-pssh path owns session creation, so in-band
431
+ // `encrypted` events (e.g. a re-appended init segment on an ABR
432
+ // switch) must not spawn a duplicate session.
433
+ const drmInfoWithPssh = {
434
+ ...drmInfo,
435
+ contentProtections: [
436
+ { keySystem: DrmKeySystem.WIDEVINE, pssh: 'AAAA' },
437
+ ],
438
+ };
439
+ drmController.setBufferingDrmInfo(drmInfoWithPssh);
440
+ await emitEncrypted(new Uint8Array([1, 2, 3]));
441
+ expect(errorSpy).not.toHaveBeenCalled();
442
+ expect(mediaKeys.createSession).not.toHaveBeenCalled();
443
+ });
392
444
  describe('and the drm controller is disposed', () => {
393
445
  it('does nothing', async () => {
394
446
  drmController.dispose();
@@ -613,6 +665,29 @@ describe('DrmControllerImpl', () => {
613
665
  });
614
666
  });
615
667
  describe('when a session message event is observed', () => {
668
+ it('does not update the session when disposed before the license resolves', async () => {
669
+ let resolveLicense = () => { };
670
+ licenseProvider.and.returnValue(new Promise((res) => {
671
+ resolveLicense = res;
672
+ }));
673
+ drmController = new DrmControllerImpl(deps, {
674
+ keySystems: {
675
+ [DrmKeySystem.WIDEVINE]: {
676
+ licenseServer: { url: 'http://example.com/widevine' },
677
+ },
678
+ },
679
+ licenseProvider,
680
+ });
681
+ drmController.setBufferingDrmInfo(drmInfo);
682
+ await emitEncrypted(new Uint8Array([1, 2, 3]), 'cenc');
683
+ getSession(0).dispatch('message', { message: new ArrayBuffer(1) });
684
+ await flushPromises();
685
+ // License in flight — dispose, then let it resolve.
686
+ drmController.dispose();
687
+ resolveLicense(new ArrayBuffer(2));
688
+ await flushPromises();
689
+ expect(getSession(0).update).not.toHaveBeenCalled();
690
+ });
616
691
  it('calls the licenseProvider with resolved licenseServer options', async () => {
617
692
  drmController = new DrmControllerImpl(deps, {
618
693
  keySystems: {
@@ -666,6 +741,24 @@ describe('DrmControllerImpl', () => {
666
741
  }, message);
667
742
  }
668
743
  });
744
+ it('falls back to the wildcard key system license server', async () => {
745
+ drmController = new DrmControllerImpl(deps, {
746
+ keySystems: {
747
+ // Only a wildcard entry — no per-key-system configuration.
748
+ '*': {
749
+ licenseServer: () => ({
750
+ url: 'http://example.com/wildcard',
751
+ }),
752
+ },
753
+ },
754
+ licenseProvider,
755
+ });
756
+ drmController.setBufferingDrmInfo(drmInfo);
757
+ await emitEncrypted(new Uint8Array([1, 2, 3]), 'cenc');
758
+ const message = new ArrayBuffer(1);
759
+ await emitMessage(0, message);
760
+ expect(licenseProvider).toHaveBeenCalledOnceWith(DrmKeySystem.WIDEVINE, { url: 'http://example.com/wildcard' }, message);
761
+ });
669
762
  describe('when license takes too long to resolve', () => {
670
763
  it('emits an error event', async () => {
671
764
  drmController = new DrmControllerImpl(deps, {
@@ -857,28 +950,70 @@ describe('DrmControllerImpl', () => {
857
950
  drmController.setBufferingDrmInfo(drmInfo);
858
951
  await emitEncrypted(new Uint8Array([1, 2, 3]), 'cenc');
859
952
  await emitMessage(0, new ArrayBuffer(1));
860
- expect(spy).toHaveBeenCalledOnceWith(objectContaining({
953
+ expect(spy).toHaveBeenCalledWith(objectContaining({
861
954
  kind: 'license',
862
955
  startTime: any(Number),
863
956
  endTime: any(Number),
864
957
  }));
865
958
  });
959
+ it('measures the key setup, contiguous with and before the license', async () => {
960
+ licenseProvider.and.resolveTo(new Uint8Array([1]).buffer);
961
+ const spy = createEventSpy(drmController, 'loadSpanMeasured');
962
+ drmController.setBufferingDrmInfo(drmInfo, { trackUri: 'track-a' });
963
+ await emitEncrypted(new Uint8Array([1, 2, 3]), 'cenc');
964
+ await emitMessage(0, new ArrayBuffer(1));
965
+ const spans = spy.calls.all().map((call) => call.args[0]);
966
+ expect(spans.map((span) => span.kind)).toEqual([
967
+ 'keySetup',
968
+ 'license',
969
+ ]);
970
+ const [keySetup, license] = spans;
971
+ expect(keySetup.trackUri).toEqual('track-a');
972
+ expect(keySetup.endTime).toEqual(license.startTime);
973
+ });
974
+ it('carries the content mime and content type on the license span', async () => {
975
+ licenseProvider.and.resolveTo(new Uint8Array([1]).buffer);
976
+ const spy = createEventSpy(drmController, 'loadSpanMeasured');
977
+ drmController.setBufferingDrmInfo(drmInfo);
978
+ await emitEncrypted(new Uint8Array([1, 2, 3]), 'cenc');
979
+ await emitMessage(0, new ArrayBuffer(1));
980
+ expect(spy).toHaveBeenCalledWith(objectContaining({
981
+ kind: 'license',
982
+ mimeType: 'audio/mp4',
983
+ contentType: 'audio',
984
+ }));
985
+ });
866
986
  it('does not measure a failed license exchange', async () => {
867
987
  licenseProvider.and.rejectWith(new Error('license failed'));
868
988
  const spy = createEventSpy(drmController, 'loadSpanMeasured');
869
989
  drmController.setBufferingDrmInfo(drmInfo);
870
990
  await emitEncrypted(new Uint8Array([1, 2, 3]), 'cenc');
871
991
  await emitMessage(0, new ArrayBuffer(1));
872
- expect(spy).not.toHaveBeenCalled();
992
+ // Setup completed at the message, so keySetup is still measured.
993
+ expect(spy).not.toHaveBeenCalledWith(objectContaining({ kind: 'license' }));
873
994
  errorSpy.calls.reset();
874
995
  });
996
+ it('measures key setup only for the first session of a track load', async () => {
997
+ licenseProvider.and.resolveTo(new Uint8Array([1]).buffer);
998
+ const spy = createEventSpy(drmController, 'loadSpanMeasured');
999
+ drmController.setBufferingDrmInfo(drmInfo, { trackUri: 'track-a' });
1000
+ await emitEncrypted(new Uint8Array([1]), 'cenc');
1001
+ await emitEncrypted(new Uint8Array([2]), 'cenc');
1002
+ expect(mediaKeys.createSession).toHaveBeenCalledTimes(2);
1003
+ await emitMessage(0, new ArrayBuffer(1));
1004
+ await emitMessage(1, new ArrayBuffer(1));
1005
+ const keySetupSpans = spy.calls
1006
+ .all()
1007
+ .filter((call) => call.args[0].kind === 'keySetup');
1008
+ expect(keySetupSpans.length).toEqual(1);
1009
+ });
875
1010
  it('attributes the license span to the buffering track uri', async () => {
876
1011
  licenseProvider.and.resolveTo(new Uint8Array([1]).buffer);
877
1012
  const spy = createEventSpy(drmController, 'loadSpanMeasured');
878
1013
  drmController.setBufferingDrmInfo(drmInfo, { trackUri: 'track-a' });
879
1014
  await emitEncrypted(new Uint8Array([1, 2, 3]), 'cenc');
880
1015
  await emitMessage(0, new ArrayBuffer(1));
881
- expect(spy).toHaveBeenCalledOnceWith(objectContaining({
1016
+ expect(spy).toHaveBeenCalledWith(objectContaining({
882
1017
  kind: 'license',
883
1018
  trackUri: 'track-a',
884
1019
  }));
@@ -912,12 +1047,14 @@ describe('DrmControllerImpl', () => {
912
1047
  // on the controller's current buffering track.
913
1048
  await emitMessage(1, new ArrayBuffer(1));
914
1049
  await emitMessage(0, new ArrayBuffer(1));
915
- expect(spy).toHaveBeenCalledTimes(2);
916
- expect(spy).toHaveBeenCalledWith(objectContaining({
917
- kind: 'license',
918
- trackUri: 'track-preloaded',
919
- }));
920
- expect(spy).toHaveBeenCalledWith(objectContaining({ kind: 'license', trackUri: 'track-active' }));
1050
+ const licenseTrackUris = spy.calls
1051
+ .all()
1052
+ .map((call) => call.args[0])
1053
+ .filter((span) => span.kind === 'license')
1054
+ .map((span) => span.trackUri);
1055
+ expect(licenseTrackUris.length).toEqual(2);
1056
+ expect(licenseTrackUris).toContain('track-preloaded');
1057
+ expect(licenseTrackUris).toContain('track-active');
921
1058
  });
922
1059
  });
923
1060
  describe('serverCertificate', () => {
@@ -25,10 +25,8 @@ import './global/configureVinylGlobal.test';
25
25
  import './global/environment.test';
26
26
  import './global/globalRef.test';
27
27
  import './global/PlayerRegistry.test';
28
- import './patch/media/MediaElementPatchOptions.test';
29
- import './patch/media/patches/createPreventStallsPatch.test';
30
- import './patch/media/patches/createUnreliablePlaybackEventsPatch.test';
31
- import './patch/media/patchMediaElement.test';
28
+ import './playback/createStallDetector.test';
29
+ import './playback/createStallMonitor.test';
32
30
  import './playback/error/InvalidSeekError.test';
33
31
  import './playback/error/ReportableMediaError.test';
34
32
  import './playback/logging/mediaErrorToJson.test';
@@ -116,6 +114,7 @@ import './util/media/codecOverrides.test';
116
114
  import './util/media/codecSupport.test';
117
115
  import './util/media/getAudioContext.test';
118
116
  import './util/media/mediaSource.test';
117
+ import './util/media/mimeType.test';
119
118
  import './util/media/sourceBuffer.test';
120
119
  import './vinyl/createVinylFactories.test';
121
120
  import './vinyl/playerConfigFactory.test';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../test/unit/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../test/unit/index.ts"],"names":[],"mappings":"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"}
@@ -25,10 +25,8 @@ import './global/configureVinylGlobal.test';
25
25
  import './global/environment.test';
26
26
  import './global/globalRef.test';
27
27
  import './global/PlayerRegistry.test';
28
- import './patch/media/MediaElementPatchOptions.test';
29
- import './patch/media/patches/createPreventStallsPatch.test';
30
- import './patch/media/patches/createUnreliablePlaybackEventsPatch.test';
31
- import './patch/media/patchMediaElement.test';
28
+ import './playback/createStallDetector.test';
29
+ import './playback/createStallMonitor.test';
32
30
  import './playback/error/InvalidSeekError.test';
33
31
  import './playback/error/ReportableMediaError.test';
34
32
  import './playback/logging/mediaErrorToJson.test';
@@ -116,6 +114,7 @@ import './util/media/codecOverrides.test';
116
114
  import './util/media/codecSupport.test';
117
115
  import './util/media/getAudioContext.test';
118
116
  import './util/media/mediaSource.test';
117
+ import './util/media/mimeType.test';
119
118
  import './util/media/sourceBuffer.test';
120
119
  import './vinyl/createVinylFactories.test';
121
120
  import './vinyl/playerConfigFactory.test';
@@ -78,6 +78,29 @@ describe('PlaybackController', () => {
78
78
  if (!controller.disposed)
79
79
  controller.dispose();
80
80
  });
81
+ describe('stall detection', () => {
82
+ it('does not emit stallEntered before playback is observed', async () => {
83
+ const enteredSpy = createEventSpy(controller, 'stallEntered');
84
+ await clock.tick(2);
85
+ expect(enteredSpy).not.toHaveBeenCalled();
86
+ });
87
+ it('emits stallEntered when the play head freezes while playing and stallEnded on resume', async () => {
88
+ const enteredSpy = createEventSpy(controller, 'stallEntered');
89
+ const endedSpy = createEventSpy(controller, 'stallEnded');
90
+ media.dispatchEvent(mockEvent('playing'));
91
+ media.currentTime = 1;
92
+ media.dispatchEvent(mockEvent('timeupdate'));
93
+ // Frozen for the 1s default threshold.
94
+ await clock.tick(1);
95
+ expect(enteredSpy).toHaveBeenCalledTimes(1);
96
+ expect(endedSpy).not.toHaveBeenCalled();
97
+ // Play head advances -> stall ends with reason 'playing'.
98
+ media.currentTime = 2;
99
+ media.dispatchEvent(mockEvent('timeupdate'));
100
+ expect(endedSpy).toHaveBeenCalledTimes(1);
101
+ expect(endedSpy.calls.mostRecent().args[0].reason).toBe('playing');
102
+ });
103
+ });
81
104
  it('assigns properties, methods, and events directly to a media object', () => {
82
105
  expect(controller.buffered).toBeInstanceOf(ReadonlyRangesImpl);
83
106
  testDelegate(controller, 'currentTime', 2);
@@ -191,6 +214,135 @@ describe('PlaybackController', () => {
191
214
  },
192
215
  });
193
216
  }
217
+ /**
218
+ * Simulates WebKit reverting a seek: the first `revertCount`
219
+ * seeks land at `revertTo` instead of the requested time; later
220
+ * seeks land on the requested time.
221
+ */
222
+ function enableSeekWithReverts(revertTo, revertCount) {
223
+ let currentTime = 0;
224
+ let reverts = revertCount;
225
+ Object.defineProperty(media, 'currentTime', {
226
+ get() {
227
+ return currentTime;
228
+ },
229
+ set(value) {
230
+ currentTime = reverts-- > 0 ? revertTo : value;
231
+ media.dispatchEvent(mockEvent('seeking'));
232
+ void (async () => {
233
+ await flushPromises();
234
+ media.dispatchEvent(mockEvent('seeked'));
235
+ })();
236
+ },
237
+ });
238
+ }
239
+ /**
240
+ * Simulates a WebKit cold-seek stall: `seeking` fires but
241
+ * `seeked` does not for the first `stuckAttempts` attempts, then
242
+ * completes.
243
+ */
244
+ function enableStuckSeek(stuckAttempts) {
245
+ let currentTime = 0;
246
+ let attempt = 0;
247
+ Object.defineProperty(media, 'currentTime', {
248
+ get() {
249
+ return currentTime;
250
+ },
251
+ set(value) {
252
+ currentTime = value;
253
+ media.dispatchEvent(mockEvent('seeking'));
254
+ if (attempt++ >= stuckAttempts) {
255
+ void (async () => {
256
+ await flushPromises();
257
+ media.dispatchEvent(mockEvent('seeked'));
258
+ })();
259
+ }
260
+ },
261
+ });
262
+ }
263
+ it('warms the decoder and retries when a seek stalls', async () => {
264
+ enableStuckSeek(1); // first attempt hangs, retry completes
265
+ setSeekable([[0, 30]]);
266
+ media.paused = false;
267
+ const seek = controller.seekTo(5);
268
+ // Flush to arm the first attempt's seeked timeout, then
269
+ // advance to fire it; the retry lands via its seeked event.
270
+ await clock.tick(0, 4);
271
+ await seek;
272
+ // Warmed the decoder with play(), then landed on retry.
273
+ expect(media.play).toHaveBeenCalled();
274
+ expect(media.currentTime).toBe(5);
275
+ });
276
+ it('gives up after the retry limit when a seek never completes', async () => {
277
+ enableStuckSeek(99); // never completes
278
+ setSeekable([[0, 30]]);
279
+ media.paused = false;
280
+ const seek = controller.seekTo(5);
281
+ // Leading flush arms the initial attempt's seeked timeout;
282
+ // each subsequent tick fires one and arms the next retry
283
+ // (initial + SEEK_RETRY_LIMIT attempts all time out).
284
+ await clock.tick(0, 4, 4, 4);
285
+ await seek;
286
+ expect(media.play).toHaveBeenCalled();
287
+ });
288
+ it('stops retrying when a re-seek never re-enters seeking', async () => {
289
+ let sets = 0;
290
+ let currentTime = 0;
291
+ Object.defineProperty(media, 'currentTime', {
292
+ get() {
293
+ return currentTime;
294
+ },
295
+ set(value) {
296
+ currentTime = value;
297
+ // Only the first attempt emits `seeking`; re-seeks to
298
+ // the same position stay silent (WebKit), so their
299
+ // seeking wait times out and returns null.
300
+ if (sets++ === 0) {
301
+ media.dispatchEvent(mockEvent('seeking'));
302
+ }
303
+ },
304
+ });
305
+ setSeekable([[0, 30]]);
306
+ media.paused = false;
307
+ const seek = controller.seekTo(5);
308
+ await clock.tick(0, 4, 4, 4);
309
+ await seek;
310
+ expect(media.currentTime).toBe(5);
311
+ });
312
+ it('rejects a seek disposed while awaiting seeked', async () => {
313
+ setSeekable([[0, 30]]);
314
+ media.paused = false;
315
+ const seek = controller.seekTo(5);
316
+ media.dispatchEvent(mockEvent('seeking'));
317
+ await flushPromises();
318
+ controller.dispose();
319
+ await expectAsync(seek).toBeRejectedWithError(AbortError);
320
+ });
321
+ it('re-seeks when WebKit lands the play head off target', async () => {
322
+ enableSeekWithReverts(20, 1);
323
+ setSeekable([[0, 30]]);
324
+ media.paused = true;
325
+ await controller.seekTo(5);
326
+ expect(media.currentTime).toBeCloseTo(5);
327
+ });
328
+ it('gives up re-seeking after the retry limit', async () => {
329
+ enableSeekWithReverts(20, 99);
330
+ setSeekable([[0, 30]]);
331
+ media.paused = true;
332
+ await controller.seekTo(5);
333
+ expect(media.currentTime).toBe(20);
334
+ });
335
+ it('stops re-seeking when a newer seek supersedes', async () => {
336
+ enableSeekWithReverts(20, 99);
337
+ setSeekable([[0, 30]]);
338
+ media.paused = true;
339
+ const first = controller.seekTo(5);
340
+ const second = controller.seekTo(9);
341
+ await Promise.allSettled([first, second]);
342
+ // Both landed at the reverted position; the first stopped
343
+ // re-seeking once superseded rather than fighting the newer.
344
+ expect(media.currentTime).toBe(20);
345
+ });
194
346
  it('waits for metadata before initiating seek', async () => {
195
347
  enableSeekAutoComplete();
196
348
  const seeked = controller.seekTo(3);
@@ -199,6 +351,19 @@ describe('PlaybackController', () => {
199
351
  await seeked;
200
352
  expect(media.currentTime).toBe(3);
201
353
  });
354
+ it('fabricates a playing event if playback resumes after a seek without one', async () => {
355
+ enableSeekAutoComplete();
356
+ setSeekable([[0, 10]]);
357
+ media.paused = false;
358
+ const playingSpy = createSpy('playing');
359
+ controller.on('playing', playingSpy);
360
+ await controller.seekTo(3);
361
+ // The play head advances but no 'playing' event fires; the
362
+ // post-seek stall detector fabricates one.
363
+ media.currentTime = 3.5;
364
+ await clock.tick(0.25);
365
+ expect(playingSpy).toHaveBeenCalled();
366
+ });
202
367
  it('does not let a metadata-deferred seek clobber a newer seek', async () => {
203
368
  // Reproduces the real race: the activate-time seek to the
204
369
  // track start parks waiting for the `loadedmetadata` EVENT.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=createStallDetector.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createStallDetector.test.d.ts","sourceRoot":"","sources":["../../../../../test/unit/playback/createStallDetector.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,163 @@
1
+ /*
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { createStallDetector } from '@amazon/vinyl';
6
+ import { implementEventFakes, MockHTMLAudioElement, mockEvent, MockTimeRanges, useMockTime, } from '@amazon/vinyl-util/browserTestUtil';
7
+ describe('createStallDetector', () => {
8
+ const clock = useMockTime();
9
+ let media;
10
+ let fabricatePlaying;
11
+ let stop;
12
+ beforeEach(() => {
13
+ media = new MockHTMLAudioElement();
14
+ implementEventFakes(media);
15
+ media.play.and.returnValue(Promise.resolve());
16
+ media.paused = false;
17
+ media.ended = false;
18
+ media.readyState = media.HAVE_ENOUGH_DATA;
19
+ media.currentTime = 10;
20
+ media.buffered = new MockTimeRanges([[0, 100]]);
21
+ fabricatePlaying = jasmine.createSpy('fabricatePlaying');
22
+ });
23
+ afterEach(() => {
24
+ stop?.();
25
+ });
26
+ function detect(overrides = {}) {
27
+ stop = createStallDetector(media, { fabricatePlaying, ...overrides });
28
+ }
29
+ /** Advances the mock clock by `n` default poll intervals. */
30
+ async function poll(n) {
31
+ for (let i = 0; i < n; i++) {
32
+ await clock.tick(0.25);
33
+ }
34
+ }
35
+ describe('a stall inside ready buffered data', () => {
36
+ it('nudges the play head once frozen past the stall threshold', async () => {
37
+ detect();
38
+ // Threshold is 0.75s = three polls; the third nudges by stallSkip.
39
+ await poll(3);
40
+ expect(media.currentTime).toBeCloseTo(10.1);
41
+ });
42
+ it('does not recover before the stall threshold', async () => {
43
+ detect();
44
+ await poll(2);
45
+ expect(media.currentTime).toBe(10);
46
+ expect(media.play).not.toHaveBeenCalled();
47
+ });
48
+ it('nudges even when the ready state is low (iOS reports a stale readyState)', async () => {
49
+ media.readyState = media.HAVE_METADATA;
50
+ detect();
51
+ await poll(3);
52
+ expect(media.currentTime).toBeCloseTo(10.1);
53
+ expect(media.play).not.toHaveBeenCalled();
54
+ });
55
+ it('keeps nudging, then gives up after maxAttempts', async () => {
56
+ detect();
57
+ // Default maxAttempts is 3, so at most three nudges (one every 3 polls).
58
+ await poll(12);
59
+ expect(media.currentTime).toBeCloseTo(10.3);
60
+ // Further polls do nothing; the detector has stopped.
61
+ await poll(6);
62
+ expect(media.currentTime).toBeCloseTo(10.3);
63
+ });
64
+ });
65
+ describe('a stall with no data at the playhead', () => {
66
+ it('does not recover when the playhead is outside all buffered ranges', async () => {
67
+ media.buffered = new MockTimeRanges([[50, 100]]);
68
+ detect();
69
+ await poll(6);
70
+ expect(media.currentTime).toBe(10);
71
+ expect(fabricatePlaying).not.toHaveBeenCalled();
72
+ });
73
+ it('does not recover at the end of buffered data', async () => {
74
+ // Within the default end margin (0.5s) of the buffer end.
75
+ media.buffered = new MockTimeRanges([[0, 10.3]]);
76
+ detect();
77
+ await poll(6);
78
+ expect(media.currentTime).toBe(10);
79
+ });
80
+ it('nudges at the end of the media (stuck end-of-track on src)', async () => {
81
+ // Buffer ends at the media duration: no more data is coming, so a
82
+ // freeze here is a stuck end-of-track and a nudge drives it to end.
83
+ media.buffered = new MockTimeRanges([[0, 10.3]]);
84
+ media.duration = 10.3;
85
+ detect();
86
+ await poll(3);
87
+ expect(media.currentTime).toBeCloseTo(10.1);
88
+ });
89
+ it('nudges outside buffered ranges when nudgeUnbuffered is set', async () => {
90
+ // WebKit path: re-issue the seek even though buffered looks empty.
91
+ media.buffered = new MockTimeRanges([[50, 100]]);
92
+ detect({ nudgeUnbuffered: true });
93
+ await poll(3);
94
+ expect(media.currentTime).toBeCloseTo(10.1);
95
+ });
96
+ it('stops when the source is emptied', async () => {
97
+ detect();
98
+ media.dispatchEvent(mockEvent('emptied'));
99
+ // Stopped: a later freeze in buffered data is not nudged.
100
+ await poll(6);
101
+ expect(media.currentTime).toBe(10);
102
+ });
103
+ });
104
+ describe('fabricating a playing event', () => {
105
+ it('fabricates when the head progresses without a playing event', async () => {
106
+ detect();
107
+ media.currentTime = 20;
108
+ await poll(1);
109
+ expect(fabricatePlaying).toHaveBeenCalledTimes(1);
110
+ // Detector stopped; a later freeze is not recovered.
111
+ await poll(6);
112
+ expect(media.play).not.toHaveBeenCalled();
113
+ });
114
+ it('does not fabricate when a real playing event fired and it keeps progressing', async () => {
115
+ detect();
116
+ media.dispatchEvent(mockEvent('playing'));
117
+ media.currentTime = 20;
118
+ await poll(6);
119
+ expect(fabricatePlaying).not.toHaveBeenCalled();
120
+ });
121
+ it('fabricates after reviving a stall even if a playing event fired earlier', async () => {
122
+ // iOS pattern: a playing event fires, then playback stalls.
123
+ media.readyState = media.HAVE_METADATA;
124
+ detect();
125
+ media.dispatchEvent(mockEvent('playing'));
126
+ await poll(3);
127
+ expect(media.currentTime).toBeCloseTo(10.1); // nudged (recovered)
128
+ // The recovery revives playback.
129
+ media.currentTime = 11;
130
+ await poll(1);
131
+ expect(fabricatePlaying).toHaveBeenCalledTimes(1);
132
+ });
133
+ });
134
+ describe('when the element is not advancing by design', () => {
135
+ it('does not recover while paused', async () => {
136
+ media.paused = true;
137
+ detect();
138
+ await poll(6);
139
+ expect(media.play).not.toHaveBeenCalled();
140
+ expect(media.currentTime).toBe(10);
141
+ });
142
+ it('does not recover once ended', async () => {
143
+ media.ended = true;
144
+ detect();
145
+ await poll(6);
146
+ expect(media.play).not.toHaveBeenCalled();
147
+ expect(media.currentTime).toBe(10);
148
+ });
149
+ });
150
+ it('honors provided options', async () => {
151
+ detect({
152
+ pollInterval: 0.5,
153
+ stallThreshold: 1,
154
+ bufferEndMargin: 0.2,
155
+ stallSkip: 0.25,
156
+ maxAttempts: 1,
157
+ });
158
+ // Threshold 1s = two 0.5s polls; one nudge of 0.25, then it gives up.
159
+ for (let i = 0; i < 6; i++)
160
+ await clock.tick(0.5);
161
+ expect(media.currentTime).toBeCloseTo(10.25);
162
+ });
163
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=createStallMonitor.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createStallMonitor.test.d.ts","sourceRoot":"","sources":["../../../../../test/unit/playback/createStallMonitor.test.ts"],"names":[],"mappings":""}