@amazon/vinyl 3.0.0 → 3.1.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.
- package/dist/index.cjs +987 -969
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +665 -638
- package/dist/index.js.map +4 -4
- package/dist/test/benchmark.js.map +2 -2
- package/dist/test/integ.es5.js +357 -353
- package/dist/test/integ.js +2361 -1870
- package/dist/test/integ.js.map +4 -4
- package/dist/test/jasmine.css +50 -3
- package/dist/test/jasmineHtml.es5.js +195 -155
- package/dist/test/jasmineHtml.js +2938 -1833
- package/dist/test/jasmineHtml.js.map +3 -3
- package/dist/types/current/ad/AdControllerImpl.d.ts.map +1 -1
- package/dist/types/current/ad/AdControllerImpl.js +4 -1
- package/dist/types/current/ad/discoverHlsInterstitials.d.ts.map +1 -1
- package/dist/types/current/ad/discoverHlsInterstitials.js +2 -2
- package/dist/types/current/drm/DrmControllerImpl.d.ts +2 -0
- package/dist/types/current/drm/DrmControllerImpl.d.ts.map +1 -1
- package/dist/types/current/drm/DrmControllerImpl.js +56 -48
- package/dist/types/current/drm/licenseProvider/defaultLicenseProvider.d.ts.map +1 -1
- package/dist/types/current/drm/licenseProvider/defaultLicenseProvider.js +2 -2
- package/dist/types/current/index.d.ts +3 -6
- package/dist/types/current/index.d.ts.map +1 -1
- package/dist/types/current/index.js +3 -6
- package/dist/types/current/playback/PlaybackControllerImpl.d.ts +15 -0
- package/dist/types/current/playback/PlaybackControllerImpl.d.ts.map +1 -1
- package/dist/types/current/playback/PlaybackControllerImpl.js +100 -9
- package/dist/types/current/playback/ReadonlyPlaybackController.d.ts +27 -1
- package/dist/types/current/playback/ReadonlyPlaybackController.d.ts.map +1 -1
- package/dist/types/current/playback/ReadonlyPlaybackController.js +16 -0
- 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 +94 -0
- package/dist/types/current/streaming/AudioOptions.d.ts +27 -0
- package/dist/types/current/streaming/AudioOptions.d.ts.map +1 -1
- package/dist/types/current/streaming/AudioOptions.js +5 -1
- package/dist/types/current/streaming/ContentStream.d.ts +0 -5
- package/dist/types/current/streaming/ContentStream.d.ts.map +1 -1
- package/dist/types/current/streaming/ContentStream.js +0 -4
- package/dist/types/current/streaming/LoadMetric.d.ts.map +1 -1
- package/dist/types/current/streaming/StreamingEventMap.d.ts +1 -5
- package/dist/types/current/streaming/StreamingEventMap.d.ts.map +1 -1
- package/dist/types/current/streaming/StreamingEventMap.js +0 -1
- package/dist/types/current/streaming/buffering/BufferingController.d.ts +0 -11
- package/dist/types/current/streaming/buffering/BufferingController.d.ts.map +1 -1
- package/dist/types/current/streaming/buffering/BufferingController.js +0 -13
- package/dist/types/current/streaming/createDefaultMediaTimelineTransformer.d.ts.map +1 -1
- package/dist/types/current/streaming/createDefaultMediaTimelineTransformer.js +13 -4
- package/dist/types/current/text/SidecarTextTrackLoader.d.ts.map +1 -1
- package/dist/types/current/text/SidecarTextTrackLoader.js +4 -4
- package/dist/types/current/text/TextTrack.d.ts.map +1 -1
- package/dist/types/current/track/TrackController.d.ts.map +1 -1
- package/dist/types/current/track/TrackController.js +38 -32
- package/dist/types/current/track/createSegmentDataProvider.d.ts.map +1 -1
- package/dist/types/current/track/createSegmentDataProvider.js +6 -3
- package/dist/types/current/track/dash/DashMediaQualityMetadataResolver.d.ts +10 -6
- package/dist/types/current/track/dash/DashMediaQualityMetadataResolver.d.ts.map +1 -1
- package/dist/types/current/track/dash/DashMediaQualityMetadataResolver.js +13 -8
- package/dist/types/current/track/dash/createDashFactories.d.ts +1 -1
- package/dist/types/current/track/dash/timeline/DashRepresentationSegmentProvider.d.ts.map +1 -1
- package/dist/types/current/track/dash/timeline/DashRepresentationSegmentProvider.js +71 -3
- package/dist/types/current/track/dash/urlDashManifestProvider.js +2 -2
- package/dist/types/current/track/dash/util/mpd.d.ts +6 -0
- package/dist/types/current/track/dash/util/mpd.d.ts.map +1 -1
- package/dist/types/current/track/dash/util/mpd.js +24 -3
- package/dist/types/current/track/filters/resourceTypeFilter.d.ts +4 -0
- package/dist/types/current/track/filters/resourceTypeFilter.d.ts.map +1 -1
- package/dist/types/current/track/filters/resourceTypeFilter.js +4 -0
- package/dist/types/current/track/filters/sampleRateFilter.d.ts +21 -7
- package/dist/types/current/track/filters/sampleRateFilter.d.ts.map +1 -1
- package/dist/types/current/track/filters/sampleRateFilter.js +42 -24
- package/dist/types/current/track/hls/createHlsFactories.d.ts +1 -1
- package/dist/types/current/track/hls/createUrlHlsManifestProvider.d.ts.map +1 -1
- package/dist/types/current/track/hls/createUrlHlsManifestProvider.js +3 -3
- package/dist/types/current/track/mse/MseTrack.d.ts +9 -17
- package/dist/types/current/track/mse/MseTrack.d.ts.map +1 -1
- package/dist/types/current/track/mse/MseTrack.js +29 -46
- package/dist/types/current/tsconfig.tsbuildinfo +1 -1
- 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/current/vinyl/createVinylFactories.d.ts +7 -16
- package/dist/types/current/vinyl/createVinylFactories.d.ts.map +1 -1
- package/dist/types/current/vinyl/createVinylFactories.js +2 -12
- package/dist/types/ts3.7/drm/DrmControllerImpl.d.ts +2 -0
- package/dist/types/ts3.7/index.d.ts +3 -6
- package/dist/types/ts3.7/playback/PlaybackControllerImpl.d.ts +15 -0
- package/dist/types/ts3.7/playback/ReadonlyPlaybackController.d.ts +28 -0
- 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 +27 -0
- package/dist/types/ts3.7/streaming/ContentStream.d.ts +0 -5
- package/dist/types/ts3.7/streaming/StreamingEventMap.d.ts +0 -5
- package/dist/types/ts3.7/streaming/buffering/BufferingController.d.ts +0 -11
- package/dist/types/ts3.7/track/dash/DashMediaQualityMetadataResolver.d.ts +10 -6
- package/dist/types/ts3.7/track/dash/createDashFactories.d.ts +1 -1
- package/dist/types/ts3.7/track/dash/util/mpd.d.ts +6 -0
- package/dist/types/ts3.7/track/filters/resourceTypeFilter.d.ts +4 -0
- package/dist/types/ts3.7/track/filters/sampleRateFilter.d.ts +21 -7
- package/dist/types/ts3.7/track/hls/createHlsFactories.d.ts +1 -1
- package/dist/types/ts3.7/track/mse/MseTrack.d.ts +9 -17
- package/dist/types/ts3.7/util/media/mimeType.d.ts +8 -0
- package/dist/types/ts3.7/vinyl/createVinylFactories.d.ts +7 -16
- package/dist/types/ts4.1/drm/DrmControllerImpl.d.ts +2 -0
- package/dist/types/ts4.1/index.d.ts +3 -6
- package/dist/types/ts4.1/playback/PlaybackControllerImpl.d.ts +15 -0
- package/dist/types/ts4.1/playback/ReadonlyPlaybackController.d.ts +28 -0
- 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 +27 -0
- package/dist/types/ts4.1/streaming/ContentStream.d.ts +0 -5
- package/dist/types/ts4.1/streaming/StreamingEventMap.d.ts +0 -5
- package/dist/types/ts4.1/streaming/buffering/BufferingController.d.ts +0 -11
- package/dist/types/ts4.1/track/dash/DashMediaQualityMetadataResolver.d.ts +10 -6
- package/dist/types/ts4.1/track/dash/createDashFactories.d.ts +1 -1
- package/dist/types/ts4.1/track/dash/util/mpd.d.ts +6 -0
- package/dist/types/ts4.1/track/filters/resourceTypeFilter.d.ts +4 -0
- package/dist/types/ts4.1/track/filters/sampleRateFilter.d.ts +21 -7
- package/dist/types/ts4.1/track/hls/createHlsFactories.d.ts +1 -1
- package/dist/types/ts4.1/track/mse/MseTrack.d.ts +9 -17
- package/dist/types/ts4.1/util/media/mimeType.d.ts +8 -0
- package/dist/types/ts4.1/vinyl/createVinylFactories.d.ts +7 -16
- package/dist/types/ts4.7/drm/DrmControllerImpl.d.ts +2 -0
- package/dist/types/ts4.7/index.d.ts +3 -6
- package/dist/types/ts4.7/playback/PlaybackControllerImpl.d.ts +15 -0
- package/dist/types/ts4.7/playback/ReadonlyPlaybackController.d.ts +28 -0
- 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 +27 -0
- package/dist/types/ts4.7/streaming/ContentStream.d.ts +0 -5
- package/dist/types/ts4.7/streaming/StreamingEventMap.d.ts +0 -5
- package/dist/types/ts4.7/streaming/buffering/BufferingController.d.ts +0 -11
- package/dist/types/ts4.7/track/dash/DashMediaQualityMetadataResolver.d.ts +10 -6
- package/dist/types/ts4.7/track/dash/createDashFactories.d.ts +1 -1
- package/dist/types/ts4.7/track/dash/util/mpd.d.ts +6 -0
- package/dist/types/ts4.7/track/filters/resourceTypeFilter.d.ts +4 -0
- package/dist/types/ts4.7/track/filters/sampleRateFilter.d.ts +21 -7
- package/dist/types/ts4.7/track/hls/createHlsFactories.d.ts +1 -1
- package/dist/types/ts4.7/track/mse/MseTrack.d.ts +9 -17
- package/dist/types/ts4.7/util/media/mimeType.d.ts +8 -0
- package/dist/types/ts4.7/vinyl/createVinylFactories.d.ts +7 -16
- package/dist/unit/types/current/ad/AdControllerImpl.test.js +27 -1
- package/dist/unit/types/current/drm/DrmControllerImpl.test.js +93 -0
- package/dist/unit/types/current/index.d.ts +3 -4
- package/dist/unit/types/current/index.d.ts.map +1 -1
- package/dist/unit/types/current/index.js +3 -4
- package/dist/unit/types/current/playback/PlaybackControllerImpl.test.js +165 -0
- 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 +125 -0
- package/dist/unit/types/current/streaming/ContentStream.test.js +0 -11
- package/dist/unit/types/current/streaming/MseTrack.test.js +47 -74
- package/dist/unit/types/current/streaming/abr/QualitySelectorImpl.test.js +1 -1
- package/dist/unit/types/current/streaming/buffering/BufferingController.test.js +0 -21
- package/dist/unit/types/current/streaming/createDefaultMediaTimelineTransformer.test.js +133 -0
- package/dist/unit/types/current/track/TrackController.test.js +97 -1
- package/dist/unit/types/current/track/createSegmentDataProvider.test.js +18 -0
- package/dist/unit/types/current/track/dash/DashMediaQualityMetadataResolver.test.js +46 -14
- package/dist/unit/types/current/track/dash/createSegmentControllerFactory.test.js +1 -0
- package/dist/unit/types/current/track/dash/timeline/DashRepresentationSegmentProvider.test.js +114 -0
- package/dist/unit/types/current/track/dash/util/mpd.test.js +37 -0
- package/dist/unit/types/current/track/filters/resourceTypeFilter.test.js +7 -0
- package/dist/unit/types/current/track/filters/sampleRateFilter.test.js +136 -34
- package/dist/unit/types/current/track/source/SourceObjectTrack.test.js +1 -1
- package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -1
- 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/createVinylFactories.test.js +2 -36
- package/dist/vinylTestUtil/index.js +6 -4
- package/dist/vinylTestUtil/index.js.map +2 -2
- package/dist/vinylTestUtil/types/current/assets/vinylTestAssets.d.ts +1 -0
- package/dist/vinylTestUtil/types/current/assets/vinylTestAssets.d.ts.map +1 -1
- package/dist/vinylTestUtil/types/current/assets/vinylTestAssets.js +1 -0
- package/dist/vinylTestUtil/types/current/media/FrequencyAnalyzer.d.ts.map +1 -1
- package/dist/vinylTestUtil/types/current/mock/streaming/MockContentStream.d.ts +0 -1
- package/dist/vinylTestUtil/types/current/mock/streaming/MockContentStream.d.ts.map +1 -1
- package/dist/vinylTestUtil/types/current/mock/streaming/MockContentStream.js +0 -1
- package/dist/vinylTestUtil/types/current/mock/streaming/buffering/MockBufferingController.d.ts +0 -1
- package/dist/vinylTestUtil/types/current/mock/streaming/buffering/MockBufferingController.d.ts.map +1 -1
- package/dist/vinylTestUtil/types/current/mock/streaming/buffering/MockBufferingController.js +0 -1
- package/dist/vinylTestUtil/types/current/tsconfig.tsbuildinfo +1 -1
- package/dist/vinylTestUtil/types/current/util/playback/eventPromises.js +1 -1
- package/dist/vinylTestUtil/types/current/util/playback/expectTrackCanSeek.d.ts.map +1 -1
- package/dist/vinylTestUtil/types/current/util/playback/expectTrackCanSeek.js +9 -1
- package/dist/vinylTestUtil/types/ts3.7/assets/vinylTestAssets.d.ts +1 -0
- package/dist/vinylTestUtil/types/ts3.7/mock/streaming/MockContentStream.d.ts +0 -1
- package/dist/vinylTestUtil/types/ts3.7/mock/streaming/buffering/MockBufferingController.d.ts +0 -1
- package/dist/vinylTestUtil/types/ts4.1/assets/vinylTestAssets.d.ts +1 -0
- package/dist/vinylTestUtil/types/ts4.1/mock/streaming/MockContentStream.d.ts +0 -1
- package/dist/vinylTestUtil/types/ts4.1/mock/streaming/buffering/MockBufferingController.d.ts +0 -1
- package/dist/vinylTestUtil/types/ts4.7/assets/vinylTestAssets.d.ts +1 -0
- package/dist/vinylTestUtil/types/ts4.7/mock/streaming/MockContentStream.d.ts +0 -1
- package/dist/vinylTestUtil/types/ts4.7/mock/streaming/buffering/MockBufferingController.d.ts +0 -1
- package/docs/USAGE.md +29 -0
- package/package.json +11 -10
- package/dist/types/current/patch/media/HtmlMediaElementPatch.d.ts +0 -3
- package/dist/types/current/patch/media/HtmlMediaElementPatch.d.ts.map +0 -1
- package/dist/types/current/patch/media/HtmlMediaElementPatch.js +0 -5
- package/dist/types/current/patch/media/MediaElementPatchOptions.d.ts +0 -19
- package/dist/types/current/patch/media/MediaElementPatchOptions.d.ts.map +0 -1
- package/dist/types/current/patch/media/MediaElementPatchOptions.js +0 -16
- package/dist/types/current/patch/media/patchMediaElement.d.ts +0 -9
- package/dist/types/current/patch/media/patchMediaElement.d.ts.map +0 -1
- package/dist/types/current/patch/media/patchMediaElement.js +0 -15
- package/dist/types/current/patch/media/patches/createPreventStallsPatch.d.ts +0 -17
- package/dist/types/current/patch/media/patches/createPreventStallsPatch.d.ts.map +0 -1
- package/dist/types/current/patch/media/patches/createPreventStallsPatch.js +0 -55
- package/dist/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.d.ts +0 -26
- package/dist/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.d.ts.map +0 -1
- package/dist/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.js +0 -218
- package/dist/types/current/vinyl/VinylPatchOptions.d.ts +0 -10
- package/dist/types/current/vinyl/VinylPatchOptions.d.ts.map +0 -1
- package/dist/types/current/vinyl/VinylPatchOptions.js +0 -11
- package/dist/types/ts3.7/patch/media/HtmlMediaElementPatch.d.ts +0 -3
- package/dist/types/ts3.7/patch/media/MediaElementPatchOptions.d.ts +0 -19
- package/dist/types/ts3.7/patch/media/patchMediaElement.d.ts +0 -9
- package/dist/types/ts3.7/patch/media/patches/createPreventStallsPatch.d.ts +0 -17
- package/dist/types/ts3.7/patch/media/patches/createUnreliablePlaybackEventsPatch.d.ts +0 -26
- package/dist/types/ts3.7/vinyl/VinylPatchOptions.d.ts +0 -10
- package/dist/types/ts4.1/patch/media/HtmlMediaElementPatch.d.ts +0 -3
- package/dist/types/ts4.1/patch/media/MediaElementPatchOptions.d.ts +0 -19
- package/dist/types/ts4.1/patch/media/patchMediaElement.d.ts +0 -9
- package/dist/types/ts4.1/patch/media/patches/createPreventStallsPatch.d.ts +0 -17
- package/dist/types/ts4.1/patch/media/patches/createUnreliablePlaybackEventsPatch.d.ts +0 -26
- package/dist/types/ts4.1/vinyl/VinylPatchOptions.d.ts +0 -10
- package/dist/types/ts4.7/patch/media/HtmlMediaElementPatch.d.ts +0 -3
- package/dist/types/ts4.7/patch/media/MediaElementPatchOptions.d.ts +0 -19
- package/dist/types/ts4.7/patch/media/patchMediaElement.d.ts +0 -9
- package/dist/types/ts4.7/patch/media/patches/createPreventStallsPatch.d.ts +0 -17
- package/dist/types/ts4.7/patch/media/patches/createUnreliablePlaybackEventsPatch.d.ts +0 -26
- package/dist/types/ts4.7/vinyl/VinylPatchOptions.d.ts +0 -10
- package/dist/unit/types/current/patch/media/MediaElementPatchOptions.test.d.ts +0 -2
- package/dist/unit/types/current/patch/media/MediaElementPatchOptions.test.d.ts.map +0 -1
- package/dist/unit/types/current/patch/media/MediaElementPatchOptions.test.js +0 -17
- package/dist/unit/types/current/patch/media/patchMediaElement.test.d.ts +0 -2
- package/dist/unit/types/current/patch/media/patchMediaElement.test.d.ts.map +0 -1
- package/dist/unit/types/current/patch/media/patchMediaElement.test.js +0 -36
- package/dist/unit/types/current/patch/media/patches/createPreventStallsPatch.test.d.ts +0 -2
- package/dist/unit/types/current/patch/media/patches/createPreventStallsPatch.test.d.ts.map +0 -1
- package/dist/unit/types/current/patch/media/patches/createPreventStallsPatch.test.js +0 -93
- package/dist/unit/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.test.d.ts +0 -2
- package/dist/unit/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.test.d.ts.map +0 -1
- package/dist/unit/types/current/patch/media/patches/createUnreliablePlaybackEventsPatch.test.js +0 -423
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CapabilitiesImplDeps } from '../client/CapabilitiesImpl';
|
|
2
2
|
import { CapabilitiesImpl } from '../client/CapabilitiesImpl';
|
|
3
|
-
import type { Merge, PartialDeep
|
|
3
|
+
import type { Merge, PartialDeep } from '@amazon/vinyl-util';
|
|
4
4
|
import { noop } from '@amazon/vinyl-util';
|
|
5
5
|
import type { PlaybackControllerImplDeps, PlaybackControllerImplOptions } from '../playback/PlaybackControllerImpl';
|
|
6
6
|
import { PlaybackControllerImpl } from '../playback/PlaybackControllerImpl';
|
|
@@ -9,7 +9,6 @@ import { PlaybackSourceImpl } from '../playback/PlaybackSourceImpl';
|
|
|
9
9
|
import { type VinylTrackFactoryDeps } from '../track/createVinylTrackFactories';
|
|
10
10
|
import type { TrackControllerImplDeps, TrackControllerImplOptions } from '../track/TrackController';
|
|
11
11
|
import { TrackControllerImpl } from '../track/TrackController';
|
|
12
|
-
import type { VinylPatchOptions } from './VinylPatchOptions';
|
|
13
12
|
import { type QualitySelectorImplOptions } from '../streaming/abr/QualitySelectorImpl';
|
|
14
13
|
import { AdControllerImpl, type AdControllerImplDeps, type AdControllerImplOptions } from '../ad/AdControllerImpl';
|
|
15
14
|
import { type MediaTextTrackProvider } from '../text/mediaTextTrackProvider';
|
|
@@ -41,11 +40,6 @@ export interface VinylDependencyOptions {
|
|
|
41
40
|
* `'hidden'`; without one they render natively. See `TextTrackRenderer`.
|
|
42
41
|
*/
|
|
43
42
|
readonly textTrackRenderer?: TextTrackRenderer;
|
|
44
|
-
/**
|
|
45
|
-
* Flags for patches that should be applied browser-specifically.
|
|
46
|
-
* These will be defaulted based on the user-agent.
|
|
47
|
-
*/
|
|
48
|
-
readonly patches?: PartialDeep<VinylPatchOptions>;
|
|
49
43
|
/**
|
|
50
44
|
* Configuration for the track controller.
|
|
51
45
|
*/
|
|
@@ -82,12 +76,7 @@ export interface VinylDependencyOptions {
|
|
|
82
76
|
*/
|
|
83
77
|
export declare function createVinylFactories(options: VinylDependencyOptions): {
|
|
84
78
|
options: (_deps: import("@amazon/vinyl-util").AnyRecord, add: import("@amazon/vinyl-util").AddDisposable) => import("@amazon/vinyl-observable").MutableValue<VinylOptions>;
|
|
85
|
-
|
|
86
|
-
media: (deps: {
|
|
87
|
-
readonly patchedMedia: {
|
|
88
|
-
readonly patched: HTMLMediaElement;
|
|
89
|
-
};
|
|
90
|
-
}) => HTMLMediaElement;
|
|
79
|
+
media: () => HTMLMediaElement;
|
|
91
80
|
textTrackProvider: (deps: {
|
|
92
81
|
readonly media: HTMLMediaElement;
|
|
93
82
|
}) => MediaTextTrackProvider;
|
|
@@ -153,7 +142,7 @@ export declare function createVinylFactories(options: VinylDependencyOptions): {
|
|
|
153
142
|
readonly manifestTransformed: ObservableValue<Promise<import("..").DashManifestData>>;
|
|
154
143
|
readonly options: ObservableValue<Pick<VinylOptions, "text">>;
|
|
155
144
|
}) => import("..").SidecarTextTrackController;
|
|
156
|
-
options: import("@amazon/vinyl-di").Factory<ObservableValue<Pick<VinylOptions, "
|
|
145
|
+
options: import("@amazon/vinyl-di").Factory<ObservableValue<Pick<VinylOptions, "text" | "audio" | "abr" | "allowedContentTypes">>>;
|
|
157
146
|
playbackController: import("@amazon/vinyl-di").Factory<import("..").PlaybackController>;
|
|
158
147
|
playbackSource: import("@amazon/vinyl-di").Factory<import("..").PlaybackSource>;
|
|
159
148
|
drmKeySystemResolver: import("@amazon/vinyl-di").Factory<import("..").DrmKeySystemResolver>;
|
|
@@ -165,7 +154,9 @@ export declare function createVinylFactories(options: VinylDependencyOptions): {
|
|
|
165
154
|
textTrackRenderer: import("@amazon/vinyl-di").Factory<TextTrackRenderer | null>;
|
|
166
155
|
adController: import("@amazon/vinyl-di").Factory<import("..").AdController>;
|
|
167
156
|
};
|
|
168
|
-
createHlsFactories: (deps: import("..").HlsFactoryDeps) => (loadOptions: import("..").HlsTrackLoadOptions
|
|
157
|
+
createHlsFactories: (deps: import("..").HlsFactoryDeps) => (loadOptions: import("..").HlsTrackLoadOptions /**
|
|
158
|
+
* Configuration for adaptive bitrate switching.
|
|
159
|
+
*/) => {
|
|
169
160
|
baseContentTypesValue: typeof import("..").createHlsContentTypesValue;
|
|
170
161
|
contentTypesValue: typeof import("..").createAllowedContentTypesValue;
|
|
171
162
|
manifestProvider: () => import("..").HlsManifestProvider;
|
|
@@ -208,7 +199,7 @@ export declare function createVinylFactories(options: VinylDependencyOptions): {
|
|
|
208
199
|
readonly manifestTransformed: ObservableValue<Promise<import("..").HlsManifestData>>;
|
|
209
200
|
readonly options: ObservableValue<Pick<VinylOptions, "text">>;
|
|
210
201
|
}) => import("..").SidecarTextTrackController;
|
|
211
|
-
options: import("@amazon/vinyl-di").Factory<ObservableValue<Pick<VinylOptions, "
|
|
202
|
+
options: import("@amazon/vinyl-di").Factory<ObservableValue<Pick<VinylOptions, "text" | "audio" | "abr" | "allowedContentTypes">>>;
|
|
212
203
|
playbackController: import("@amazon/vinyl-di").Factory<import("..").PlaybackController>;
|
|
213
204
|
playbackSource: import("@amazon/vinyl-di").Factory<import("..").PlaybackSource>;
|
|
214
205
|
drmKeySystemResolver: import("@amazon/vinyl-di").Factory<import("..").DrmKeySystemResolver>;
|
|
@@ -6,11 +6,22 @@ import { AdControllerImpl } from '@amazon/vinyl';
|
|
|
6
6
|
import { MockPlaybackController, MockTrack } from '@amazon/vinyl/vinylTestUtil';
|
|
7
7
|
describe('AdControllerImpl', () => {
|
|
8
8
|
let playbackController;
|
|
9
|
+
let controllers;
|
|
9
10
|
beforeEach(() => {
|
|
10
11
|
playbackController = new MockPlaybackController();
|
|
12
|
+
controllers = [];
|
|
13
|
+
});
|
|
14
|
+
// Dispose every controller a spec created. An activated-but-unstarted ad
|
|
15
|
+
// arms a `sleep(adLoadTimeout)` timer.
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
for (const c of controllers)
|
|
18
|
+
if (!c.disposed)
|
|
19
|
+
c.dispose();
|
|
11
20
|
});
|
|
12
21
|
function createController() {
|
|
13
|
-
|
|
22
|
+
const c = new AdControllerImpl({ playbackController });
|
|
23
|
+
controllers.push(c);
|
|
24
|
+
return c;
|
|
14
25
|
}
|
|
15
26
|
function updateTime(time) {
|
|
16
27
|
playbackController.currentTime = time;
|
|
@@ -301,6 +312,21 @@ describe('AdControllerImpl', () => {
|
|
|
301
312
|
await flush();
|
|
302
313
|
expect(c.currentAdBreak).toBeNull();
|
|
303
314
|
});
|
|
315
|
+
it('ignores a late provider ad-discovery resolution after dispose', async () => {
|
|
316
|
+
const c = createController();
|
|
317
|
+
let resolveAds = () => { };
|
|
318
|
+
const track = new MockTrack();
|
|
319
|
+
track.uri = 't1';
|
|
320
|
+
track.active = true;
|
|
321
|
+
track.getAds = () => new Promise((res) => {
|
|
322
|
+
resolveAds = res;
|
|
323
|
+
});
|
|
324
|
+
c.setAdsProvider(track); // refreshAds() runs; getAds() stays pending
|
|
325
|
+
c.dispose();
|
|
326
|
+
resolveAds(trackAds(makeBreak())); // refreshAds .then: interrupted (disposed)
|
|
327
|
+
await flush();
|
|
328
|
+
expect(c.currentTrackAds).toBeNull();
|
|
329
|
+
});
|
|
304
330
|
});
|
|
305
331
|
it('emits currentTrackAdsChange with the TrackAds when a parent track is set', async () => {
|
|
306
332
|
const c = createController();
|
|
@@ -389,6 +389,58 @@ describe('DrmControllerImpl', () => {
|
|
|
389
389
|
expect(errorSpy).not.toHaveBeenCalled();
|
|
390
390
|
expect(mediaKeys.createSession).toHaveBeenCalledTimes(1); // reused
|
|
391
391
|
});
|
|
392
|
+
it('reuses the session when a transformer alters the CDM init data', async () => {
|
|
393
|
+
// A non-identity initDataTransformer changes the bytes handed to the
|
|
394
|
+
// CDM (always the case for FairPlay, or any custom transformer). The
|
|
395
|
+
// reuse check must compare the ORIGINAL init data, not the
|
|
396
|
+
// transformed bytes — otherwise every re-appended init segment fires
|
|
397
|
+
// `encrypted` and spins up a brand-new session instead of recycling.
|
|
398
|
+
const transformed = new Uint8Array([9, 9, 9]);
|
|
399
|
+
const controller = new DrmControllerImpl(deps, {
|
|
400
|
+
licenseProvider,
|
|
401
|
+
keySystems: {
|
|
402
|
+
[DrmKeySystem.WIDEVINE]: {
|
|
403
|
+
initDataTransformer: () => transformed,
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
});
|
|
407
|
+
const localErrors = createEventSpy(controller, 'error');
|
|
408
|
+
const encryptedCb = commonEme.addEncryptedListener.calls.mostRecent().args[1];
|
|
409
|
+
controller.setBufferingDrmInfo(drmInfo);
|
|
410
|
+
encryptedCb({
|
|
411
|
+
initData: new Uint8Array([1, 2, 3]),
|
|
412
|
+
initDataType: 'cenc',
|
|
413
|
+
});
|
|
414
|
+
await flushPromises();
|
|
415
|
+
expect(mediaKeys.createSession).toHaveBeenCalledTimes(1);
|
|
416
|
+
// The session stored the transformed bytes handed to the CDM.
|
|
417
|
+
expect(getSession(0).initData).toEqual(transformed);
|
|
418
|
+
// The same raw init data fires again (e.g. a quality switch
|
|
419
|
+
// re-appends the init segment) — the session must be reused.
|
|
420
|
+
encryptedCb({
|
|
421
|
+
initData: new Uint8Array([1, 2, 3]),
|
|
422
|
+
initDataType: 'cenc',
|
|
423
|
+
});
|
|
424
|
+
await flushPromises();
|
|
425
|
+
expect(localErrors).not.toHaveBeenCalled();
|
|
426
|
+
expect(mediaKeys.createSession).toHaveBeenCalledTimes(1); // reused
|
|
427
|
+
controller.dispose();
|
|
428
|
+
});
|
|
429
|
+
it('ignores encrypted events when the manifest supplies pssh', async () => {
|
|
430
|
+
// The proactive manifest-pssh path owns session creation, so in-band
|
|
431
|
+
// `encrypted` events (e.g. a re-appended init segment on an ABR
|
|
432
|
+
// switch) must not spawn a duplicate session.
|
|
433
|
+
const drmInfoWithPssh = {
|
|
434
|
+
...drmInfo,
|
|
435
|
+
contentProtections: [
|
|
436
|
+
{ keySystem: DrmKeySystem.WIDEVINE, pssh: 'AAAA' },
|
|
437
|
+
],
|
|
438
|
+
};
|
|
439
|
+
drmController.setBufferingDrmInfo(drmInfoWithPssh);
|
|
440
|
+
await emitEncrypted(new Uint8Array([1, 2, 3]));
|
|
441
|
+
expect(errorSpy).not.toHaveBeenCalled();
|
|
442
|
+
expect(mediaKeys.createSession).not.toHaveBeenCalled();
|
|
443
|
+
});
|
|
392
444
|
describe('and the drm controller is disposed', () => {
|
|
393
445
|
it('does nothing', async () => {
|
|
394
446
|
drmController.dispose();
|
|
@@ -613,6 +665,29 @@ describe('DrmControllerImpl', () => {
|
|
|
613
665
|
});
|
|
614
666
|
});
|
|
615
667
|
describe('when a session message event is observed', () => {
|
|
668
|
+
it('does not update the session when disposed before the license resolves', async () => {
|
|
669
|
+
let resolveLicense = () => { };
|
|
670
|
+
licenseProvider.and.returnValue(new Promise((res) => {
|
|
671
|
+
resolveLicense = res;
|
|
672
|
+
}));
|
|
673
|
+
drmController = new DrmControllerImpl(deps, {
|
|
674
|
+
keySystems: {
|
|
675
|
+
[DrmKeySystem.WIDEVINE]: {
|
|
676
|
+
licenseServer: { url: 'http://example.com/widevine' },
|
|
677
|
+
},
|
|
678
|
+
},
|
|
679
|
+
licenseProvider,
|
|
680
|
+
});
|
|
681
|
+
drmController.setBufferingDrmInfo(drmInfo);
|
|
682
|
+
await emitEncrypted(new Uint8Array([1, 2, 3]), 'cenc');
|
|
683
|
+
getSession(0).dispatch('message', { message: new ArrayBuffer(1) });
|
|
684
|
+
await flushPromises();
|
|
685
|
+
// License in flight — dispose, then let it resolve.
|
|
686
|
+
drmController.dispose();
|
|
687
|
+
resolveLicense(new ArrayBuffer(2));
|
|
688
|
+
await flushPromises();
|
|
689
|
+
expect(getSession(0).update).not.toHaveBeenCalled();
|
|
690
|
+
});
|
|
616
691
|
it('calls the licenseProvider with resolved licenseServer options', async () => {
|
|
617
692
|
drmController = new DrmControllerImpl(deps, {
|
|
618
693
|
keySystems: {
|
|
@@ -666,6 +741,24 @@ describe('DrmControllerImpl', () => {
|
|
|
666
741
|
}, message);
|
|
667
742
|
}
|
|
668
743
|
});
|
|
744
|
+
it('falls back to the wildcard key system license server', async () => {
|
|
745
|
+
drmController = new DrmControllerImpl(deps, {
|
|
746
|
+
keySystems: {
|
|
747
|
+
// Only a wildcard entry — no per-key-system configuration.
|
|
748
|
+
'*': {
|
|
749
|
+
licenseServer: () => ({
|
|
750
|
+
url: 'http://example.com/wildcard',
|
|
751
|
+
}),
|
|
752
|
+
},
|
|
753
|
+
},
|
|
754
|
+
licenseProvider,
|
|
755
|
+
});
|
|
756
|
+
drmController.setBufferingDrmInfo(drmInfo);
|
|
757
|
+
await emitEncrypted(new Uint8Array([1, 2, 3]), 'cenc');
|
|
758
|
+
const message = new ArrayBuffer(1);
|
|
759
|
+
await emitMessage(0, message);
|
|
760
|
+
expect(licenseProvider).toHaveBeenCalledOnceWith(DrmKeySystem.WIDEVINE, { url: 'http://example.com/wildcard' }, message);
|
|
761
|
+
});
|
|
669
762
|
describe('when license takes too long to resolve', () => {
|
|
670
763
|
it('emits an error event', async () => {
|
|
671
764
|
drmController = new DrmControllerImpl(deps, {
|
|
@@ -25,10 +25,8 @@ import './global/configureVinylGlobal.test';
|
|
|
25
25
|
import './global/environment.test';
|
|
26
26
|
import './global/globalRef.test';
|
|
27
27
|
import './global/PlayerRegistry.test';
|
|
28
|
-
import './
|
|
29
|
-
import './
|
|
30
|
-
import './patch/media/patches/createUnreliablePlaybackEventsPatch.test';
|
|
31
|
-
import './patch/media/patchMediaElement.test';
|
|
28
|
+
import './playback/createStallDetector.test';
|
|
29
|
+
import './playback/createStallMonitor.test';
|
|
32
30
|
import './playback/error/InvalidSeekError.test';
|
|
33
31
|
import './playback/error/ReportableMediaError.test';
|
|
34
32
|
import './playback/logging/mediaErrorToJson.test';
|
|
@@ -116,6 +114,7 @@ import './util/media/codecOverrides.test';
|
|
|
116
114
|
import './util/media/codecSupport.test';
|
|
117
115
|
import './util/media/getAudioContext.test';
|
|
118
116
|
import './util/media/mediaSource.test';
|
|
117
|
+
import './util/media/mimeType.test';
|
|
119
118
|
import './util/media/sourceBuffer.test';
|
|
120
119
|
import './vinyl/createVinylFactories.test';
|
|
121
120
|
import './vinyl/playerConfigFactory.test';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../test/unit/index.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,OAAO,wBAAwB,CAAA;AAC/B,OAAO,4BAA4B,CAAA;AACnC,OAAO,wCAAwC,CAAA;AAC/C,OAAO,oCAAoC,CAAA;AAC3C,OAAO,gCAAgC,CAAA;AACvC,cAAc,0CAA0C,CAAA;AACxD,OAAO,iCAAiC,CAAA;AACxC,OAAO,gCAAgC,CAAA;AACvC,OAAO,4CAA4C,CAAA;AACnD,OAAO,kCAAkC,CAAA;AACzC,OAAO,wCAAwC,CAAA;AAC/C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,6BAA6B,CAAA;AACpC,OAAO,8BAA8B,CAAA;AACrC,OAAO,yBAAyB,CAAA;AAChC,OAAO,iCAAiC,CAAA;AACxC,OAAO,2BAA2B,CAAA;AAClC,OAAO,mDAAmD,CAAA;AAC1D,OAAO,+CAA+C,CAAA;AACtD,OAAO,kCAAkC,CAAA;AACzC,OAAO,0CAA0C,CAAA;AACjD,OAAO,0BAA0B,CAAA;AACjC,OAAO,oCAAoC,CAAA;AAC3C,OAAO,2BAA2B,CAAA;AAClC,OAAO,yBAAyB,CAAA;AAChC,OAAO,8BAA8B,CAAA;AACrC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../test/unit/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,10 +25,8 @@ import './global/configureVinylGlobal.test';
|
|
|
25
25
|
import './global/environment.test';
|
|
26
26
|
import './global/globalRef.test';
|
|
27
27
|
import './global/PlayerRegistry.test';
|
|
28
|
-
import './
|
|
29
|
-
import './
|
|
30
|
-
import './patch/media/patches/createUnreliablePlaybackEventsPatch.test';
|
|
31
|
-
import './patch/media/patchMediaElement.test';
|
|
28
|
+
import './playback/createStallDetector.test';
|
|
29
|
+
import './playback/createStallMonitor.test';
|
|
32
30
|
import './playback/error/InvalidSeekError.test';
|
|
33
31
|
import './playback/error/ReportableMediaError.test';
|
|
34
32
|
import './playback/logging/mediaErrorToJson.test';
|
|
@@ -116,6 +114,7 @@ import './util/media/codecOverrides.test';
|
|
|
116
114
|
import './util/media/codecSupport.test';
|
|
117
115
|
import './util/media/getAudioContext.test';
|
|
118
116
|
import './util/media/mediaSource.test';
|
|
117
|
+
import './util/media/mimeType.test';
|
|
119
118
|
import './util/media/sourceBuffer.test';
|
|
120
119
|
import './vinyl/createVinylFactories.test';
|
|
121
120
|
import './vinyl/playerConfigFactory.test';
|
|
@@ -78,6 +78,29 @@ describe('PlaybackController', () => {
|
|
|
78
78
|
if (!controller.disposed)
|
|
79
79
|
controller.dispose();
|
|
80
80
|
});
|
|
81
|
+
describe('stall detection', () => {
|
|
82
|
+
it('does not emit stallEntered before playback is observed', async () => {
|
|
83
|
+
const enteredSpy = createEventSpy(controller, 'stallEntered');
|
|
84
|
+
await clock.tick(2);
|
|
85
|
+
expect(enteredSpy).not.toHaveBeenCalled();
|
|
86
|
+
});
|
|
87
|
+
it('emits stallEntered when the play head freezes while playing and stallEnded on resume', async () => {
|
|
88
|
+
const enteredSpy = createEventSpy(controller, 'stallEntered');
|
|
89
|
+
const endedSpy = createEventSpy(controller, 'stallEnded');
|
|
90
|
+
media.dispatchEvent(mockEvent('playing'));
|
|
91
|
+
media.currentTime = 1;
|
|
92
|
+
media.dispatchEvent(mockEvent('timeupdate'));
|
|
93
|
+
// Frozen for the 1s default threshold.
|
|
94
|
+
await clock.tick(1);
|
|
95
|
+
expect(enteredSpy).toHaveBeenCalledTimes(1);
|
|
96
|
+
expect(endedSpy).not.toHaveBeenCalled();
|
|
97
|
+
// Play head advances -> stall ends with reason 'playing'.
|
|
98
|
+
media.currentTime = 2;
|
|
99
|
+
media.dispatchEvent(mockEvent('timeupdate'));
|
|
100
|
+
expect(endedSpy).toHaveBeenCalledTimes(1);
|
|
101
|
+
expect(endedSpy.calls.mostRecent().args[0].reason).toBe('playing');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
81
104
|
it('assigns properties, methods, and events directly to a media object', () => {
|
|
82
105
|
expect(controller.buffered).toBeInstanceOf(ReadonlyRangesImpl);
|
|
83
106
|
testDelegate(controller, 'currentTime', 2);
|
|
@@ -191,6 +214,135 @@ describe('PlaybackController', () => {
|
|
|
191
214
|
},
|
|
192
215
|
});
|
|
193
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Simulates WebKit reverting a seek: the first `revertCount`
|
|
219
|
+
* seeks land at `revertTo` instead of the requested time; later
|
|
220
|
+
* seeks land on the requested time.
|
|
221
|
+
*/
|
|
222
|
+
function enableSeekWithReverts(revertTo, revertCount) {
|
|
223
|
+
let currentTime = 0;
|
|
224
|
+
let reverts = revertCount;
|
|
225
|
+
Object.defineProperty(media, 'currentTime', {
|
|
226
|
+
get() {
|
|
227
|
+
return currentTime;
|
|
228
|
+
},
|
|
229
|
+
set(value) {
|
|
230
|
+
currentTime = reverts-- > 0 ? revertTo : value;
|
|
231
|
+
media.dispatchEvent(mockEvent('seeking'));
|
|
232
|
+
void (async () => {
|
|
233
|
+
await flushPromises();
|
|
234
|
+
media.dispatchEvent(mockEvent('seeked'));
|
|
235
|
+
})();
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Simulates a WebKit cold-seek stall: `seeking` fires but
|
|
241
|
+
* `seeked` does not for the first `stuckAttempts` attempts, then
|
|
242
|
+
* completes.
|
|
243
|
+
*/
|
|
244
|
+
function enableStuckSeek(stuckAttempts) {
|
|
245
|
+
let currentTime = 0;
|
|
246
|
+
let attempt = 0;
|
|
247
|
+
Object.defineProperty(media, 'currentTime', {
|
|
248
|
+
get() {
|
|
249
|
+
return currentTime;
|
|
250
|
+
},
|
|
251
|
+
set(value) {
|
|
252
|
+
currentTime = value;
|
|
253
|
+
media.dispatchEvent(mockEvent('seeking'));
|
|
254
|
+
if (attempt++ >= stuckAttempts) {
|
|
255
|
+
void (async () => {
|
|
256
|
+
await flushPromises();
|
|
257
|
+
media.dispatchEvent(mockEvent('seeked'));
|
|
258
|
+
})();
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
it('warms the decoder and retries when a seek stalls', async () => {
|
|
264
|
+
enableStuckSeek(1); // first attempt hangs, retry completes
|
|
265
|
+
setSeekable([[0, 30]]);
|
|
266
|
+
media.paused = false;
|
|
267
|
+
const seek = controller.seekTo(5);
|
|
268
|
+
// Flush to arm the first attempt's seeked timeout, then
|
|
269
|
+
// advance to fire it; the retry lands via its seeked event.
|
|
270
|
+
await clock.tick(0, 4);
|
|
271
|
+
await seek;
|
|
272
|
+
// Warmed the decoder with play(), then landed on retry.
|
|
273
|
+
expect(media.play).toHaveBeenCalled();
|
|
274
|
+
expect(media.currentTime).toBe(5);
|
|
275
|
+
});
|
|
276
|
+
it('gives up after the retry limit when a seek never completes', async () => {
|
|
277
|
+
enableStuckSeek(99); // never completes
|
|
278
|
+
setSeekable([[0, 30]]);
|
|
279
|
+
media.paused = false;
|
|
280
|
+
const seek = controller.seekTo(5);
|
|
281
|
+
// Leading flush arms the initial attempt's seeked timeout;
|
|
282
|
+
// each subsequent tick fires one and arms the next retry
|
|
283
|
+
// (initial + SEEK_RETRY_LIMIT attempts all time out).
|
|
284
|
+
await clock.tick(0, 4, 4, 4);
|
|
285
|
+
await seek;
|
|
286
|
+
expect(media.play).toHaveBeenCalled();
|
|
287
|
+
});
|
|
288
|
+
it('stops retrying when a re-seek never re-enters seeking', async () => {
|
|
289
|
+
let sets = 0;
|
|
290
|
+
let currentTime = 0;
|
|
291
|
+
Object.defineProperty(media, 'currentTime', {
|
|
292
|
+
get() {
|
|
293
|
+
return currentTime;
|
|
294
|
+
},
|
|
295
|
+
set(value) {
|
|
296
|
+
currentTime = value;
|
|
297
|
+
// Only the first attempt emits `seeking`; re-seeks to
|
|
298
|
+
// the same position stay silent (WebKit), so their
|
|
299
|
+
// seeking wait times out and returns null.
|
|
300
|
+
if (sets++ === 0) {
|
|
301
|
+
media.dispatchEvent(mockEvent('seeking'));
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
setSeekable([[0, 30]]);
|
|
306
|
+
media.paused = false;
|
|
307
|
+
const seek = controller.seekTo(5);
|
|
308
|
+
await clock.tick(0, 4, 4, 4);
|
|
309
|
+
await seek;
|
|
310
|
+
expect(media.currentTime).toBe(5);
|
|
311
|
+
});
|
|
312
|
+
it('rejects a seek disposed while awaiting seeked', async () => {
|
|
313
|
+
setSeekable([[0, 30]]);
|
|
314
|
+
media.paused = false;
|
|
315
|
+
const seek = controller.seekTo(5);
|
|
316
|
+
media.dispatchEvent(mockEvent('seeking'));
|
|
317
|
+
await flushPromises();
|
|
318
|
+
controller.dispose();
|
|
319
|
+
await expectAsync(seek).toBeRejectedWithError(AbortError);
|
|
320
|
+
});
|
|
321
|
+
it('re-seeks when WebKit lands the play head off target', async () => {
|
|
322
|
+
enableSeekWithReverts(20, 1);
|
|
323
|
+
setSeekable([[0, 30]]);
|
|
324
|
+
media.paused = true;
|
|
325
|
+
await controller.seekTo(5);
|
|
326
|
+
expect(media.currentTime).toBeCloseTo(5);
|
|
327
|
+
});
|
|
328
|
+
it('gives up re-seeking after the retry limit', async () => {
|
|
329
|
+
enableSeekWithReverts(20, 99);
|
|
330
|
+
setSeekable([[0, 30]]);
|
|
331
|
+
media.paused = true;
|
|
332
|
+
await controller.seekTo(5);
|
|
333
|
+
expect(media.currentTime).toBe(20);
|
|
334
|
+
});
|
|
335
|
+
it('stops re-seeking when a newer seek supersedes', async () => {
|
|
336
|
+
enableSeekWithReverts(20, 99);
|
|
337
|
+
setSeekable([[0, 30]]);
|
|
338
|
+
media.paused = true;
|
|
339
|
+
const first = controller.seekTo(5);
|
|
340
|
+
const second = controller.seekTo(9);
|
|
341
|
+
await Promise.allSettled([first, second]);
|
|
342
|
+
// Both landed at the reverted position; the first stopped
|
|
343
|
+
// re-seeking once superseded rather than fighting the newer.
|
|
344
|
+
expect(media.currentTime).toBe(20);
|
|
345
|
+
});
|
|
194
346
|
it('waits for metadata before initiating seek', async () => {
|
|
195
347
|
enableSeekAutoComplete();
|
|
196
348
|
const seeked = controller.seekTo(3);
|
|
@@ -199,6 +351,19 @@ describe('PlaybackController', () => {
|
|
|
199
351
|
await seeked;
|
|
200
352
|
expect(media.currentTime).toBe(3);
|
|
201
353
|
});
|
|
354
|
+
it('fabricates a playing event if playback resumes after a seek without one', async () => {
|
|
355
|
+
enableSeekAutoComplete();
|
|
356
|
+
setSeekable([[0, 10]]);
|
|
357
|
+
media.paused = false;
|
|
358
|
+
const playingSpy = createSpy('playing');
|
|
359
|
+
controller.on('playing', playingSpy);
|
|
360
|
+
await controller.seekTo(3);
|
|
361
|
+
// The play head advances but no 'playing' event fires; the
|
|
362
|
+
// post-seek stall detector fabricates one.
|
|
363
|
+
media.currentTime = 3.5;
|
|
364
|
+
await clock.tick(0.25);
|
|
365
|
+
expect(playingSpy).toHaveBeenCalled();
|
|
366
|
+
});
|
|
202
367
|
it('does not let a metadata-deferred seek clobber a newer seek', async () => {
|
|
203
368
|
// Reproduces the real race: the activate-time seek to the
|
|
204
369
|
// track start parks waiting for the `loadedmetadata` EVENT.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createStallDetector.test.d.ts","sourceRoot":"","sources":["../../../../../test/unit/playback/createStallDetector.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { createStallDetector } from '@amazon/vinyl';
|
|
6
|
+
import { implementEventFakes, MockHTMLAudioElement, mockEvent, MockTimeRanges, useMockTime, } from '@amazon/vinyl-util/browserTestUtil';
|
|
7
|
+
describe('createStallDetector', () => {
|
|
8
|
+
const clock = useMockTime();
|
|
9
|
+
let media;
|
|
10
|
+
let fabricatePlaying;
|
|
11
|
+
let stop;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
media = new MockHTMLAudioElement();
|
|
14
|
+
implementEventFakes(media);
|
|
15
|
+
media.play.and.returnValue(Promise.resolve());
|
|
16
|
+
media.paused = false;
|
|
17
|
+
media.ended = false;
|
|
18
|
+
media.readyState = media.HAVE_ENOUGH_DATA;
|
|
19
|
+
media.currentTime = 10;
|
|
20
|
+
media.buffered = new MockTimeRanges([[0, 100]]);
|
|
21
|
+
fabricatePlaying = jasmine.createSpy('fabricatePlaying');
|
|
22
|
+
});
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
stop?.();
|
|
25
|
+
});
|
|
26
|
+
function detect(overrides = {}) {
|
|
27
|
+
stop = createStallDetector(media, { fabricatePlaying, ...overrides });
|
|
28
|
+
}
|
|
29
|
+
/** Advances the mock clock by `n` default poll intervals. */
|
|
30
|
+
async function poll(n) {
|
|
31
|
+
for (let i = 0; i < n; i++) {
|
|
32
|
+
await clock.tick(0.25);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
describe('a stall inside ready buffered data', () => {
|
|
36
|
+
it('nudges the play head once frozen past the stall threshold', async () => {
|
|
37
|
+
detect();
|
|
38
|
+
// Threshold is 0.75s = three polls; the third nudges by stallSkip.
|
|
39
|
+
await poll(3);
|
|
40
|
+
expect(media.currentTime).toBeCloseTo(10.1);
|
|
41
|
+
});
|
|
42
|
+
it('does not recover before the stall threshold', async () => {
|
|
43
|
+
detect();
|
|
44
|
+
await poll(2);
|
|
45
|
+
expect(media.currentTime).toBe(10);
|
|
46
|
+
expect(media.play).not.toHaveBeenCalled();
|
|
47
|
+
});
|
|
48
|
+
it('nudges even when the ready state is low (iOS reports a stale readyState)', async () => {
|
|
49
|
+
media.readyState = media.HAVE_METADATA;
|
|
50
|
+
detect();
|
|
51
|
+
await poll(3);
|
|
52
|
+
expect(media.currentTime).toBeCloseTo(10.1);
|
|
53
|
+
expect(media.play).not.toHaveBeenCalled();
|
|
54
|
+
});
|
|
55
|
+
it('keeps nudging, then gives up after maxAttempts', async () => {
|
|
56
|
+
detect();
|
|
57
|
+
// Default maxAttempts is 3, so at most three nudges (one every 3 polls).
|
|
58
|
+
await poll(12);
|
|
59
|
+
expect(media.currentTime).toBeCloseTo(10.3);
|
|
60
|
+
// Further polls do nothing; the detector has stopped.
|
|
61
|
+
await poll(6);
|
|
62
|
+
expect(media.currentTime).toBeCloseTo(10.3);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('a stall with no data at the playhead', () => {
|
|
66
|
+
it('does not recover when the playhead is outside all buffered ranges', async () => {
|
|
67
|
+
media.buffered = new MockTimeRanges([[50, 100]]);
|
|
68
|
+
detect();
|
|
69
|
+
await poll(6);
|
|
70
|
+
expect(media.currentTime).toBe(10);
|
|
71
|
+
expect(fabricatePlaying).not.toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
it('does not recover at the end of buffered data', async () => {
|
|
74
|
+
// Within the default end margin (0.5s) of the buffer end.
|
|
75
|
+
media.buffered = new MockTimeRanges([[0, 10.3]]);
|
|
76
|
+
detect();
|
|
77
|
+
await poll(6);
|
|
78
|
+
expect(media.currentTime).toBe(10);
|
|
79
|
+
});
|
|
80
|
+
it('nudges at the end of the media (stuck end-of-track on src)', async () => {
|
|
81
|
+
// Buffer ends at the media duration: no more data is coming, so a
|
|
82
|
+
// freeze here is a stuck end-of-track and a nudge drives it to end.
|
|
83
|
+
media.buffered = new MockTimeRanges([[0, 10.3]]);
|
|
84
|
+
media.duration = 10.3;
|
|
85
|
+
detect();
|
|
86
|
+
await poll(3);
|
|
87
|
+
expect(media.currentTime).toBeCloseTo(10.1);
|
|
88
|
+
});
|
|
89
|
+
it('nudges outside buffered ranges when nudgeUnbuffered is set', async () => {
|
|
90
|
+
// WebKit path: re-issue the seek even though buffered looks empty.
|
|
91
|
+
media.buffered = new MockTimeRanges([[50, 100]]);
|
|
92
|
+
detect({ nudgeUnbuffered: true });
|
|
93
|
+
await poll(3);
|
|
94
|
+
expect(media.currentTime).toBeCloseTo(10.1);
|
|
95
|
+
});
|
|
96
|
+
it('stops when the source is emptied', async () => {
|
|
97
|
+
detect();
|
|
98
|
+
media.dispatchEvent(mockEvent('emptied'));
|
|
99
|
+
// Stopped: a later freeze in buffered data is not nudged.
|
|
100
|
+
await poll(6);
|
|
101
|
+
expect(media.currentTime).toBe(10);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
describe('fabricating a playing event', () => {
|
|
105
|
+
it('fabricates when the head progresses without a playing event', async () => {
|
|
106
|
+
detect();
|
|
107
|
+
media.currentTime = 20;
|
|
108
|
+
await poll(1);
|
|
109
|
+
expect(fabricatePlaying).toHaveBeenCalledTimes(1);
|
|
110
|
+
// Detector stopped; a later freeze is not recovered.
|
|
111
|
+
await poll(6);
|
|
112
|
+
expect(media.play).not.toHaveBeenCalled();
|
|
113
|
+
});
|
|
114
|
+
it('does not fabricate when a real playing event fired and it keeps progressing', async () => {
|
|
115
|
+
detect();
|
|
116
|
+
media.dispatchEvent(mockEvent('playing'));
|
|
117
|
+
media.currentTime = 20;
|
|
118
|
+
await poll(6);
|
|
119
|
+
expect(fabricatePlaying).not.toHaveBeenCalled();
|
|
120
|
+
});
|
|
121
|
+
it('fabricates after reviving a stall even if a playing event fired earlier', async () => {
|
|
122
|
+
// iOS pattern: a playing event fires, then playback stalls.
|
|
123
|
+
media.readyState = media.HAVE_METADATA;
|
|
124
|
+
detect();
|
|
125
|
+
media.dispatchEvent(mockEvent('playing'));
|
|
126
|
+
await poll(3);
|
|
127
|
+
expect(media.currentTime).toBeCloseTo(10.1); // nudged (recovered)
|
|
128
|
+
// The recovery revives playback.
|
|
129
|
+
media.currentTime = 11;
|
|
130
|
+
await poll(1);
|
|
131
|
+
expect(fabricatePlaying).toHaveBeenCalledTimes(1);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
describe('when the element is not advancing by design', () => {
|
|
135
|
+
it('does not recover while paused', async () => {
|
|
136
|
+
media.paused = true;
|
|
137
|
+
detect();
|
|
138
|
+
await poll(6);
|
|
139
|
+
expect(media.play).not.toHaveBeenCalled();
|
|
140
|
+
expect(media.currentTime).toBe(10);
|
|
141
|
+
});
|
|
142
|
+
it('does not recover once ended', async () => {
|
|
143
|
+
media.ended = true;
|
|
144
|
+
detect();
|
|
145
|
+
await poll(6);
|
|
146
|
+
expect(media.play).not.toHaveBeenCalled();
|
|
147
|
+
expect(media.currentTime).toBe(10);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
it('honors provided options', async () => {
|
|
151
|
+
detect({
|
|
152
|
+
pollInterval: 0.5,
|
|
153
|
+
stallThreshold: 1,
|
|
154
|
+
bufferEndMargin: 0.2,
|
|
155
|
+
stallSkip: 0.25,
|
|
156
|
+
maxAttempts: 1,
|
|
157
|
+
});
|
|
158
|
+
// Threshold 1s = two 0.5s polls; one nudge of 0.25, then it gives up.
|
|
159
|
+
for (let i = 0; i < 6; i++)
|
|
160
|
+
await clock.tick(0.5);
|
|
161
|
+
expect(media.currentTime).toBeCloseTo(10.25);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createStallMonitor.test.d.ts","sourceRoot":"","sources":["../../../../../test/unit/playback/createStallMonitor.test.ts"],"names":[],"mappings":""}
|