@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
|
@@ -422,7 +422,7 @@ describe('getPeriodSortedBandwidths', () => {
|
|
|
422
422
|
});
|
|
423
423
|
});
|
|
424
424
|
describe('estimatePeakBandwidth', () => {
|
|
425
|
-
it('pairs
|
|
425
|
+
it('pairs each tier with the cheapest peer in its bucket', () => {
|
|
426
426
|
// language=XML
|
|
427
427
|
const m = parseDashManifest(`<?xml version="1.0" ?>
|
|
428
428
|
<MPD minBufferTime="PT0S" profiles="" xmlns="urn:mpeg:dash:schema:mpd:2011">
|
|
@@ -441,20 +441,51 @@ describe('estimatePeakBandwidth', () => {
|
|
|
441
441
|
</MPD>`);
|
|
442
442
|
const as0 = m.MPD.Period[0].AdaptationSet[0];
|
|
443
443
|
const as1 = m.MPD.Period[0].AdaptationSet[1];
|
|
444
|
-
// video sorted: [4000, 3000, 2000, 1000], audio sorted: [200, 100]
|
|
445
|
-
//
|
|
444
|
+
// video sorted: [4000, 3000, 2000, 1000], audio sorted: [200, 100].
|
|
445
|
+
// Video's two audio buckets: v1,v2 → a1(200); v3,v4 → a2(100).
|
|
446
446
|
expect(estimatePeakBandwidth(as0.Representation[0], 'video')).toBe(4200);
|
|
447
|
-
// v2 pos=1/3=0.33 → audio index round(0.33*1)=0 → 200. total=3200
|
|
448
447
|
expect(estimatePeakBandwidth(as0.Representation[1], 'video')).toBe(3200);
|
|
449
|
-
// v3 pos=2/3=0.67 → audio index round(0.67*1)=1 → 100. total=2100
|
|
450
448
|
expect(estimatePeakBandwidth(as0.Representation[2], 'video')).toBe(2100);
|
|
451
|
-
// v4 pos=3/3=1.00 → audio index round(1.00*1)=1 → 100. total=1100
|
|
452
449
|
expect(estimatePeakBandwidth(as0.Representation[3], 'video')).toBe(1100);
|
|
453
|
-
// a1
|
|
454
|
-
|
|
455
|
-
|
|
450
|
+
// Audio's two video buckets: a1's bucket is v1,v2 so it pairs with the
|
|
451
|
+
// cheapest of those (v2=3000); a2's bucket is v3,v4 (cheapest v4=1000).
|
|
452
|
+
expect(estimatePeakBandwidth(as1.Representation[0], 'audio')).toBe(3200);
|
|
456
453
|
expect(estimatePeakBandwidth(as1.Representation[1], 'audio')).toBe(1100);
|
|
457
454
|
});
|
|
455
|
+
it('does not pin a small stream to its lowest tier across a finer peer', () => {
|
|
456
|
+
// 2 audio tiers alongside 10 video tiers: the top audio must stay
|
|
457
|
+
// affordable across the whole top half of video, not only at the very
|
|
458
|
+
// top. (Regression: it was priced with the single top video.)
|
|
459
|
+
// language=XML
|
|
460
|
+
const m = parseDashManifest(`<?xml version="1.0" ?>
|
|
461
|
+
<MPD minBufferTime="PT0S" profiles="" xmlns="urn:mpeg:dash:schema:mpd:2011">
|
|
462
|
+
<Period>
|
|
463
|
+
<AdaptationSet mimeType="video/mp4" codecs="avc1.640015">
|
|
464
|
+
<Representation bandwidth="10000" id="v1"/>
|
|
465
|
+
<Representation bandwidth="9000" id="v2"/>
|
|
466
|
+
<Representation bandwidth="8000" id="v3"/>
|
|
467
|
+
<Representation bandwidth="7000" id="v4"/>
|
|
468
|
+
<Representation bandwidth="6000" id="v5"/>
|
|
469
|
+
<Representation bandwidth="5000" id="v6"/>
|
|
470
|
+
<Representation bandwidth="4000" id="v7"/>
|
|
471
|
+
<Representation bandwidth="3000" id="v8"/>
|
|
472
|
+
<Representation bandwidth="2000" id="v9"/>
|
|
473
|
+
<Representation bandwidth="1000" id="v10"/>
|
|
474
|
+
</AdaptationSet>
|
|
475
|
+
<AdaptationSet mimeType="audio/mp4" codecs="mp4a.40.2">
|
|
476
|
+
<Representation bandwidth="200" id="a1"/>
|
|
477
|
+
<Representation bandwidth="100" id="a2"/>
|
|
478
|
+
</AdaptationSet>
|
|
479
|
+
</Period>
|
|
480
|
+
</MPD>`);
|
|
481
|
+
const audio = m.MPD.Period[0].AdaptationSet[1];
|
|
482
|
+
// Top audio's bucket is video[0..4]; it pairs with the cheapest of those
|
|
483
|
+
// (video[4]=6000), NOT video[0]=10000. So its total is 6200, keeping it
|
|
484
|
+
// affordable for the top half of video tiers.
|
|
485
|
+
expect(estimatePeakBandwidth(audio.Representation[0], 'audio')).toBe(6200);
|
|
486
|
+
// Bottom audio's bucket is video[5..9]; cheapest video[9]=1000 → 1100.
|
|
487
|
+
expect(estimatePeakBandwidth(audio.Representation[1], 'audio')).toBe(1100);
|
|
488
|
+
});
|
|
458
489
|
it('returns bandwidth as-is for single content type periods', () => {
|
|
459
490
|
// language=XML
|
|
460
491
|
const m = parseDashManifest(`<?xml version="1.0" ?>
|
|
@@ -482,7 +513,7 @@ describe('estimatePeakBandwidth', () => {
|
|
|
482
513
|
</MPD>`);
|
|
483
514
|
expect(estimatePeakBandwidth(m.MPD.Period[0].AdaptationSet[0].Representation[0], 'text')).toBe(50000);
|
|
484
515
|
});
|
|
485
|
-
it('pairs
|
|
516
|
+
it('pairs with the cheapest peer bucket across three content types', () => {
|
|
486
517
|
// language=XML
|
|
487
518
|
const m = parseDashManifest(`<?xml version="1.0" ?>
|
|
488
519
|
<MPD minBufferTime="PT0S" profiles="" xmlns="urn:mpeg:dash:schema:mpd:2011">
|
|
@@ -500,12 +531,13 @@ describe('estimatePeakBandwidth', () => {
|
|
|
500
531
|
</AdaptationSet>
|
|
501
532
|
</Period>
|
|
502
533
|
</MPD>`);
|
|
503
|
-
// v1
|
|
534
|
+
// v1 → cheapest audio in its bucket (200) + cheapest text (10). total=2210
|
|
504
535
|
expect(estimatePeakBandwidth(m.MPD.Period[0].AdaptationSet[0].Representation[0], 'video')).toBe(2210);
|
|
505
|
-
// v2
|
|
536
|
+
// v2 → audio bucket cheapest (100) + text (10). total=1110
|
|
506
537
|
expect(estimatePeakBandwidth(m.MPD.Period[0].AdaptationSet[0].Representation[1], 'video')).toBe(1110);
|
|
507
|
-
// t1
|
|
508
|
-
|
|
538
|
+
// t1 is the only text tier, so its bucket spans every peer — it pairs
|
|
539
|
+
// with the cheapest video (1000) and cheapest audio (100). total=1110
|
|
540
|
+
expect(estimatePeakBandwidth(m.MPD.Period[0].AdaptationSet[2].Representation[0], 'text')).toBe(1110);
|
|
509
541
|
});
|
|
510
542
|
it('handles single quality per content type', () => {
|
|
511
543
|
// language=XML
|
package/dist/unit/types/current/track/dash/timeline/DashRepresentationSegmentProvider.test.js
CHANGED
|
@@ -277,6 +277,120 @@ describe('createDashRepresentationSegmentProvider', () => {
|
|
|
277
277
|
});
|
|
278
278
|
});
|
|
279
279
|
});
|
|
280
|
+
describe('when SegmentBase is a WebM stream', () => {
|
|
281
|
+
// Minimal EBML builders for a synthetic WebM init + Cues.
|
|
282
|
+
const vintSize = (n) => n < 0x80 ? [0x80 | n] : [0x40 | (n >> 8), n & 0xff];
|
|
283
|
+
const el = (id, content) => [
|
|
284
|
+
...id,
|
|
285
|
+
...vintSize(content.length),
|
|
286
|
+
...content,
|
|
287
|
+
];
|
|
288
|
+
const bytesToArrayBuffer = (bytes) => new Uint8Array(bytes).buffer;
|
|
289
|
+
// EBML header (5 bytes) then Segment(Info > TimecodeScale=1_000_000);
|
|
290
|
+
// the Segment data starts at offset 10, so cue positions are + 10.
|
|
291
|
+
const initBuffer = bytesToArrayBuffer([
|
|
292
|
+
...el([0x1a, 0x45, 0xdf, 0xa3], []),
|
|
293
|
+
...el([0x18, 0x53, 0x80, 0x67], el([0x15, 0x49, 0xa9, 0x66], el([0x2a, 0xd7, 0xb1], [0x0f, 0x42, 0x40]))),
|
|
294
|
+
]);
|
|
295
|
+
const cuePoint = (time, pos) => el([0xbb], [
|
|
296
|
+
...el([0xb3], time),
|
|
297
|
+
...el([0xb7], [...el([0xf7], [0x01]), ...el([0xf1], pos)]),
|
|
298
|
+
]);
|
|
299
|
+
// Cue 0 @ t=0 → cluster pos 100; cue 1 @ t=2000ms → cluster pos 200.
|
|
300
|
+
const cuesBuffer = bytesToArrayBuffer(el([0x1c, 0x53, 0xbb, 0x6b], [
|
|
301
|
+
...cuePoint([0x00], [0x00, 0x64]),
|
|
302
|
+
...cuePoint([0x07, 0xd0], [0x00, 0xc8]),
|
|
303
|
+
]));
|
|
304
|
+
beforeEach(() => {
|
|
305
|
+
// WebM Cues don't carry the last segment's end, so a period end is
|
|
306
|
+
// required (VOD defines one).
|
|
307
|
+
manifest.MPD.mediaPresentationDuration = 60;
|
|
308
|
+
representation.BaseURL = [
|
|
309
|
+
{ _content: 'https://example.com/v.webm' },
|
|
310
|
+
];
|
|
311
|
+
representation.mimeType = 'video/webm';
|
|
312
|
+
representation.codecs = 'vp9';
|
|
313
|
+
representation.SegmentBase = {
|
|
314
|
+
indexRangeExact: false,
|
|
315
|
+
indexRange: [100, 199],
|
|
316
|
+
timescale: 1000000,
|
|
317
|
+
Initialization: { range: [0, 99] },
|
|
318
|
+
};
|
|
319
|
+
// The provider fetches the init and Cues ranges in parallel; return
|
|
320
|
+
// the matching buffer per Range header.
|
|
321
|
+
mockRequesterRef.value.request.and.callFake(((_input, init) => {
|
|
322
|
+
const range = init?.headers?.['Range'];
|
|
323
|
+
const body = range === 'bytes=0-99'
|
|
324
|
+
? initBuffer
|
|
325
|
+
: range === 'bytes=100-199'
|
|
326
|
+
? cuesBuffer
|
|
327
|
+
: new ArrayBuffer(0);
|
|
328
|
+
return Promise.resolve(new Response(body));
|
|
329
|
+
}));
|
|
330
|
+
});
|
|
331
|
+
it('creates a timeline from the WebM Cues', async () => {
|
|
332
|
+
const timeline = createTimeline();
|
|
333
|
+
// Prime the timeline (fetch init + Cues), then assert the segments.
|
|
334
|
+
await timeline.getSegment(0);
|
|
335
|
+
clearRequestCalls();
|
|
336
|
+
const info = await getSegmentRequestData(timeline);
|
|
337
|
+
expect(info).toEqual({
|
|
338
|
+
init: {
|
|
339
|
+
qualityId: any(String),
|
|
340
|
+
decoderId: any(String),
|
|
341
|
+
mimeType: 'video/webm; codecs="vp9"',
|
|
342
|
+
href: 'https://example.com/v.webm',
|
|
343
|
+
serviceId: 'example.com',
|
|
344
|
+
range: 'bytes=0-99',
|
|
345
|
+
},
|
|
346
|
+
segments: [
|
|
347
|
+
{
|
|
348
|
+
startTime: 0,
|
|
349
|
+
endTime: 2,
|
|
350
|
+
timestampOffset: 0,
|
|
351
|
+
href: 'https://example.com/v.webm',
|
|
352
|
+
serviceId: 'example.com',
|
|
353
|
+
// segmentDataStart(10) + cue positions 100..200.
|
|
354
|
+
range: 'bytes=110-209',
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
startTime: 2,
|
|
358
|
+
endTime: 60,
|
|
359
|
+
timestampOffset: 2,
|
|
360
|
+
href: 'https://example.com/v.webm',
|
|
361
|
+
serviceId: 'example.com',
|
|
362
|
+
// Last cluster runs open-ended to end of file.
|
|
363
|
+
range: 'bytes=210-',
|
|
364
|
+
},
|
|
365
|
+
],
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
it('indexes WebM without an explicit SegmentBase timescale', async () => {
|
|
369
|
+
delete representation.SegmentBase
|
|
370
|
+
.timescale;
|
|
371
|
+
const timeline = createTimeline();
|
|
372
|
+
const segment = await timeline.getSegment(0);
|
|
373
|
+
expect(segment).not.toBeNull();
|
|
374
|
+
// Cue 0 at ticks 0 → 0s (TimecodeScale-derived ticks-per-second).
|
|
375
|
+
expect(segment.startTime).toBe(0);
|
|
376
|
+
});
|
|
377
|
+
it('throws when the period has no determinable end', () => {
|
|
378
|
+
delete manifest.MPD
|
|
379
|
+
.mediaPresentationDuration;
|
|
380
|
+
const timeline = createTimeline();
|
|
381
|
+
return expectAsync(timeline.getSegment(0)).toBeRejectedWithError(/mediaPresentationDuration or Period\.duration required/);
|
|
382
|
+
});
|
|
383
|
+
it('throws when the Cues contain no cue points', () => {
|
|
384
|
+
// A Cues element whose only CuePoint lacks a cluster position.
|
|
385
|
+
const emptyCues = bytesToArrayBuffer(el([0x1c, 0x53, 0xbb, 0x6b], el([0xbb], el([0xb3], [0x00]))));
|
|
386
|
+
mockRequesterRef.value.request.and.callFake(((_input, init) => {
|
|
387
|
+
const range = init?.headers?.['Range'];
|
|
388
|
+
return Promise.resolve(new Response(range === 'bytes=0-99' ? initBuffer : emptyCues));
|
|
389
|
+
}));
|
|
390
|
+
const timeline = createTimeline();
|
|
391
|
+
return expectAsync(timeline.getSegment(0)).toBeRejectedWithError(/Cues contained no cue points/);
|
|
392
|
+
});
|
|
393
|
+
});
|
|
280
394
|
describe('when SegmentList is defined', () => {
|
|
281
395
|
let segmentList;
|
|
282
396
|
beforeEach(() => {
|
|
@@ -146,6 +146,31 @@ describe('mpd utils', () => {
|
|
|
146
146
|
expect(calculatePeriodStart(manifest.MPD.Period[0])).toEqual(0);
|
|
147
147
|
});
|
|
148
148
|
});
|
|
149
|
+
describe('when period.start is absent but periods have durations', () => {
|
|
150
|
+
it('derives the start from the preceding period durations', () => {
|
|
151
|
+
// language=XML
|
|
152
|
+
const manifest = parseDashManifest(`<?xml version="1.0" ?>
|
|
153
|
+
<MPD minBufferTime="PT0.0S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" type="static" xmlns="urn:mpeg:dash:schema:mpd:2011">
|
|
154
|
+
<Period duration="888.053"/>
|
|
155
|
+
<Period duration="888.053"/>
|
|
156
|
+
<Period duration="888.053"/>
|
|
157
|
+
</MPD>`);
|
|
158
|
+
expect(manifest.MPD.Period.map(calculatePeriodStart)).toEqual([
|
|
159
|
+
0, 888.053, 1776.106,
|
|
160
|
+
]);
|
|
161
|
+
});
|
|
162
|
+
it('inherits the previous start when the previous period has no duration', () => {
|
|
163
|
+
// language=XML
|
|
164
|
+
const manifest = parseDashManifest(`<?xml version="1.0" ?>
|
|
165
|
+
<MPD minBufferTime="PT0.0S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" type="static" xmlns="urn:mpeg:dash:schema:mpd:2011">
|
|
166
|
+
<Period/>
|
|
167
|
+
<Period/>
|
|
168
|
+
</MPD>`);
|
|
169
|
+
// The first period has neither start nor duration, so the
|
|
170
|
+
// second period cannot advance and inherits start 0.
|
|
171
|
+
expect(calculatePeriodStart(manifest.MPD.Period[1])).toEqual(0);
|
|
172
|
+
});
|
|
173
|
+
});
|
|
149
174
|
});
|
|
150
175
|
describe('getPeriodAtTime', () => {
|
|
151
176
|
it('returns the period spanning the given presentation time', () => {
|
|
@@ -331,6 +356,18 @@ describe('mpd utils', () => {
|
|
|
331
356
|
expect(calculateDuration(manifest)).toBe(50);
|
|
332
357
|
});
|
|
333
358
|
});
|
|
359
|
+
describe('when only per-period durations are present', () => {
|
|
360
|
+
it('sums the period durations across the presentation', () => {
|
|
361
|
+
// language=XML
|
|
362
|
+
const manifest = parseDashManifest(`<?xml version="1.0" ?>
|
|
363
|
+
<MPD minBufferTime="PT0.0S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" type="static" xmlns="urn:mpeg:dash:schema:mpd:2011">
|
|
364
|
+
<Period duration="888.053"/>
|
|
365
|
+
<Period duration="888.053"/>
|
|
366
|
+
<Period duration="888.053"/>
|
|
367
|
+
</MPD>`);
|
|
368
|
+
expect(calculateDuration(manifest)).toBeCloseTo(2664.159, 3);
|
|
369
|
+
});
|
|
370
|
+
});
|
|
334
371
|
describe('when MPD type is dynamic', () => {
|
|
335
372
|
it('returns Infinity for live presentations', () => {
|
|
336
373
|
// language=XML
|
|
@@ -22,6 +22,13 @@ describe('canPlayMimeType', () => {
|
|
|
22
22
|
expect(canPlayMimeType({ capabilities }, metadata)).toBe(true);
|
|
23
23
|
expect(capabilities.canPlayTypeMse).toHaveBeenCalledWith('audio/mp4; codecs="opus"');
|
|
24
24
|
});
|
|
25
|
+
it('supports WebM when the browser reports support', () => {
|
|
26
|
+
capabilities.canPlayTypeMse.and.returnValue(true);
|
|
27
|
+
const metadata = createEmptyMediaQualityMetadata();
|
|
28
|
+
metadata.mimeType = 'video/webm; codecs="vp9"';
|
|
29
|
+
expect(canPlayMimeType({ capabilities }, metadata)).toBe(true);
|
|
30
|
+
expect(capabilities.canPlayTypeMse).toHaveBeenCalledWith('video/webm; codecs="vp9"');
|
|
31
|
+
});
|
|
25
32
|
it('returns false for null mime type', () => {
|
|
26
33
|
capabilities.canPlayTypeMse.and.returnValue(true);
|
|
27
34
|
const metadata = createEmptyMediaQualityMetadata();
|
|
@@ -2,56 +2,61 @@
|
|
|
2
2
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { withinAudioSampleRateRange, createEmptyMediaQualityMetadata, throwSamplingRatesUnsupported, } from '@amazon/vinyl';
|
|
6
6
|
import { MockCapabilities } from '@amazon/vinyl/vinylTestUtil';
|
|
7
7
|
import { setUserAgent } from '@amazon/vinyl-util';
|
|
8
|
-
describe('
|
|
8
|
+
describe('withinAudioSampleRateRange', () => {
|
|
9
9
|
let capabilities;
|
|
10
10
|
beforeEach(() => {
|
|
11
11
|
capabilities = new MockCapabilities();
|
|
12
12
|
capabilities.sampleRate = 48_000;
|
|
13
13
|
});
|
|
14
|
+
// The filter only gates audio content types, so gated fixtures must declare
|
|
15
|
+
// contentType 'audio' (the empty metadata defaults it to null).
|
|
16
|
+
function audioQuality(rate) {
|
|
17
|
+
const quality = createEmptyMediaQualityMetadata();
|
|
18
|
+
quality.contentType = 'audio';
|
|
19
|
+
quality.audioSamplingRate = rate;
|
|
20
|
+
return quality;
|
|
21
|
+
}
|
|
14
22
|
describe('when browser is Firefox', () => {
|
|
15
23
|
beforeEach(() => {
|
|
16
24
|
setUserAgent('Firefox');
|
|
17
25
|
});
|
|
18
26
|
it('returns false when sample rate is above supported', () => {
|
|
19
|
-
const metadata =
|
|
20
|
-
metadata
|
|
21
|
-
expect(supportsAudioSamplingRate({ capabilities }, metadata, 0, [
|
|
27
|
+
const metadata = audioQuality([96_000]);
|
|
28
|
+
expect(withinAudioSampleRateRange({ capabilities }, metadata, 0, [
|
|
22
29
|
metadata,
|
|
23
30
|
])).toBe(false);
|
|
24
31
|
});
|
|
25
32
|
it('returns false when sample rate is above 48kHz even if capabilities allows it', () => {
|
|
26
33
|
capabilities.sampleRate = 96_000;
|
|
27
|
-
const metadata =
|
|
28
|
-
metadata
|
|
29
|
-
expect(supportsAudioSamplingRate({ capabilities }, metadata, 0, [
|
|
34
|
+
const metadata = audioQuality([96_000]);
|
|
35
|
+
expect(withinAudioSampleRateRange({ capabilities }, metadata, 0, [
|
|
30
36
|
metadata,
|
|
31
37
|
])).toBe(false);
|
|
32
38
|
});
|
|
33
39
|
it('returns false even when all rates are above 48kHz (no fallback to lowest)', () => {
|
|
34
|
-
const low =
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
const low = audioQuality([88_200]);
|
|
41
|
+
const high = audioQuality([96_000]);
|
|
42
|
+
expect(withinAudioSampleRateRange({ capabilities }, low, 0, [
|
|
43
|
+
low,
|
|
44
|
+
high,
|
|
45
|
+
])).toBe(false);
|
|
46
|
+
expect(withinAudioSampleRateRange({ capabilities }, high, 1, [
|
|
40
47
|
low,
|
|
41
48
|
high,
|
|
42
49
|
])).toBe(false);
|
|
43
50
|
});
|
|
44
51
|
it('returns true when sample rate is at or below supported', () => {
|
|
45
|
-
const metadata =
|
|
46
|
-
metadata
|
|
47
|
-
expect(supportsAudioSamplingRate({ capabilities }, metadata, 0, [
|
|
52
|
+
const metadata = audioQuality([48_000]);
|
|
53
|
+
expect(withinAudioSampleRateRange({ capabilities }, metadata, 0, [
|
|
48
54
|
metadata,
|
|
49
55
|
])).toBe(true);
|
|
50
56
|
});
|
|
51
57
|
it('returns true when sample rate is not set', () => {
|
|
52
|
-
const metadata =
|
|
53
|
-
metadata
|
|
54
|
-
expect(supportsAudioSamplingRate({ capabilities }, metadata, 0, [
|
|
58
|
+
const metadata = audioQuality(null);
|
|
59
|
+
expect(withinAudioSampleRateRange({ capabilities }, metadata, 0, [
|
|
55
60
|
metadata,
|
|
56
61
|
])).toBe(true);
|
|
57
62
|
});
|
|
@@ -61,33 +66,82 @@ describe('supportsAudioSamplingRate', () => {
|
|
|
61
66
|
setUserAgent('Chrome');
|
|
62
67
|
});
|
|
63
68
|
it('returns true when sample rate is at or below supported', () => {
|
|
64
|
-
const metadata =
|
|
65
|
-
metadata
|
|
66
|
-
|
|
69
|
+
const metadata = audioQuality([48_000]);
|
|
70
|
+
expect(withinAudioSampleRateRange({ capabilities }, metadata, 0, [
|
|
71
|
+
metadata,
|
|
72
|
+
])).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
it('keeps everything when there is no platform max to gauge support', () => {
|
|
75
|
+
capabilities.sampleRate = null;
|
|
76
|
+
const metadata = audioQuality([96_000]);
|
|
77
|
+
expect(withinAudioSampleRateRange({ capabilities }, metadata, 0, [
|
|
67
78
|
metadata,
|
|
68
79
|
])).toBe(true);
|
|
69
80
|
});
|
|
70
81
|
it('returns false when sample rate is above supported and others are below', () => {
|
|
71
|
-
const low =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
high.audioSamplingRate = [96_000];
|
|
75
|
-
expect(supportsAudioSamplingRate({ capabilities }, high, 1, [
|
|
82
|
+
const low = audioQuality([44_100]);
|
|
83
|
+
const high = audioQuality([96_000]);
|
|
84
|
+
expect(withinAudioSampleRateRange({ capabilities }, high, 1, [
|
|
76
85
|
low,
|
|
77
86
|
high,
|
|
78
87
|
])).toBe(false);
|
|
79
88
|
});
|
|
80
89
|
it('keeps lowest sample rate when all are above supported', () => {
|
|
81
|
-
const low =
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
const low = audioQuality([88_200]);
|
|
91
|
+
const high = audioQuality([96_000]);
|
|
92
|
+
expect(withinAudioSampleRateRange({ capabilities }, low, 0, [
|
|
93
|
+
low,
|
|
94
|
+
high,
|
|
95
|
+
])).toBe(true);
|
|
96
|
+
expect(withinAudioSampleRateRange({ capabilities }, high, 1, [
|
|
87
97
|
low,
|
|
88
98
|
high,
|
|
89
99
|
])).toBe(false);
|
|
90
100
|
});
|
|
101
|
+
it('an explicit maxSampleRate takes precedence — raising it keeps a higher rate', () => {
|
|
102
|
+
// AudioContext reports 48kHz, which would drop the 96kHz rendition.
|
|
103
|
+
capabilities.sampleRate = 48_000;
|
|
104
|
+
const low = audioQuality([48_000]);
|
|
105
|
+
const high = audioQuality([96_000]);
|
|
106
|
+
// Without an override, 96kHz is dropped (a 48kHz alternative exists).
|
|
107
|
+
expect(withinAudioSampleRateRange({ capabilities }, high, 1, [
|
|
108
|
+
low,
|
|
109
|
+
high,
|
|
110
|
+
])).toBe(false);
|
|
111
|
+
// With maxSampleRate = 96kHz, it is kept.
|
|
112
|
+
expect(withinAudioSampleRateRange({ capabilities, maxSampleRate: 96_000 }, high, 1, [low, high])).toBe(true);
|
|
113
|
+
});
|
|
114
|
+
it('an explicit maxSampleRate takes precedence — lowering it drops a rate the platform allows', () => {
|
|
115
|
+
// AudioContext reports 192kHz, which would keep the 96kHz rendition.
|
|
116
|
+
capabilities.sampleRate = 192_000;
|
|
117
|
+
const low = audioQuality([48_000]);
|
|
118
|
+
const high = audioQuality([96_000]);
|
|
119
|
+
expect(withinAudioSampleRateRange({ capabilities }, high, 1, [
|
|
120
|
+
low,
|
|
121
|
+
high,
|
|
122
|
+
])).toBe(true);
|
|
123
|
+
// Capping at 48kHz drops the 96kHz rendition and keeps the 48kHz one.
|
|
124
|
+
expect(withinAudioSampleRateRange({ capabilities, maxSampleRate: 48_000 }, high, 1, [low, high])).toBe(false);
|
|
125
|
+
expect(withinAudioSampleRateRange({ capabilities, maxSampleRate: 48_000 }, low, 0, [low, high])).toBe(true);
|
|
126
|
+
});
|
|
127
|
+
it('ignores non-audio qualities and keeps audio above the device rate', () => {
|
|
128
|
+
// Output device runs at 44.1kHz while the audio is standard 48kHz.
|
|
129
|
+
capabilities.sampleRate = 44_100;
|
|
130
|
+
const audio = audioQuality([48_000]);
|
|
131
|
+
// A co-present video quality is never gated and must not influence
|
|
132
|
+
// the audio keep-lowest fallback.
|
|
133
|
+
const video = createEmptyMediaQualityMetadata();
|
|
134
|
+
video.contentType = 'video';
|
|
135
|
+
video.audioSamplingRate = null;
|
|
136
|
+
expect(withinAudioSampleRateRange({ capabilities }, audio, 0, [
|
|
137
|
+
audio,
|
|
138
|
+
video,
|
|
139
|
+
])).toBe(true);
|
|
140
|
+
expect(withinAudioSampleRateRange({ capabilities }, video, 1, [
|
|
141
|
+
audio,
|
|
142
|
+
video,
|
|
143
|
+
])).toBe(true);
|
|
144
|
+
});
|
|
91
145
|
});
|
|
92
146
|
it('throws correct error', () => {
|
|
93
147
|
try {
|
|
@@ -100,3 +154,51 @@ describe('supportsAudioSamplingRate', () => {
|
|
|
100
154
|
}
|
|
101
155
|
});
|
|
102
156
|
});
|
|
157
|
+
describe('withinAudioSampleRateRange minSampleRate floor', () => {
|
|
158
|
+
let capabilities;
|
|
159
|
+
beforeEach(() => {
|
|
160
|
+
capabilities = new MockCapabilities();
|
|
161
|
+
// High enough that the upper bound never interferes with these tests.
|
|
162
|
+
capabilities.sampleRate = 192_000;
|
|
163
|
+
});
|
|
164
|
+
function audioQuality(rate) {
|
|
165
|
+
const quality = createEmptyMediaQualityMetadata();
|
|
166
|
+
quality.contentType = 'audio';
|
|
167
|
+
quality.audioSamplingRate = rate;
|
|
168
|
+
return quality;
|
|
169
|
+
}
|
|
170
|
+
// minSampleRate is passed via the options arg alongside capabilities.
|
|
171
|
+
function withinMin(metadata, index, array) {
|
|
172
|
+
return withinAudioSampleRateRange({ capabilities, minSampleRate: 48_000 }, metadata, index, array);
|
|
173
|
+
}
|
|
174
|
+
it('passes through non-audio qualities', () => {
|
|
175
|
+
const video = createEmptyMediaQualityMetadata();
|
|
176
|
+
video.contentType = 'video';
|
|
177
|
+
expect(withinMin(video, 0, [video])).toBe(true);
|
|
178
|
+
});
|
|
179
|
+
it('keeps qualities with no sampling rate', () => {
|
|
180
|
+
const quality = audioQuality(null);
|
|
181
|
+
expect(withinMin(quality, 0, [quality])).toBe(true);
|
|
182
|
+
});
|
|
183
|
+
it('drops rates below the floor when a rate at or above it exists', () => {
|
|
184
|
+
const low = audioQuality([24_000]);
|
|
185
|
+
const high = audioQuality([48_000]);
|
|
186
|
+
expect(withinMin(high, 1, [low, high])).toBe(true);
|
|
187
|
+
expect(withinMin(low, 0, [low, high])).toBe(false);
|
|
188
|
+
});
|
|
189
|
+
it('keeps the highest when every rate is below the floor', () => {
|
|
190
|
+
const low = audioQuality([16_000]);
|
|
191
|
+
const mid = audioQuality([24_000]);
|
|
192
|
+
expect(withinMin(mid, 1, [low, mid])).toBe(true);
|
|
193
|
+
expect(withinMin(low, 0, [low, mid])).toBe(false);
|
|
194
|
+
});
|
|
195
|
+
it('ignores non-audio qualities in the floor fallback', () => {
|
|
196
|
+
const audio = audioQuality([24_000]); // below the floor
|
|
197
|
+
const video = createEmptyMediaQualityMetadata();
|
|
198
|
+
video.contentType = 'video';
|
|
199
|
+
video.audioSamplingRate = null;
|
|
200
|
+
// Below the 48kHz floor but the only audio → kept; video is ignored.
|
|
201
|
+
expect(withinMin(audio, 0, [audio, video])).toBe(true);
|
|
202
|
+
expect(withinMin(video, 1, [audio, video])).toBe(true);
|
|
203
|
+
});
|
|
204
|
+
});
|