shaka-player 3.2.1 → 3.3.1
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/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- package/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
- package/.github/ISSUE_TEMPLATE/question.md +1 -1
- package/AUTHORS +9 -5
- package/CHANGELOG.md +358 -0
- package/CONTRIBUTORS +7 -2
- package/build/conformance.textproto +183 -169
- package/build/generateExterns.js +1 -1
- package/build/types/core +3 -0
- package/build/types/offline +1 -0
- package/build/types/polyfill +1 -0
- package/build/types/ui +2 -0
- package/demo/common/assets.js +19 -1
- package/demo/common/message_ids.js +13 -1
- package/demo/config.js +31 -1
- package/demo/index.html +1 -1
- package/demo/locales/en.json +12 -0
- package/demo/locales/source.json +48 -0
- package/dist/controls.css +26 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +20 -17
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +20 -17
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +19 -12
- package/dist/locales.js +39 -37
- package/dist/receiver.compiled.debug.js +12 -10
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +12 -10
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +231 -18
- package/dist/shaka-player.compiled.debug.d.ts +231 -18
- package/dist/shaka-player.compiled.debug.externs.js +279 -8
- package/dist/shaka-player.compiled.debug.js +512 -449
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +279 -8
- package/dist/shaka-player.compiled.js +854 -821
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +247 -19
- package/dist/shaka-player.ui.debug.d.ts +247 -19
- package/dist/shaka-player.ui.debug.externs.js +307 -9
- package/dist/shaka-player.ui.debug.js +662 -580
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +307 -9
- package/dist/shaka-player.ui.js +1047 -1000
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/bg-fetch-after.gv +29 -0
- package/docs/design/bg-fetch-after.gv.png +0 -0
- package/docs/design/bg-fetch-before.gv +18 -0
- package/docs/design/bg-fetch-before.gv.png +0 -0
- package/docs/design/bg-fetch.md +134 -0
- package/docs/tutorials/blob-url.md +15 -0
- package/docs/tutorials/fairplay.md +1 -1
- package/docs/tutorials/index.json +1 -0
- package/docs/tutorials/ui-customization.md +66 -0
- package/docs/tutorials/ui.md +5 -5
- package/externs/cmcd.js +186 -0
- package/externs/ima.js +3 -0
- package/externs/shaka/ads.js +5 -0
- package/externs/shaka/manifest.js +12 -1
- package/externs/shaka/manifest_parser.js +10 -1
- package/externs/shaka/net.js +20 -4
- package/externs/shaka/offline.js +31 -2
- package/externs/shaka/player.js +138 -5
- package/externs/shaka/text.js +24 -0
- package/externs/webcrypto.js +18 -0
- package/karma.conf.js +1 -0
- package/lib/abr/ewma.js +14 -0
- package/lib/abr/ewma_bandwidth_estimator.js +16 -2
- package/lib/abr/simple_abr_manager.js +6 -0
- package/lib/ads/client_side_ad.js +8 -0
- package/lib/ads/client_side_ad_manager.js +54 -90
- package/lib/ads/server_side_ad.js +7 -0
- package/lib/ads/server_side_ad_manager.js +7 -10
- package/lib/cast/cast_proxy.js +3 -2
- package/lib/cast/cast_receiver.js +2 -1
- package/lib/cast/cast_sender.js +2 -2
- package/lib/cast/cast_utils.js +1 -0
- package/lib/dash/dash_parser.js +141 -16
- package/lib/dash/segment_base.js +25 -1
- package/lib/dash/segment_list.js +19 -10
- package/lib/dash/segment_template.js +24 -11
- package/lib/hls/hls_parser.js +146 -40
- package/lib/media/drm_engine.js +7 -0
- package/lib/media/gap_jumping_controller.js +4 -2
- package/lib/media/media_source_engine.js +1 -2
- package/lib/media/quality_observer.js +291 -0
- package/lib/media/segment_index.js +8 -1
- package/lib/media/segment_reference.js +37 -4
- package/lib/media/streaming_engine.js +49 -7
- package/lib/net/http_fetch_plugin.js +31 -11
- package/lib/net/http_plugin_utils.js +1 -0
- package/lib/net/http_xhr_plugin.js +40 -14
- package/lib/net/networking_engine.js +83 -19
- package/lib/offline/download_info.js +68 -0
- package/lib/offline/download_manager.js +13 -5
- package/lib/offline/indexeddb/base_storage_cell.js +35 -0
- package/lib/offline/indexeddb/storage_mechanism.js +1 -1
- package/lib/offline/indexeddb/v5_storage_cell.js +5 -0
- package/lib/offline/storage.js +393 -284
- package/lib/offline/stored_content_utils.js +2 -0
- package/lib/player.js +249 -43
- package/lib/polyfill/media_capabilities.js +36 -15
- package/lib/polyfill/mediasource.js +6 -0
- package/lib/polyfill/orientation.js +1 -1
- package/lib/polyfill/patchedmediakeys_apple.js +4 -4
- package/lib/polyfill/patchedmediakeys_ms.js +4 -4
- package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
- package/lib/polyfill/random_uuid.js +52 -0
- package/lib/text/cue.js +18 -0
- package/lib/text/mp4_ttml_parser.js +3 -0
- package/lib/text/text_engine.js +14 -2
- package/lib/text/ttml_text_parser.js +114 -60
- package/lib/text/ui_text_displayer.js +95 -41
- package/lib/util/cmcd_manager.js +672 -0
- package/lib/util/error.js +6 -0
- package/lib/util/fake_event.js +53 -7
- package/lib/util/language_utils.js +12 -0
- package/lib/util/mutex.js +52 -0
- package/lib/util/periods.js +102 -65
- package/lib/util/platform.js +13 -1
- package/lib/util/player_configuration.js +18 -0
- package/lib/util/stream_utils.js +99 -10
- package/lib/util/xml_utils.js +19 -0
- package/package.json +2 -2
- package/shaka-player.uncompiled.js +3 -0
- package/test/cast/cast_proxy_unit.js +12 -6
- package/test/cast/cast_utils_unit.js +1 -1
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_live_unit.js +101 -1
- package/test/dash/dash_parser_manifest_unit.js +222 -2
- package/test/dash/dash_parser_segment_base_unit.js +2 -0
- package/test/dash/dash_parser_segment_list_unit.js +2 -1
- package/test/dash/dash_parser_segment_template_unit.js +2 -1
- package/test/hls/hls_live_unit.js +2 -0
- package/test/hls/hls_parser_unit.js +7 -1
- package/test/media/closed_caption_parser_unit.js +6 -1
- package/test/media/drm_engine_unit.js +47 -3
- package/test/media/quality_observer_unit.js +139 -0
- package/test/media/segment_reference_unit.js +16 -1
- package/test/media/streaming_engine_integration.js +4 -2
- package/test/media/streaming_engine_unit.js +147 -0
- package/test/net/http_plugin_unit.js +20 -15
- package/test/offline/storage_integration.js +108 -4
- package/test/player_integration.js +178 -8
- package/test/player_src_equals_integration.js +41 -8
- package/test/player_unit.js +19 -9
- package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
- package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
- package/test/test/assets/3675/dash_0.mpd +30 -0
- package/test/test/assets/3675/dash_1.mpd +30 -0
- package/test/test/assets/3675/dash_2.mpd +30 -0
- package/test/test/assets/3675/dash_3.mpd +30 -0
- package/test/test/assets/3675/dash_4.mpd +30 -0
- package/test/test/assets/3675/dash_5.mpd +26 -0
- package/test/test/assets/3675/init-stream0.m4s +0 -0
- package/test/test/assets/chapters.vtt +2 -2
- package/test/test/assets/chapters2.vtt +10 -0
- package/test/test/util/dash_parser_util.js +4 -0
- package/test/test/util/fake_ad.js +7 -0
- package/test/test/util/fake_ad_manager.js +1 -1
- package/test/test/util/fake_drm_engine.js +9 -2
- package/test/test/util/manifest_generator.js +3 -2
- package/test/test/util/test_scheme.js +14 -1
- package/test/test/util/ttml_utils.js +81 -0
- package/test/text/mp4_ttml_parser_unit.js +11 -18
- package/test/text/ttml_text_parser_unit.js +552 -227
- package/test/text/ui_text_displayer_unit.js +29 -17
- package/test/ui/localization_unit.js +15 -14
- package/test/ui/text_displayer_layout_unit.js +13 -1
- package/test/ui/ui_unit.js +250 -0
- package/test/util/cmcd_manager_unit.js +291 -0
- package/test/util/stream_utils_unit.js +45 -4
- package/third_party/closure-uri/uri.js +21 -0
- package/ui/airplay_button.js +1 -0
- package/ui/audio_language_selection.js +7 -0
- package/ui/cast_button.js +3 -3
- package/ui/context_menu.js +109 -0
- package/ui/controls.js +45 -13
- package/ui/controls.less +1 -0
- package/ui/enums.js +4 -0
- package/ui/externs/ui.js +28 -1
- package/ui/fast_forward_button.js +14 -5
- package/ui/fullscreen_button.js +1 -0
- package/ui/less/buttons.less +0 -4
- package/ui/less/containers.less +77 -7
- package/ui/less/overflow_menu.less +0 -10
- package/ui/less/tooltip.less +97 -0
- package/ui/locales/en.json +1 -0
- package/ui/locales/ru.json +6 -6
- package/ui/locales/source.json +4 -0
- package/ui/localization.js +28 -51
- package/ui/loop_button.js +5 -0
- package/ui/mute_button.js +2 -1
- package/ui/overflow_menu.js +5 -25
- package/ui/pip_button.js +7 -3
- package/ui/play_button.js +2 -2
- package/ui/playback_rate_selection.js +8 -9
- package/ui/resolution_selection.js +7 -0
- package/ui/rewind_button.js +15 -6
- package/ui/seek_bar.js +4 -2
- package/ui/settings_menu.js +36 -4
- package/ui/small_play_button.js +1 -0
- package/ui/statistics_button.js +253 -0
- package/ui/text_selection.js +12 -4
- package/ui/ui.js +30 -0
- package/ui/volume_bar.js +1 -1
- package/externs/media_capabilities.js +0 -16
|
@@ -38,6 +38,14 @@ describe('DashParser Manifest', () => {
|
|
|
38
38
|
|
|
39
39
|
/** @type {string} */
|
|
40
40
|
const thumbnailScheme = 'http://dashif.org/guidelines/thumbnail_tile';
|
|
41
|
+
/**
|
|
42
|
+
* CICP scheme. parameter must be one of the following: "ColourPrimaries",
|
|
43
|
+
* "TransferCharacteristics", or "MatrixCoefficients".
|
|
44
|
+
*
|
|
45
|
+
* @param {string} parameter
|
|
46
|
+
* @return {string}
|
|
47
|
+
*/
|
|
48
|
+
const cicpScheme = (parameter) => `urn:mpeg:mpegB:cicp:${parameter}`;
|
|
41
49
|
|
|
42
50
|
beforeAll(async () => {
|
|
43
51
|
mp4Index = await shaka.test.Util.fetch(mp4IndexSegmentUri);
|
|
@@ -49,6 +57,8 @@ describe('DashParser Manifest', () => {
|
|
|
49
57
|
onEventSpy = jasmine.createSpy('onEvent');
|
|
50
58
|
playerInterface = {
|
|
51
59
|
networkingEngine: fakeNetEngine,
|
|
60
|
+
modifyManifestRequest: (request, manifestInfo) => {},
|
|
61
|
+
modifySegmentRequest: (request, segmentInfo) => {},
|
|
52
62
|
filter: (manifest) => Promise.resolve(),
|
|
53
63
|
makeTextStreamsForClosedCaptions: (manifest) => {},
|
|
54
64
|
onTimelineRegionAdded: fail, // Should not have any EventStream elements.
|
|
@@ -1864,7 +1874,7 @@ describe('DashParser Manifest', () => {
|
|
|
1864
1874
|
expect(textStream.kind).toBe('caption');
|
|
1865
1875
|
});
|
|
1866
1876
|
|
|
1867
|
-
it('converts Roles element to "forced"', async () => {
|
|
1877
|
+
it('converts Roles element to "forced" (old role)', async () => {
|
|
1868
1878
|
const manifestText = [
|
|
1869
1879
|
'<MPD minBufferTime="PT75S">',
|
|
1870
1880
|
' <Period id="1" duration="PT30S">',
|
|
@@ -1896,7 +1906,40 @@ describe('DashParser Manifest', () => {
|
|
|
1896
1906
|
expect(textStream.forced).toBe(true);
|
|
1897
1907
|
});
|
|
1898
1908
|
|
|
1899
|
-
it('
|
|
1909
|
+
it('converts Roles element to "forced"', async () => {
|
|
1910
|
+
const manifestText = [
|
|
1911
|
+
'<MPD minBufferTime="PT75S">',
|
|
1912
|
+
' <Period id="1" duration="PT30S">',
|
|
1913
|
+
' <AdaptationSet id="1" contentType="text">',
|
|
1914
|
+
' <Accessibility schemeIdUri="urn:mpeg:dash:role:2011" ',
|
|
1915
|
+
' value="captions" />',
|
|
1916
|
+
' <Accessibility schemeIdUri="urn:mpeg:dash:role:2011" ',
|
|
1917
|
+
' value="forced-subtitle" />',
|
|
1918
|
+
' <Accessibility schemeIdUri="foobar" value="bar" />',
|
|
1919
|
+
' <Representation id="text-en" mimeType="text/webvtt">',
|
|
1920
|
+
' <BaseURL>t-en.vtt</BaseURL>',
|
|
1921
|
+
' </Representation>',
|
|
1922
|
+
' </AdaptationSet>',
|
|
1923
|
+
' <AdaptationSet id="1" mimeType="video/mp4">',
|
|
1924
|
+
' <Representation id="video-sd" width="640" height="480">',
|
|
1925
|
+
' <BaseURL>v-sd.mp4</BaseURL>',
|
|
1926
|
+
' <SegmentBase indexRange="100-200" />',
|
|
1927
|
+
' </Representation>',
|
|
1928
|
+
' </AdaptationSet>',
|
|
1929
|
+
' </Period>',
|
|
1930
|
+
'</MPD>',
|
|
1931
|
+
].join('\n');
|
|
1932
|
+
|
|
1933
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
1934
|
+
/** @type {shaka.extern.Manifest} */
|
|
1935
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
1936
|
+
const textStream = manifest.textStreams[0];
|
|
1937
|
+
expect(textStream.roles).toEqual(['captions', 'forced-subtitle']);
|
|
1938
|
+
expect(textStream.forced).toBe(true);
|
|
1939
|
+
});
|
|
1940
|
+
|
|
1941
|
+
it('supports HDR signaling via profiles', async () => {
|
|
1942
|
+
// (DASH-IF IOP v4.3 10.3.3.)
|
|
1900
1943
|
const hdrProfile =
|
|
1901
1944
|
'http://dashif.org/guidelines/dash-if-uhd#hevc-hdr-pq10';
|
|
1902
1945
|
const manifestText = [
|
|
@@ -1927,6 +1970,110 @@ describe('DashParser Manifest', () => {
|
|
|
1927
1970
|
expect(stream.hdr).toBe('PQ');
|
|
1928
1971
|
});
|
|
1929
1972
|
|
|
1973
|
+
it('supports HDR signaling via SupplementalProperty', async () => {
|
|
1974
|
+
// (DASH-IF IOP v4.3 6.2.5.1.)
|
|
1975
|
+
const hdrScheme = cicpScheme('TransferCharacteristics');
|
|
1976
|
+
const pq = 16;
|
|
1977
|
+
const manifestText = [
|
|
1978
|
+
'<MPD minBufferTime="PT75S">',
|
|
1979
|
+
' <Period id="1" duration="PT30S">',
|
|
1980
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
1981
|
+
` <SupplementalProperty schemeIdUri="${hdrScheme}" value="${pq}" />`,
|
|
1982
|
+
' <Representation codecs="hvc1.2.4.L150.90">',
|
|
1983
|
+
' <BaseURL>v-sd.mp4</BaseURL>',
|
|
1984
|
+
' <SegmentBase indexRange="100-200" />',
|
|
1985
|
+
' </Representation>',
|
|
1986
|
+
' </AdaptationSet>',
|
|
1987
|
+
' <AdaptationSet id="3" mimeType="audio/mp4">',
|
|
1988
|
+
' <Representation id="audio-en">',
|
|
1989
|
+
' <BaseURL>a-en.mp4</BaseURL>',
|
|
1990
|
+
' <SegmentBase indexRange="100-200" />',
|
|
1991
|
+
' </Representation>',
|
|
1992
|
+
' </AdaptationSet>',
|
|
1993
|
+
' </Period>',
|
|
1994
|
+
'</MPD>',
|
|
1995
|
+
].join('\n');
|
|
1996
|
+
|
|
1997
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
1998
|
+
|
|
1999
|
+
/** @type {shaka.extern.Manifest} */
|
|
2000
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2001
|
+
expect(manifest.variants.length).toBe(1);
|
|
2002
|
+
const stream = manifest.variants[0].video;
|
|
2003
|
+
expect(stream.hdr).toBe('PQ');
|
|
2004
|
+
});
|
|
2005
|
+
|
|
2006
|
+
it('supports HDR signaling via EssentialProperty', async () => {
|
|
2007
|
+
// (DASH-IF IOP v4.3 6.2.5.1.)
|
|
2008
|
+
const hdrScheme = cicpScheme('TransferCharacteristics');
|
|
2009
|
+
const hlg = 18;
|
|
2010
|
+
const manifestText = [
|
|
2011
|
+
'<MPD minBufferTime="PT75S">',
|
|
2012
|
+
' <Period id="1" duration="PT30S">',
|
|
2013
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
2014
|
+
` <EssentialProperty schemeIdUri="${hdrScheme}" value="${hlg}" />`,
|
|
2015
|
+
' <Representation codecs="hvc1.2.4.L153.B0">',
|
|
2016
|
+
' <BaseURL>v-sd.mp4</BaseURL>',
|
|
2017
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2018
|
+
' </Representation>',
|
|
2019
|
+
' </AdaptationSet>',
|
|
2020
|
+
' <AdaptationSet id="3" mimeType="audio/mp4">',
|
|
2021
|
+
' <Representation id="audio-en">',
|
|
2022
|
+
' <BaseURL>a-en.mp4</BaseURL>',
|
|
2023
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2024
|
+
' </Representation>',
|
|
2025
|
+
' </AdaptationSet>',
|
|
2026
|
+
' </Period>',
|
|
2027
|
+
'</MPD>',
|
|
2028
|
+
].join('\n');
|
|
2029
|
+
|
|
2030
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2031
|
+
|
|
2032
|
+
/** @type {shaka.extern.Manifest} */
|
|
2033
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2034
|
+
expect(manifest.variants.length).toBe(1);
|
|
2035
|
+
const stream = manifest.variants[0].video;
|
|
2036
|
+
expect(stream.hdr).toBe('HLG');
|
|
2037
|
+
});
|
|
2038
|
+
|
|
2039
|
+
it('supports SDR signalling via EssentialProperty', async () => {
|
|
2040
|
+
// (DASH-IF IOP v4.3 6.2.5.1.)
|
|
2041
|
+
const scheme = cicpScheme('TransferCharacteristics');
|
|
2042
|
+
const sdrValues = [1, 6, 13, 14, 15];
|
|
2043
|
+
const manifestPromises = [];
|
|
2044
|
+
for (const value of sdrValues) {
|
|
2045
|
+
const manifestText = [
|
|
2046
|
+
'<MPD minBufferTime="PT75S">',
|
|
2047
|
+
' <Period id="1" duration="PT30S">',
|
|
2048
|
+
' <AdaptationSet id="2" mimeType="video/mp4">',
|
|
2049
|
+
` <EssentialProperty schemeIdUri="${scheme}" value="${value}" />`,
|
|
2050
|
+
' <Representation codecs="avc1.640028">',
|
|
2051
|
+
' <BaseURL>v-sd.mp4</BaseURL>',
|
|
2052
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2053
|
+
' </Representation>',
|
|
2054
|
+
' </AdaptationSet>',
|
|
2055
|
+
' <AdaptationSet id="3" mimeType="audio/mp4">',
|
|
2056
|
+
' <Representation id="audio-en">',
|
|
2057
|
+
' <BaseURL>a-en.mp4</BaseURL>',
|
|
2058
|
+
' <SegmentBase indexRange="100-200" />',
|
|
2059
|
+
' </Representation>',
|
|
2060
|
+
' </AdaptationSet>',
|
|
2061
|
+
' </Period>',
|
|
2062
|
+
'</MPD>',
|
|
2063
|
+
].join('\n');
|
|
2064
|
+
|
|
2065
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
2066
|
+
|
|
2067
|
+
manifestPromises.push(parser.start('dummy://foo', playerInterface));
|
|
2068
|
+
}
|
|
2069
|
+
const manifests = await Promise.all(manifestPromises);
|
|
2070
|
+
for (const manifest of manifests) {
|
|
2071
|
+
expect(manifest.variants.length).toBe(1);
|
|
2072
|
+
const stream = manifest.variants[0].video;
|
|
2073
|
+
expect(stream.hdr).toBe('SDR');
|
|
2074
|
+
}
|
|
2075
|
+
});
|
|
2076
|
+
|
|
1930
2077
|
it('Does not error when image adaptation sets are present', async () => {
|
|
1931
2078
|
const manifestText = [
|
|
1932
2079
|
'<MPD minBufferTime="PT75S">',
|
|
@@ -2150,4 +2297,77 @@ describe('DashParser Manifest', () => {
|
|
|
2150
2297
|
expect(uri).not.toContain('/p2/');
|
|
2151
2298
|
}
|
|
2152
2299
|
});
|
|
2300
|
+
|
|
2301
|
+
/**
|
|
2302
|
+
* @param {!Array.<number>} periods Start time of multiple periods
|
|
2303
|
+
* @return {string}
|
|
2304
|
+
*/
|
|
2305
|
+
function buildManifestWithPeriodStartTime(periods) {
|
|
2306
|
+
const mpdTemplate = [
|
|
2307
|
+
`<MPD type="dynamic"`,
|
|
2308
|
+
'availabilityStartTime="1970-01-01T00:00:00Z"',
|
|
2309
|
+
'timeShiftBufferDepth="PT10H">',
|
|
2310
|
+
' %(periods)s',
|
|
2311
|
+
'</MPD>',
|
|
2312
|
+
].join('\n');
|
|
2313
|
+
const periodTemplate = (id, period, duration) => {
|
|
2314
|
+
return [
|
|
2315
|
+
` <Period id="${id}" start="PT${period}S">`,
|
|
2316
|
+
' <AdaptationSet mimeType="video/mp4" lang="en" group="1">',
|
|
2317
|
+
' <SegmentTemplate startNumber="1" media="l-$Number$.mp4">',
|
|
2318
|
+
' <SegmentTimeline>',
|
|
2319
|
+
` <S t="0" d="${duration}" />`,
|
|
2320
|
+
' </SegmentTimeline>',
|
|
2321
|
+
' </SegmentTemplate>',
|
|
2322
|
+
' <Representation id="1"/>',
|
|
2323
|
+
' </AdaptationSet>',
|
|
2324
|
+
' </Period>',
|
|
2325
|
+
].join('\n');
|
|
2326
|
+
};
|
|
2327
|
+
const periodXmls = periods.map((period, i) => {
|
|
2328
|
+
const duration = i+1 === periods.length ? 10 : periods[i+1] - period;
|
|
2329
|
+
// Period start time as ID here. If we use index then there will be
|
|
2330
|
+
// periods with same period ID and different start time which are invalid.
|
|
2331
|
+
return periodTemplate(period, period, duration);
|
|
2332
|
+
});
|
|
2333
|
+
return sprintf(mpdTemplate, {
|
|
2334
|
+
periods: periodXmls.join('\n'),
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
// Bug description: Inconsistent period start time in the manifests due
|
|
2339
|
+
// to failover triggered in backend servers
|
|
2340
|
+
|
|
2341
|
+
// When one of the servers is down, the manifest will be served by other
|
|
2342
|
+
// redundant servers. The period start time might become out of sync
|
|
2343
|
+
// during the switch-over/recovery.
|
|
2344
|
+
|
|
2345
|
+
it('skip periods that are earlier than max period start time', async () => {
|
|
2346
|
+
const sources = [
|
|
2347
|
+
buildManifestWithPeriodStartTime([5, 15]),
|
|
2348
|
+
buildManifestWithPeriodStartTime([6, 15]), // simulate out-of-sync of +1s
|
|
2349
|
+
buildManifestWithPeriodStartTime([4, 15]), // simulate out-of-sync of -1s
|
|
2350
|
+
];
|
|
2351
|
+
const segments = [];
|
|
2352
|
+
|
|
2353
|
+
for (const source of sources) {
|
|
2354
|
+
fakeNetEngine.setResponseText('dummy://foo', source);
|
|
2355
|
+
/** @type {shaka.extern.Manifest} */
|
|
2356
|
+
// eslint-disable-next-line no-await-in-loop
|
|
2357
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
2358
|
+
const video = manifest.variants[0].video;
|
|
2359
|
+
// eslint-disable-next-line no-await-in-loop
|
|
2360
|
+
await video.createSegmentIndex();
|
|
2361
|
+
goog.asserts.assert(video.segmentIndex, 'Null segmentIndex!');
|
|
2362
|
+
segments.push(Array.from(video.segmentIndex));
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
// Expect identical segments
|
|
2366
|
+
expect(segments[0].length).toBe(2);
|
|
2367
|
+
expect(segments[1].length).toBe(2);
|
|
2368
|
+
expect(segments[0][0].startTime).toBe(5);
|
|
2369
|
+
expect(segments[1][0].startTime).toBe(5);
|
|
2370
|
+
expect(segments[0][1].startTime).toBe(15);
|
|
2371
|
+
expect(segments[1][1].startTime).toBe(15);
|
|
2372
|
+
});
|
|
2153
2373
|
});
|
|
@@ -35,6 +35,8 @@ describe('DashParser SegmentBase', () => {
|
|
|
35
35
|
|
|
36
36
|
playerInterface = {
|
|
37
37
|
networkingEngine: fakeNetEngine,
|
|
38
|
+
modifyManifestRequest: (request, manifestInfo) => {},
|
|
39
|
+
modifySegmentRequest: (request, segmentInfo) => {},
|
|
38
40
|
filter: (manifest) => Promise.resolve(),
|
|
39
41
|
makeTextStreamsForClosedCaptions: (manifest) => {},
|
|
40
42
|
onTimelineRegionAdded: fail, // Should not have any EventStream elements.
|
|
@@ -344,6 +344,8 @@ describe('DashParser SegmentList', () => {
|
|
|
344
344
|
|
|
345
345
|
const playerInterface = {
|
|
346
346
|
networkingEngine: networkingEngine,
|
|
347
|
+
modifyManifestRequest: (request, manifestInfo) => {},
|
|
348
|
+
modifySegmentRequest: (request, segmentInfo) => {},
|
|
347
349
|
filter: () => {},
|
|
348
350
|
makeTextStreamsForClosedCaptions: (manifest) => {},
|
|
349
351
|
onTimelineRegionAdded: fail, // Should not have any EventStream elements.
|
|
@@ -374,4 +376,3 @@ describe('DashParser SegmentList', () => {
|
|
|
374
376
|
expect(actual).toEqual(expected);
|
|
375
377
|
});
|
|
376
378
|
});
|
|
377
|
-
|
|
@@ -46,6 +46,8 @@ describe('DashParser SegmentTemplate', () => {
|
|
|
46
46
|
|
|
47
47
|
playerInterface = {
|
|
48
48
|
networkingEngine: fakeNetEngine,
|
|
49
|
+
modifyManifestRequest: (request, manifestInfo) => {},
|
|
50
|
+
modifySegmentRequest: (request, segmentInfo) => {},
|
|
49
51
|
filter: (manifest) => Promise.resolve(),
|
|
50
52
|
makeTextStreamsForClosedCaptions: (manifest) => {},
|
|
51
53
|
onTimelineRegionAdded: fail, // Should not have any EventStream elements.
|
|
@@ -585,4 +587,3 @@ describe('DashParser SegmentTemplate', () => {
|
|
|
585
587
|
});
|
|
586
588
|
});
|
|
587
589
|
});
|
|
588
|
-
|
|
@@ -116,6 +116,8 @@ describe('HlsParser live', () => {
|
|
|
116
116
|
|
|
117
117
|
config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
118
118
|
playerInterface = {
|
|
119
|
+
modifyManifestRequest: (request, manifestInfo) => {},
|
|
120
|
+
modifySegmentRequest: (request, segmentInfo) => {},
|
|
119
121
|
filter: () => Promise.resolve(),
|
|
120
122
|
makeTextStreamsForClosedCaptions: (manifest) => {},
|
|
121
123
|
networkingEngine: fakeNetEngine,
|
|
@@ -94,6 +94,8 @@ describe('HlsParser', () => {
|
|
|
94
94
|
config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
95
95
|
onEventSpy = jasmine.createSpy('onEvent');
|
|
96
96
|
playerInterface = {
|
|
97
|
+
modifyManifestRequest: (request, manifestInfo) => {},
|
|
98
|
+
modifySegmentRequest: (request, segmentInfo) => {},
|
|
97
99
|
filter: () => Promise.resolve(),
|
|
98
100
|
makeTextStreamsForClosedCaptions: (manifest) => {},
|
|
99
101
|
networkingEngine: fakeNetEngine,
|
|
@@ -783,7 +785,7 @@ describe('HlsParser', () => {
|
|
|
783
785
|
'RESOLUTION=960x540,FRAME-RATE=120,AUDIO="aud2"\n',
|
|
784
786
|
'video2\n',
|
|
785
787
|
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
|
|
786
|
-
'URI="audio"\n',
|
|
788
|
+
'DEFAULT=YES,URI="audio"\n',
|
|
787
789
|
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud2",LANGUAGE="fr",',
|
|
788
790
|
'URI="audio2"\n',
|
|
789
791
|
].join('');
|
|
@@ -801,6 +803,7 @@ describe('HlsParser', () => {
|
|
|
801
803
|
manifest.anyTimeline();
|
|
802
804
|
manifest.addPartialVariant((variant) => {
|
|
803
805
|
variant.bandwidth = 200;
|
|
806
|
+
variant.primary = true;
|
|
804
807
|
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
805
808
|
stream.size(960, 540);
|
|
806
809
|
});
|
|
@@ -810,6 +813,7 @@ describe('HlsParser', () => {
|
|
|
810
813
|
});
|
|
811
814
|
manifest.addPartialVariant((variant) => {
|
|
812
815
|
variant.bandwidth = 300;
|
|
816
|
+
variant.primary = false;
|
|
813
817
|
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
814
818
|
stream.size(960, 540);
|
|
815
819
|
});
|
|
@@ -1307,6 +1311,8 @@ describe('HlsParser', () => {
|
|
|
1307
1311
|
// stream.
|
|
1308
1312
|
const timeline = actual.presentationTimeline;
|
|
1309
1313
|
expect(timeline.getDuration()).toBe(10);
|
|
1314
|
+
expect(timeline.getSeekRangeStart()).toBe(0);
|
|
1315
|
+
expect(timeline.getSeekRangeEnd()).toBe(10);
|
|
1310
1316
|
|
|
1311
1317
|
expect(actual.textStreams.length).toBe(1);
|
|
1312
1318
|
expect(actual.variants.length).toBe(1);
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
goog.require('shaka.media.ClosedCaptionParser');
|
|
2
8
|
goog.require('shaka.test.Util');
|
|
3
9
|
|
|
@@ -12,4 +18,3 @@ describe('ClosedCaptionParser', () => {
|
|
|
12
18
|
parser.parseFrom(videoSegment);
|
|
13
19
|
});
|
|
14
20
|
});
|
|
15
|
-
|
|
@@ -31,7 +31,7 @@ describe('DrmEngine', () => {
|
|
|
31
31
|
navigator.requestMediaKeySystemAccess;
|
|
32
32
|
const originalLogError = shaka.log.error;
|
|
33
33
|
const originalBatchTime = shaka.media.DrmEngine.KEY_STATUS_BATCH_TIME;
|
|
34
|
-
const originalDecodingInfo =
|
|
34
|
+
const originalDecodingInfo = navigator.mediaCapabilities.decodingInfo;
|
|
35
35
|
|
|
36
36
|
/** @type {!jasmine.Spy} */
|
|
37
37
|
let decodingInfoSpy;
|
|
@@ -76,7 +76,7 @@ describe('DrmEngine', () => {
|
|
|
76
76
|
|
|
77
77
|
beforeEach(() => {
|
|
78
78
|
decodingInfoSpy = jasmine.createSpy('decodingInfo');
|
|
79
|
-
|
|
79
|
+
navigator.mediaCapabilities.decodingInfo =
|
|
80
80
|
shaka.test.Util.spyFunc(decodingInfoSpy);
|
|
81
81
|
|
|
82
82
|
logErrorSpy = jasmine.createSpy('shaka.log.error');
|
|
@@ -153,7 +153,7 @@ describe('DrmEngine', () => {
|
|
|
153
153
|
|
|
154
154
|
navigator.requestMediaKeySystemAccess =
|
|
155
155
|
originalRequestMediaKeySystemAccess;
|
|
156
|
-
|
|
156
|
+
navigator.mediaCapabilities.decodingInfo = originalDecodingInfo;
|
|
157
157
|
shaka.log.error = originalLogError;
|
|
158
158
|
});
|
|
159
159
|
|
|
@@ -2152,6 +2152,50 @@ describe('DrmEngine', () => {
|
|
|
2152
2152
|
[drmInfoAudio]);
|
|
2153
2153
|
expect(returned).toEqual([drmInfoDesired]);
|
|
2154
2154
|
});
|
|
2155
|
+
|
|
2156
|
+
it('dedupes the merged init data based on keyId matching', () => {
|
|
2157
|
+
const serverCert = new Uint8Array(0);
|
|
2158
|
+
const drmInfoVideo = {
|
|
2159
|
+
keySystem: 'drm.abc',
|
|
2160
|
+
licenseServerUri: 'http://abc.drm/license',
|
|
2161
|
+
distinctiveIdentifierRequired: false,
|
|
2162
|
+
persistentStateRequired: true,
|
|
2163
|
+
videoRobustness: 'really_really_ridiculously_good',
|
|
2164
|
+
serverCertificate: serverCert,
|
|
2165
|
+
serverCertificateUri: '',
|
|
2166
|
+
initData: [{keyId: 'v-init'}],
|
|
2167
|
+
keyIds: new Set(['deadbeefdeadbeefdeadbeefdeadbeef']),
|
|
2168
|
+
};
|
|
2169
|
+
const drmInfoAudio = {
|
|
2170
|
+
keySystem: 'drm.abc',
|
|
2171
|
+
licenseServerUri: undefined,
|
|
2172
|
+
distinctiveIdentifierRequired: true,
|
|
2173
|
+
persistentStateRequired: false,
|
|
2174
|
+
audioRobustness: 'good',
|
|
2175
|
+
serverCertificate: undefined,
|
|
2176
|
+
serverCertificateUri: '',
|
|
2177
|
+
initData: [{keyId: 'v-init'}, {keyId: 'a-init'}],
|
|
2178
|
+
keyIds: new Set(['eadbeefdeadbeefdeadbeefdeadbeefd']),
|
|
2179
|
+
};
|
|
2180
|
+
const drmInfoDesired = {
|
|
2181
|
+
keySystem: 'drm.abc',
|
|
2182
|
+
licenseServerUri: 'http://abc.drm/license',
|
|
2183
|
+
distinctiveIdentifierRequired: true,
|
|
2184
|
+
persistentStateRequired: true,
|
|
2185
|
+
audioRobustness: 'good',
|
|
2186
|
+
videoRobustness: 'really_really_ridiculously_good',
|
|
2187
|
+
serverCertificate: serverCert,
|
|
2188
|
+
serverCertificateUri: '',
|
|
2189
|
+
initData: [{keyId: 'v-init'}, {keyId: 'a-init'}],
|
|
2190
|
+
keyIds: new Set([
|
|
2191
|
+
'deadbeefdeadbeefdeadbeefdeadbeef',
|
|
2192
|
+
'eadbeefdeadbeefdeadbeefdeadbeefd',
|
|
2193
|
+
]),
|
|
2194
|
+
};
|
|
2195
|
+
const returned = shaka.media.DrmEngine.getCommonDrmInfos([drmInfoVideo],
|
|
2196
|
+
[drmInfoAudio]);
|
|
2197
|
+
expect(returned).toEqual([drmInfoDesired]);
|
|
2198
|
+
});
|
|
2155
2199
|
}); // describe('getCommonDrmInfos')
|
|
2156
2200
|
|
|
2157
2201
|
describe('configure', () => {
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
goog.require('shaka.media.QualityObserver');
|
|
8
|
+
goog.require('shaka.test.Util');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
describe('QualityObserver', () => {
|
|
12
|
+
/** @type {!shaka.media.QualityObserver} */
|
|
13
|
+
let observer;
|
|
14
|
+
|
|
15
|
+
/** @type {!jasmine.Spy} */
|
|
16
|
+
let onQualityChange;
|
|
17
|
+
|
|
18
|
+
const createQualityInfo = (contentType, bandwidth) => {
|
|
19
|
+
return {
|
|
20
|
+
bandwidth: bandwidth,
|
|
21
|
+
audioSamplingRate: 444000,
|
|
22
|
+
codecs: 'my codec',
|
|
23
|
+
contentType: contentType,
|
|
24
|
+
frameRate: 30,
|
|
25
|
+
height: 720,
|
|
26
|
+
mimeType: 'mime type',
|
|
27
|
+
channelsCount: 2,
|
|
28
|
+
pixelAspectRatio: '1:1',
|
|
29
|
+
width: 1280,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
let emptyBuffer = true;
|
|
33
|
+
let bufferStart = 0;
|
|
34
|
+
let bufferEnd = 0;
|
|
35
|
+
|
|
36
|
+
const quality1 = createQualityInfo('video', 1);
|
|
37
|
+
const quality2 = createQualityInfo('video', 2);
|
|
38
|
+
|
|
39
|
+
const getBufferedInfo = () => {
|
|
40
|
+
if (emptyBuffer) {
|
|
41
|
+
return {
|
|
42
|
+
video: [],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
video: [{start: bufferStart, end: bufferEnd}],
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
onQualityChange = jasmine.createSpy('onQualityChange');
|
|
52
|
+
observer = new shaka.media.QualityObserver(getBufferedInfo);
|
|
53
|
+
observer.setListeners(shaka.test.Util.spyFunc(onQualityChange));
|
|
54
|
+
emptyBuffer = true;
|
|
55
|
+
bufferStart = 0;
|
|
56
|
+
bufferEnd = 0;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('does not call onQualityChange when there are no quality changes', () => {
|
|
60
|
+
observer.poll(10, false);
|
|
61
|
+
expect(onQualityChange).not.toHaveBeenCalled();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('calls onQualityChange when position is after 1st quality change', () => {
|
|
65
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
66
|
+
emptyBuffer = false;
|
|
67
|
+
bufferStart = 10;
|
|
68
|
+
bufferEnd = 20;
|
|
69
|
+
observer.poll(10, false);
|
|
70
|
+
expect(onQualityChange).toHaveBeenCalledWith(quality1, 10);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('does not call onQualityChange when pos advances with no change', () => {
|
|
74
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
75
|
+
emptyBuffer = false;
|
|
76
|
+
bufferStart = 10;
|
|
77
|
+
bufferEnd = 20;
|
|
78
|
+
observer.poll(10, false);
|
|
79
|
+
expect(onQualityChange).toHaveBeenCalledWith(quality1, 10);
|
|
80
|
+
observer.poll(11, false);
|
|
81
|
+
expect(onQualityChange).toHaveBeenCalledTimes(1);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('does not call onQualityChange on seek to unbuffered position', () => {
|
|
85
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
86
|
+
emptyBuffer = false;
|
|
87
|
+
bufferStart = 10;
|
|
88
|
+
bufferEnd = 20;
|
|
89
|
+
observer.poll(15, false);
|
|
90
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality1, 15]);
|
|
91
|
+
observer.addMediaQualityChange(quality2, 20);
|
|
92
|
+
observer.poll(25, true);
|
|
93
|
+
expect(onQualityChange).not.toHaveBeenCalledOnceMore();
|
|
94
|
+
bufferEnd = 30;
|
|
95
|
+
observer.poll(26, false);
|
|
96
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality2, 26]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('calls onQualityChange when position advances over 2nd quality change',
|
|
100
|
+
() => {
|
|
101
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
102
|
+
emptyBuffer = false;
|
|
103
|
+
bufferStart = 10;
|
|
104
|
+
bufferEnd = 20;
|
|
105
|
+
observer.poll(10, false);
|
|
106
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality1, 10]);
|
|
107
|
+
observer.addMediaQualityChange(quality2, 20);
|
|
108
|
+
bufferStart = 10;
|
|
109
|
+
bufferEnd = 30;
|
|
110
|
+
observer.poll(20, false);
|
|
111
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality2, 20]);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('calls onQualityChange when position moves back over a quality chanage',
|
|
115
|
+
() => {
|
|
116
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
117
|
+
emptyBuffer = false;
|
|
118
|
+
bufferStart = 10;
|
|
119
|
+
bufferEnd = 20;
|
|
120
|
+
observer.addMediaQualityChange(quality2, 20);
|
|
121
|
+
bufferStart = 10;
|
|
122
|
+
bufferEnd = 30;
|
|
123
|
+
observer.poll(25, false);
|
|
124
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality2, 25]);
|
|
125
|
+
observer.poll(15, false);
|
|
126
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality1, 15]);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('uses last applied quality when there are two at the same position',
|
|
130
|
+
() => {
|
|
131
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
132
|
+
observer.addMediaQualityChange(quality2, 10);
|
|
133
|
+
emptyBuffer = false;
|
|
134
|
+
bufferStart = 10;
|
|
135
|
+
bufferEnd = 20;
|
|
136
|
+
observer.poll(15, false);
|
|
137
|
+
expect(onQualityChange).toHaveBeenCalledWith(quality2, 15);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -38,14 +38,29 @@ describe('SegmentReference', () => {
|
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
describe('InitSegmentReference', () => {
|
|
41
|
+
const mediaQuality = {
|
|
42
|
+
bandwidth: 1,
|
|
43
|
+
audioSamplingRate: 444000,
|
|
44
|
+
codecs: 'my codec',
|
|
45
|
+
contentType: 'video',
|
|
46
|
+
frameRate: 30,
|
|
47
|
+
height: 720,
|
|
48
|
+
mimeType: 'mime type',
|
|
49
|
+
channelsCount: 2,
|
|
50
|
+
pixelAspectRatio: '1:1',
|
|
51
|
+
width: 1280,
|
|
52
|
+
};
|
|
53
|
+
|
|
41
54
|
it('returns in getters values from constructor parameters', () => {
|
|
42
55
|
const reference = new shaka.media.InitSegmentReference(
|
|
43
56
|
/* getUris= */ () => ['x', 'y'],
|
|
44
57
|
/* startByte= */ 4,
|
|
45
|
-
/* endByte= */ 5
|
|
58
|
+
/* endByte= */ 5,
|
|
59
|
+
mediaQuality);
|
|
46
60
|
|
|
47
61
|
expect(reference.getUris()).toEqual(['x', 'y']);
|
|
48
62
|
expect(reference.getStartByte()).toBe(4);
|
|
49
63
|
expect(reference.getEndByte()).toBe(5);
|
|
64
|
+
expect(reference.getMediaQuality()).toBe(mediaQuality);
|
|
50
65
|
});
|
|
51
66
|
});
|
|
@@ -60,7 +60,6 @@ describe('StreamingEngine', () => {
|
|
|
60
60
|
/** @type {!shaka.media.StreamingEngine} */
|
|
61
61
|
let streamingEngine;
|
|
62
62
|
|
|
63
|
-
|
|
64
63
|
/** @type {shaka.extern.Variant} */
|
|
65
64
|
let variant;
|
|
66
65
|
|
|
@@ -262,6 +261,7 @@ describe('StreamingEngine', () => {
|
|
|
262
261
|
|
|
263
262
|
function createStreamingEngine() {
|
|
264
263
|
const playerInterface = {
|
|
264
|
+
modifySegmentRequest: (request, segmentInfo) => {},
|
|
265
265
|
getPresentationTime: () => playhead.getTime(),
|
|
266
266
|
getBandwidthEstimate: () => 1e6,
|
|
267
267
|
mediaSourceEngine: mediaSourceEngine,
|
|
@@ -270,6 +270,7 @@ describe('StreamingEngine', () => {
|
|
|
270
270
|
onEvent: Util.spyFunc(onEvent),
|
|
271
271
|
onManifestUpdate: () => {},
|
|
272
272
|
onSegmentAppended: () => playhead.notifyOfBufferingChange(),
|
|
273
|
+
onInitSegmentAppended: () => {},
|
|
273
274
|
};
|
|
274
275
|
streamingEngine = new shaka.media.StreamingEngine(
|
|
275
276
|
/** @type {shaka.extern.Manifest} */(manifest), playerInterface);
|
|
@@ -419,8 +420,9 @@ describe('StreamingEngine', () => {
|
|
|
419
420
|
// 3. Playhead seeks to force us back inside the window
|
|
420
421
|
// 4. (maybe) seek if there is a gap at the period boundary
|
|
421
422
|
// 5. (maybe) seek to flush a pipeline stall
|
|
423
|
+
// 6. (maybe) on slower platforms (e.g. GitHub actions)
|
|
422
424
|
expect(seekCount).toBeGreaterThan(2);
|
|
423
|
-
expect(seekCount).toBeLessThan(
|
|
425
|
+
expect(seekCount).toBeLessThan(7);
|
|
424
426
|
});
|
|
425
427
|
});
|
|
426
428
|
|