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