@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
@@ -0,0 +1,125 @@
1
+ /*
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { createStallMonitor, StallEndedReason, } from '@amazon/vinyl';
6
+ import { EventHostImpl } from '@amazon/vinyl-util';
7
+ import { useMockTime } from '@amazon/vinyl-util/browserTestUtil';
8
+ describe('createStallMonitor', () => {
9
+ const clock = useMockTime();
10
+ let host;
11
+ let onStallEntered;
12
+ let onStallEnded;
13
+ let stop;
14
+ beforeEach(() => {
15
+ host = new EventHostImpl();
16
+ onStallEntered = jasmine.createSpy('onStallEntered');
17
+ onStallEnded = jasmine.createSpy('onStallEnded');
18
+ });
19
+ afterEach(() => stop?.());
20
+ function monitor(overrides = {}) {
21
+ stop = createStallMonitor(host, { onStallEntered, onStallEnded }, overrides);
22
+ }
23
+ /** Advances the mock clock by `n` default (0.25s) poll intervals. */
24
+ async function poll(n) {
25
+ for (let i = 0; i < n; i++)
26
+ await clock.tick(0.25);
27
+ }
28
+ it('does not report a stall before playback is observed', async () => {
29
+ monitor();
30
+ // No 'playing' has been observed (e.g. initial load / awaiting a seek).
31
+ await poll(8);
32
+ expect(onStallEntered).not.toHaveBeenCalled();
33
+ });
34
+ it('reports a stall once the play head is frozen past the threshold', async () => {
35
+ monitor();
36
+ host.dispatch('playing', {});
37
+ await poll(3); // 0.75s < 1s threshold
38
+ expect(onStallEntered).not.toHaveBeenCalled();
39
+ await poll(1); // 1s
40
+ expect(onStallEntered).toHaveBeenCalledTimes(1);
41
+ });
42
+ it('honors a configurable threshold', async () => {
43
+ monitor({ stallThreshold: 2 });
44
+ host.dispatch('playing', {});
45
+ await poll(4); // 1s < 2s
46
+ expect(onStallEntered).not.toHaveBeenCalled();
47
+ await poll(4); // 2s
48
+ expect(onStallEntered).toHaveBeenCalledTimes(1);
49
+ });
50
+ it('does not report a stall while timeUpdates keep arriving', async () => {
51
+ monitor();
52
+ host.dispatch('playing', {});
53
+ for (let i = 0; i < 10; i++) {
54
+ await poll(2); // 0.5s, under the threshold
55
+ host.dispatch('timeUpdate', { previous: i, current: i + 1 });
56
+ }
57
+ expect(onStallEntered).not.toHaveBeenCalled();
58
+ });
59
+ it('ends a stall with reason "playing" when the play head advances, measuring from the last timeUpdate', async () => {
60
+ monitor();
61
+ host.dispatch('playing', {});
62
+ host.dispatch('timeUpdate', { previous: 0, current: 1 });
63
+ await poll(4); // freeze 1s -> stallEntered
64
+ expect(onStallEntered).toHaveBeenCalledTimes(1);
65
+ await poll(4); // frozen another 1s (total 2s)
66
+ host.dispatch('timeUpdate', { previous: 1, current: 2 }); // resume
67
+ expect(onStallEnded).toHaveBeenCalledTimes(1);
68
+ const info = onStallEnded.calls.mostRecent().args[0];
69
+ expect(info.reason).toBe(StallEndedReason.PLAYING);
70
+ expect(info.duration).toBeCloseTo(2, 1);
71
+ });
72
+ for (const [event, reason] of [
73
+ ['pause', StallEndedReason.PAUSE],
74
+ ['seeking', StallEndedReason.SEEKING],
75
+ ['emptied', StallEndedReason.EMPTIED],
76
+ ]) {
77
+ it(`ends a stall with reason "${reason}" on ${event}`, async () => {
78
+ monitor();
79
+ host.dispatch('playing', {});
80
+ await poll(4); // stallEntered
81
+ expect(onStallEntered).toHaveBeenCalledTimes(1);
82
+ host.dispatch(event, {});
83
+ expect(onStallEnded).toHaveBeenCalledTimes(1);
84
+ expect(onStallEnded.calls.mostRecent().args[0].reason).toBe(reason);
85
+ });
86
+ }
87
+ it('ends a stall with reason "playing" when a playing event fires (resume without a timeUpdate)', async () => {
88
+ monitor();
89
+ host.dispatch('playing', {});
90
+ await poll(4); // stallEntered
91
+ expect(onStallEntered).toHaveBeenCalledTimes(1);
92
+ // A 'playing' event (rather than a timeUpdate) signals the resume.
93
+ host.dispatch('playing', {});
94
+ expect(onStallEnded).toHaveBeenCalledTimes(1);
95
+ expect(onStallEnded.calls.mostRecent().args[0].reason).toBe(StallEndedReason.PLAYING);
96
+ });
97
+ it('suspends detection after a seek until playback is observed again', async () => {
98
+ monitor();
99
+ host.dispatch('playing', {});
100
+ host.dispatch('seeking', {}); // suspends; observedPlaying = false
101
+ await poll(8);
102
+ expect(onStallEntered).not.toHaveBeenCalled();
103
+ // Once playback is observed again, detection resumes.
104
+ host.dispatch('playing', {});
105
+ await poll(4);
106
+ expect(onStallEntered).toHaveBeenCalledTimes(1);
107
+ });
108
+ it('reports each stall/recovery cycle', async () => {
109
+ monitor();
110
+ host.dispatch('playing', {});
111
+ await poll(4);
112
+ host.dispatch('timeUpdate', { previous: 0, current: 1 }); // resume 1
113
+ await poll(4);
114
+ host.dispatch('timeUpdate', { previous: 1, current: 2 }); // resume 2
115
+ expect(onStallEntered).toHaveBeenCalledTimes(2);
116
+ expect(onStallEnded).toHaveBeenCalledTimes(2);
117
+ });
118
+ it('stops reporting after disposal', async () => {
119
+ monitor();
120
+ host.dispatch('playing', {});
121
+ stop();
122
+ await poll(8);
123
+ expect(onStallEntered).not.toHaveBeenCalled();
124
+ });
125
+ });
@@ -58,17 +58,6 @@ describe('ContentStreamImpl', () => {
58
58
  bufferingController.dispatch('error', { error, target });
59
59
  expect(spy).toHaveBeenCalledWith({ error, target });
60
60
  });
61
- it('redispatches hasDataChange from bufferingController', () => {
62
- const spy = createEventSpy(contentStream, 'hasDataChange');
63
- const event = { previous: false, current: true };
64
- bufferingController.dispatch('hasDataChange', event);
65
- expect(spy).toHaveBeenCalledWith(event);
66
- });
67
- it('exposes hasData from the bufferingController', () => {
68
- expect(contentStream.hasData).toBeFalse();
69
- bufferingController.hasData = true;
70
- expect(contentStream.hasData).toBeTrue();
71
- });
72
61
  });
73
62
  describe('preload', () => {
74
63
  it('configures segmentController with startTime and prefetchPriority', () => {
@@ -2,10 +2,10 @@
2
2
  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
- import { createEmptyMediaQualityMetadata, MseTrack, PLAYHEAD_NUDGE, SEEKING_STALL_TIME_CHECK, } from '@amazon/vinyl';
5
+ import { createEmptyMediaQualityMetadata, MseTrack, } from '@amazon/vinyl';
6
6
  import { createMockDashDependencies, } from '@amazon/vinyl/vinylTestUtil';
7
7
  import { createEventSpy, useMockLogger } from '@amazon/vinyl-util/testUtil';
8
- import { flushPromises, useMockTime } from '@amazon/vinyl-util/browserTestUtil';
8
+ import { flushPromises } from '@amazon/vinyl-util/browserTestUtil';
9
9
  import { externalDependencies } from '@amazon/vinyl-di';
10
10
  import { Abort } from '@amazon/vinyl-util';
11
11
  var any = jasmine.any;
@@ -413,73 +413,6 @@ describe('MseTrack', () => {
413
413
  expect(track.bufferingEnded).toBe(false);
414
414
  });
415
415
  });
416
- describe('stalled-seek recovery nudge', () => {
417
- const clock = useMockTime();
418
- function fillStream(stream) {
419
- stream.hasData = true;
420
- stream.dispatch('hasDataChange', { previous: false, current: true });
421
- }
422
- async function setup() {
423
- deps.playbackController.seekTo.and.resolveTo(void 0);
424
- track = createTrack();
425
- await awaitContentTypes();
426
- return { audio: getAudioStream(), video: getVideoStream() };
427
- }
428
- it('nudges the playhead when all streams have data but the seek is still stuck', async () => {
429
- const { audio, video } = await setup();
430
- deps.playbackController.seeking = true;
431
- deps.playbackController.currentTime = 30;
432
- fillStream(audio);
433
- // Only one stream has data — nothing scheduled yet.
434
- fillStream(video);
435
- expect(deps.playbackController.seekTo).not.toHaveBeenCalled();
436
- await clock.tick(SEEKING_STALL_TIME_CHECK * 1000);
437
- expect(deps.playbackController.seekTo).toHaveBeenCalledOnceWith(30 + PLAYHEAD_NUDGE, 0);
438
- });
439
- it('does not nudge if the seek completes before the check fires', async () => {
440
- const { audio, video } = await setup();
441
- deps.playbackController.seeking = true;
442
- fillStream(audio);
443
- fillStream(video);
444
- deps.playbackController.seeking = false;
445
- await clock.tick(SEEKING_STALL_TIME_CHECK * 1000);
446
- expect(deps.playbackController.seekTo).not.toHaveBeenCalled();
447
- });
448
- it('does not nudge until every stream has data', async () => {
449
- const { audio } = await setup();
450
- deps.playbackController.seeking = true;
451
- fillStream(audio);
452
- await clock.tick(SEEKING_STALL_TIME_CHECK * 1000);
453
- expect(deps.playbackController.seekTo).not.toHaveBeenCalled();
454
- });
455
- it('does not nudge if a stream loses its data before the check fires', async () => {
456
- const { audio, video } = await setup();
457
- deps.playbackController.seeking = true;
458
- fillStream(audio);
459
- fillStream(video);
460
- // A stream's buffer was cleared during the wait window.
461
- video.hasData = false;
462
- await clock.tick(SEEKING_STALL_TIME_CHECK * 1000);
463
- expect(deps.playbackController.seekTo).not.toHaveBeenCalled();
464
- });
465
- it('does not nudge when not seeking', async () => {
466
- const { audio, video } = await setup();
467
- deps.playbackController.seeking = false;
468
- fillStream(audio);
469
- fillStream(video);
470
- await clock.tick(SEEKING_STALL_TIME_CHECK * 1000);
471
- expect(deps.playbackController.seekTo).not.toHaveBeenCalled();
472
- });
473
- it('does not nudge after the track is disposed', async () => {
474
- const { audio, video } = await setup();
475
- deps.playbackController.seeking = true;
476
- fillStream(audio);
477
- fillStream(video);
478
- track.dispose();
479
- await clock.tick(SEEKING_STALL_TIME_CHECK * 1000);
480
- expect(deps.playbackController.seekTo).not.toHaveBeenCalled();
481
- });
482
- });
483
416
  describe('checkBufferingEnded', () => {
484
417
  it('calls endOfStream and dispatches bufferingEnded when all streams are done', async () => {
485
418
  track = createTrack();
@@ -652,6 +585,41 @@ describe('MseTrack', () => {
652
585
  expect(track.qualities).toEqual([qualityMetadata]);
653
586
  expect(track.qualitiesUnfiltered).toEqual([qualityMetadata]);
654
587
  });
588
+ it('plays the surviving content type when another is entirely filtered out', async () => {
589
+ // The content types now come from the FILTERED timeline: with every
590
+ // audio rendition filtered, only 'video' is required. No audio stream
591
+ // is created, so the load is never stranded waiting for an audio
592
+ // source buffer that will never arrive, and the track does not error.
593
+ deps.contentTypesValue.value = Promise.resolve(new Set(['video']));
594
+ const videoQuality = {
595
+ ...createEmptyMediaQualityMetadata(),
596
+ contentType: 'video',
597
+ qualityId: 'v1',
598
+ };
599
+ setTimeline({
600
+ periods: [
601
+ {
602
+ startTime: 0,
603
+ endTime: 100,
604
+ qualities: [
605
+ {
606
+ metadata: videoQuality,
607
+ getSegment: () => Promise.resolve(null),
608
+ },
609
+ ],
610
+ },
611
+ ],
612
+ minBufferTime: 2,
613
+ getAdBreaks: () => Promise.resolve([]),
614
+ getDuration: () => Promise.resolve(Infinity),
615
+ });
616
+ track = createTrack();
617
+ await flushPromises();
618
+ expect(track.error).toBeNull();
619
+ expect(track.contentTypes).toEqual(new Set(['video']));
620
+ expect(getStream('video')).not.toBeNull();
621
+ expect(getStream('audio')).toBeNull();
622
+ });
655
623
  it('reads qualities from the filtered timeline but qualitiesUnfiltered from the raw one', async () => {
656
624
  // The transformed timeline is filtered (e.g. by preferred audio
657
625
  // language) down to one quality; the raw timeline keeps them all.
@@ -1025,10 +993,6 @@ describe('MseTrack', () => {
1025
993
  name: 'audio language',
1026
994
  apply: () => (deps.audio.value = jaAudio),
1027
995
  },
1028
- {
1029
- name: 'allowedContentTypes',
1030
- apply: () => (deps.allowedContentTypes.value = allowed),
1031
- },
1032
996
  {
1033
997
  name: 'audio descriptive',
1034
998
  apply: () => (deps.audio.value = descriptiveAudio),
@@ -1053,6 +1017,18 @@ describe('MseTrack', () => {
1053
1017
  });
1054
1018
  });
1055
1019
  }
1020
+ describe('when allowedContentTypes changes', () => {
1021
+ // It only affects the content-type set, which flows through
1022
+ // contentTypesValue -> setContentTypes. Reloading directly here too
1023
+ // would double hard-reset and seek to 0.
1024
+ it('does not reload directly', () => {
1025
+ const clearSpy = spyOn(track, 'clearPrefetch');
1026
+ const resetSpy = spyOn(track, 'reset');
1027
+ deps.allowedContentTypes.value = allowed;
1028
+ expect(clearSpy).not.toHaveBeenCalled();
1029
+ expect(resetSpy).not.toHaveBeenCalled();
1030
+ });
1031
+ });
1056
1032
  describe('when abr resolution restrictions change', () => {
1057
1033
  it('clears prefetch (without a rebuild) when maxHeight changes', () => {
1058
1034
  const clearSpy = spyOn(track, 'clearPrefetch');
@@ -333,7 +333,7 @@ describe('QualitySelectorImpl', () => {
333
333
  });
334
334
  });
335
335
  });
336
- describe('when options change', () => {
336
+ describe('when options change after construction', () => {
337
337
  it('merges set options with defaults', () => {
338
338
  options.value = {
339
339
  highBufferThreshold: 32,
@@ -226,27 +226,6 @@ describe('BufferingControllerImpl', () => {
226
226
  expect(sourceBufferController.buffered.ranges).toEqual([[40, 60]]);
227
227
  });
228
228
  });
229
- describe('hasData', () => {
230
- beforeEach(() => {
231
- bufferingController = createBufferingController();
232
- bufferingController.activate();
233
- });
234
- it('flips true when the buffer fills and false when cleared', async () => {
235
- const spy = createEventSpy(bufferingController, 'hasDataChange');
236
- expect(bufferingController.hasData).toBeFalse();
237
- setSegmentList([1]);
238
- await open();
239
- expect(bufferingController.hasData).toBeTrue();
240
- expect(spy).toHaveBeenCalledWith({ previous: false, current: true });
241
- // Stop the segment provider so the post-clear re-poll can't re-fill.
242
- segmentController.getSegment.and.returnValue(Promise.resolve(null));
243
- spy.calls.reset();
244
- bufferingController.clear();
245
- await nextPollImmediate();
246
- expect(bufferingController.hasData).toBeFalse();
247
- expect(spy).toHaveBeenCalledWith({ previous: true, current: false });
248
- });
249
- });
250
229
  describe('when segments exceed max append size', () => {
251
230
  beforeEach(() => {
252
231
  bufferingController = createBufferingController({
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { createDefaultMediaTimelineTransformer, createEmptyMediaQualityMetadata, } from '@amazon/vinyl';
6
6
  import { data } from '@amazon/vinyl-observable';
7
+ import { setUserAgent } from '@amazon/vinyl-util';
7
8
  import { MockCapabilities, MockDrmController, } from '@amazon/vinyl/vinylTestUtil';
8
9
  function createQuality(overrides) {
9
10
  return {
@@ -332,6 +333,138 @@ describe('createDefaultMediaTimelineTransformer', () => {
332
333
  expect(result.periods[0].qualities[0].metadata.qualityId).toBe('ja');
333
334
  unsub();
334
335
  });
336
+ it('disables the sampling-rate filter via audio options at runtime', async () => {
337
+ // Output device at 44.1kHz: the 96kHz rendition is normally dropped
338
+ // (a 44.1kHz alternative exists, so the keep-lowest fallback declines).
339
+ capabilities.sampleRate = 44_100;
340
+ const timeline = {
341
+ periods: [
342
+ {
343
+ startTime: 0,
344
+ endTime: 100,
345
+ qualities: [
346
+ createQuality({
347
+ contentType: 'audio',
348
+ mimeType: 'audio/mp4',
349
+ qualityId: 'a44',
350
+ audioSamplingRate: [44_100],
351
+ }),
352
+ createQuality({
353
+ contentType: 'audio',
354
+ mimeType: 'audio/mp4',
355
+ qualityId: 'a96',
356
+ audioSamplingRate: [96_000],
357
+ }),
358
+ ],
359
+ },
360
+ ],
361
+ minBufferTime: 2,
362
+ getAdBreaks: () => Promise.resolve([]),
363
+ getDuration: () => Promise.resolve(Infinity),
364
+ };
365
+ const options = data({ audio: { disableSampleRateFilter: false } });
366
+ const transformed = createDefaultMediaTimelineTransformer({
367
+ capabilities,
368
+ drmController,
369
+ mediaTimeline: data(Promise.resolve(timeline)),
370
+ options,
371
+ });
372
+ const unsub = transformed.onData(() => { });
373
+ const ids = (t) => t.periods[0].qualities.map((q) => q.metadata.qualityId);
374
+ // Filter on: the 96kHz rendition is dropped.
375
+ expect(ids(await transformed.value)).toEqual(['a44']);
376
+ // Filter off: both renditions are kept.
377
+ options.value = { audio: { disableSampleRateFilter: true } };
378
+ expect(ids(await transformed.value)).toEqual(['a44', 'a96']);
379
+ unsub();
380
+ });
381
+ it('honors audio.maxSampleRate over the reported rate at runtime', async () => {
382
+ // Non-Firefox: Firefox hard-caps at 48kHz regardless of maxSampleRate.
383
+ setUserAgent('Chrome');
384
+ // AudioContext reports 48kHz, so the 96kHz rendition is dropped.
385
+ capabilities.sampleRate = 48_000;
386
+ const timeline = {
387
+ periods: [
388
+ {
389
+ startTime: 0,
390
+ endTime: 100,
391
+ qualities: [
392
+ createQuality({
393
+ contentType: 'audio',
394
+ mimeType: 'audio/mp4',
395
+ qualityId: 'a48',
396
+ audioSamplingRate: [48_000],
397
+ }),
398
+ createQuality({
399
+ contentType: 'audio',
400
+ mimeType: 'audio/mp4',
401
+ qualityId: 'a96',
402
+ audioSamplingRate: [96_000],
403
+ }),
404
+ ],
405
+ },
406
+ ],
407
+ minBufferTime: 2,
408
+ getAdBreaks: () => Promise.resolve([]),
409
+ getDuration: () => Promise.resolve(Infinity),
410
+ };
411
+ const options = data({ audio: {} });
412
+ const transformed = createDefaultMediaTimelineTransformer({
413
+ capabilities,
414
+ drmController,
415
+ mediaTimeline: data(Promise.resolve(timeline)),
416
+ options,
417
+ });
418
+ const unsub = transformed.onData(() => { });
419
+ const ids = (t) => t.periods[0].qualities.map((q) => q.metadata.qualityId);
420
+ expect(ids(await transformed.value)).toEqual(['a48']);
421
+ // Raise the cap to 96kHz: the 96kHz rendition is now kept.
422
+ options.value = { audio: { maxSampleRate: 96_000 } };
423
+ expect(ids(await transformed.value)).toEqual(['a48', 'a96']);
424
+ unsub();
425
+ });
426
+ it('applies audio.minSampleRate as a soft floor at runtime', async () => {
427
+ capabilities.sampleRate = 192_000; // max cap drops nothing
428
+ const timeline = {
429
+ periods: [
430
+ {
431
+ startTime: 0,
432
+ endTime: 100,
433
+ qualities: [
434
+ createQuality({
435
+ contentType: 'audio',
436
+ mimeType: 'audio/mp4',
437
+ qualityId: 'a48',
438
+ audioSamplingRate: [48_000],
439
+ }),
440
+ createQuality({
441
+ contentType: 'audio',
442
+ mimeType: 'audio/mp4',
443
+ qualityId: 'a24',
444
+ audioSamplingRate: [24_000],
445
+ }),
446
+ ],
447
+ },
448
+ ],
449
+ minBufferTime: 2,
450
+ getAdBreaks: () => Promise.resolve([]),
451
+ getDuration: () => Promise.resolve(Infinity),
452
+ };
453
+ const options = data({ audio: {} });
454
+ const transformed = createDefaultMediaTimelineTransformer({
455
+ capabilities,
456
+ drmController,
457
+ mediaTimeline: data(Promise.resolve(timeline)),
458
+ options,
459
+ });
460
+ const unsub = transformed.onData(() => { });
461
+ const ids = (t) => t.periods[0].qualities.map((q) => q.metadata.qualityId);
462
+ expect(ids(await transformed.value)).toEqual(['a48', 'a24']);
463
+ // Floor at 48kHz: the 24kHz rendition is dropped.
464
+ options.value = { audio: { minSampleRate: 48_000 } };
465
+ expect(ids(await transformed.value)).toEqual(['a48']);
466
+ unsub();
467
+ });
335
468
  it('preserves minBufferTime', async () => {
336
469
  const timeline = {
337
470
  periods: [
@@ -13,81 +13,87 @@ function createQuality(contentType, bandwidth) {
13
13
  getSegment: () => Promise.resolve(null),
14
14
  };
15
15
  }
16
- describe('filterTimelineQualities', () => {
17
- const timeline = {
18
- periods: [
19
- {
20
- startTime: 0,
21
- endTime: 10,
22
- qualities: [
23
- createQuality('audio', 128000),
24
- createQuality('audio', 256000),
25
- createQuality('video', 500000),
26
- ],
27
- },
28
- ],
16
+ function timelineOf(qualities) {
17
+ return {
18
+ periods: [{ startTime: 0, endTime: 10, qualities: [...qualities] }],
29
19
  minBufferTime: 2,
30
20
  getAdBreaks: () => Promise.resolve([]),
31
21
  getDuration: () => Promise.resolve(Infinity),
32
22
  };
23
+ }
24
+ function contentTypesOf(timeline) {
25
+ return new Set(timeline.periods[0].qualities.map((q) => q.metadata.contentType));
26
+ }
27
+ function throwEmpty() {
28
+ throw new Error('no qualities');
29
+ }
30
+ describe('filterTimelineQualities', () => {
31
+ const timeline = timelineOf([
32
+ createQuality('audio', 128000),
33
+ createQuality('audio', 256000),
34
+ createQuality('video', 500000),
35
+ ]);
33
36
  it('returns the timeline unchanged when the filter is null', () => {
34
37
  // A null predicate (e.g. no language preference) is a no-op.
35
- const result = filterTimelineQualities(null, () => {
36
- throw new Error('empty');
37
- }, timeline);
38
+ const result = filterTimelineQualities(null, throwEmpty, timeline);
38
39
  expect(result).toBe(timeline);
39
40
  });
40
- it('filters qualities by predicate', () => {
41
- const result = filterTimelineQualities((q) => q.contentType === 'audio', () => {
42
- throw new Error('empty');
43
- }, timeline);
41
+ it('filters qualities by predicate while keeping every present stream', () => {
42
+ const result = filterTimelineQualities((q) => q.bandwidth !== 256000, throwEmpty, timeline);
44
43
  expect(result.periods[0].qualities.length).toBe(2);
45
- expect(result.periods[0].qualities.every((q) => q.metadata.contentType === 'audio')).toBeTrue();
44
+ expect(contentTypesOf(result)).toEqual(new Set(['audio', 'video']));
46
45
  });
47
46
  it('preserves minBufferTime', () => {
48
- const result = filterTimelineQualities(() => true, () => {
49
- throw new Error('empty');
50
- }, timeline);
47
+ const result = filterTimelineQualities(() => true, throwEmpty, timeline);
51
48
  expect(result.minBufferTime).toBe(2);
52
49
  });
53
50
  it('throws when filtering removes all qualities', () => {
54
- expect(() => filterTimelineQualities(() => false, () => {
55
- throw new Error('no qualities');
56
- }, timeline)).toThrowError('no qualities');
51
+ expect(() => filterTimelineQualities(() => false, throwEmpty, timeline)).toThrowError('no qualities');
52
+ });
53
+ it('throws when filtering drops a present video stream to zero', () => {
54
+ expect(() => filterTimelineQualities((q) => q.contentType === 'audio', throwEmpty, timeline)).toThrowError('no qualities');
55
+ });
56
+ it('throws when filtering drops a present audio stream to zero', () => {
57
+ expect(() => filterTimelineQualities((q) => q.contentType === 'video', throwEmpty, timeline)).toThrowError('no qualities');
58
+ });
59
+ it('does not throw when losing only an optional text sidecar stream', () => {
60
+ const withText = timelineOf([
61
+ createQuality('audio', 128000),
62
+ createQuality('video', 500000),
63
+ createQuality('text', 1000),
64
+ ]);
65
+ const result = filterTimelineQualities((q) => q.contentType !== 'text', throwEmpty, withText);
66
+ expect(contentTypesOf(result)).toEqual(new Set(['audio', 'video']));
57
67
  });
58
68
  });
59
69
  describe('filterTimelineQualitiesAsync', () => {
60
- const timeline = {
61
- periods: [
62
- {
63
- startTime: 0,
64
- endTime: 10,
65
- qualities: [
66
- createQuality('audio', 128000),
67
- createQuality('video', 500000),
68
- ],
69
- },
70
- ],
71
- minBufferTime: 2,
72
- getAdBreaks: () => Promise.resolve([]),
73
- getDuration: () => Promise.resolve(Infinity),
74
- };
75
- it('filters qualities by async predicate', async () => {
76
- const result = await filterTimelineQualitiesAsync((q) => Promise.resolve(q.contentType === 'audio'), () => {
77
- throw new Error('empty');
78
- }, timeline);
79
- expect(result.periods[0].qualities.length).toBe(1);
80
- expect(result.periods[0].qualities[0].metadata.contentType).toBe('audio');
70
+ const timeline = timelineOf([
71
+ createQuality('audio', 128000),
72
+ createQuality('audio', 256000),
73
+ createQuality('video', 500000),
74
+ ]);
75
+ it('filters qualities by async predicate while keeping every present stream', async () => {
76
+ const result = await filterTimelineQualitiesAsync((q) => Promise.resolve(q.bandwidth !== 256000), throwEmpty, timeline);
77
+ expect(result.periods[0].qualities.length).toBe(2);
78
+ expect(contentTypesOf(result)).toEqual(new Set(['audio', 'video']));
81
79
  });
82
80
  it('preserves minBufferTime', async () => {
83
- const result = await filterTimelineQualitiesAsync(() => Promise.resolve(true), () => {
84
- throw new Error('empty');
85
- }, timeline);
81
+ const result = await filterTimelineQualitiesAsync(() => Promise.resolve(true), throwEmpty, timeline);
86
82
  expect(result.minBufferTime).toBe(2);
87
83
  });
88
84
  it('throws when filtering removes all qualities', async () => {
89
- await expectAsync(filterTimelineQualitiesAsync(() => Promise.resolve(false), () => {
90
- throw new Error('no qualities');
91
- }, timeline)).toBeRejectedWithError('no qualities');
85
+ await expectAsync(filterTimelineQualitiesAsync(() => Promise.resolve(false), throwEmpty, timeline)).toBeRejectedWithError('no qualities');
86
+ });
87
+ it('throws when filtering drops a present video stream to zero', async () => {
88
+ await expectAsync(filterTimelineQualitiesAsync((q) => Promise.resolve(q.contentType === 'audio'), throwEmpty, timeline)).toBeRejectedWithError('no qualities');
89
+ });
90
+ it('does not throw when losing only an optional text sidecar stream', async () => {
91
+ const withText = timelineOf([
92
+ createQuality('audio', 128000),
93
+ createQuality('video', 500000),
94
+ createQuality('text', 1000),
95
+ ]);
96
+ const result = await filterTimelineQualitiesAsync((q) => Promise.resolve(q.contentType !== 'text'), throwEmpty, withText);
97
+ expect(contentTypesOf(result)).toEqual(new Set(['audio', 'video']));
92
98
  });
93
99
  });