shaka-player 4.3.9 → 4.4.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/.github/workflows/build-and-test.yaml +11 -18
- package/.github/workflows/compute-incremental-coverage.py +3 -0
- package/.github/workflows/release-please.yaml +7 -0
- package/.github/workflows/selenium-lab-tests.yaml +45 -10
- package/AUTHORS +9 -0
- package/CHANGELOG.md +295 -190
- package/CONTRIBUTORS +8 -0
- package/LICENSE +32 -0
- package/README.md +63 -10
- package/demo/autoTemplate.txt +40 -5
- package/demo/close_button.js +11 -0
- package/demo/common/asset.js +13 -1
- package/demo/common/assets.js +112 -28
- package/demo/common/message_ids.js +25 -1
- package/demo/config.js +69 -10
- package/demo/customWarning.txt +2 -2
- package/demo/index.html +3 -1
- package/demo/locales/en.json +26 -2
- package/demo/locales/source.json +105 -9
- package/demo/main.js +57 -9
- package/demo/search.js +3 -1
- package/demo/service_worker.js +3 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +132 -118
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +132 -118
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +46 -28
- package/dist/locales.js +31 -31
- package/dist/receiver.compiled.debug.js +60 -52
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +60 -52
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +676 -391
- package/dist/shaka-player.compiled.debug.d.ts +676 -391
- package/dist/shaka-player.compiled.debug.externs.js +1188 -616
- package/dist/shaka-player.compiled.debug.js +1046 -700
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +1188 -616
- package/dist/shaka-player.compiled.js +1094 -933
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +677 -392
- package/dist/shaka-player.ui.debug.d.ts +677 -392
- package/dist/shaka-player.ui.debug.externs.js +1023 -451
- package/dist/shaka-player.ui.debug.js +1101 -738
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +1023 -451
- package/dist/shaka-player.ui.js +1244 -1071
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/ad_monetization.md +15 -1
- package/docs/tutorials/application-level-redirects.md +1 -1
- package/docs/tutorials/config.md +9 -5
- package/docs/tutorials/drm-config.md +61 -0
- package/docs/tutorials/fairplay.md +19 -4
- package/docs/tutorials/license-server-auth.md +4 -4
- package/docs/tutorials/license-wrapping.md +2 -2
- package/docs/tutorials/ui-customization.md +7 -3
- package/docs/tutorials/ui.md +7 -7
- package/docs/tutorials/upgrade.md +3 -0
- package/externs/ima.js +123 -2
- package/externs/isoboxer.js +217 -0
- package/externs/mediakeys.js +18 -0
- package/externs/mux.js +1 -105
- package/externs/pictureinpicture.js +48 -0
- package/externs/shaka/ads.js +61 -1
- package/externs/shaka/cea.js +110 -0
- package/externs/shaka/codecs.js +32 -0
- package/externs/shaka/manifest.js +101 -1
- package/externs/shaka/manifest_parser.js +0 -10
- package/externs/shaka/net.js +36 -7
- package/externs/shaka/offline.js +8 -1
- package/externs/shaka/player.js +220 -21
- package/externs/shaka/text.js +1 -382
- package/externs/shaka/transmuxer.js +59 -0
- package/karma.conf.js +15 -0
- package/lib/abr/simple_abr_manager.js +6 -3
- package/lib/ads/ad_manager.js +60 -2
- package/lib/ads/client_side_ad.js +86 -0
- package/lib/ads/client_side_ad_manager.js +93 -5
- package/lib/ads/server_side_ad.js +86 -0
- package/lib/ads/server_side_ad_manager.js +13 -0
- package/lib/cast/cast_utils.js +1 -0
- package/lib/cea/cea608_data_channel.js +24 -14
- package/lib/cea/cea608_memory.js +5 -2
- package/lib/cea/cea708_service.js +8 -9
- package/lib/cea/cea708_window.js +1 -2
- package/lib/cea/cea_decoder.js +23 -6
- package/lib/cea/cea_utils.js +25 -2
- package/lib/cea/dummy_caption_decoder.js +21 -0
- package/lib/cea/dummy_cea_parser.js +1 -3
- package/lib/cea/mp4_cea_parser.js +15 -10
- package/lib/cea/ts_cea_parser.js +69 -0
- package/lib/dash/content_protection.js +32 -2
- package/lib/dash/dash_parser.js +93 -31
- package/lib/dash/mpd_utils.js +6 -25
- package/lib/dash/segment_base.js +12 -14
- package/lib/dash/segment_list.js +10 -6
- package/lib/dash/segment_template.js +349 -32
- package/lib/dependencies/all.js +8 -0
- package/lib/hls/hls_classes.js +33 -8
- package/lib/hls/hls_parser.js +805 -191
- package/lib/hls/manifest_text_parser.js +4 -14
- package/lib/media/adaptation_set_criteria.js +43 -3
- package/lib/media/closed_caption_parser.js +74 -12
- package/lib/media/drm_engine.js +189 -49
- package/lib/media/gap_jumping_controller.js +1 -1
- package/lib/media/manifest_parser.js +34 -0
- package/lib/media/media_source_capabilities.js +10 -0
- package/lib/media/media_source_engine.js +475 -231
- package/lib/media/playhead.js +1 -1
- package/lib/media/presentation_timeline.js +62 -0
- package/lib/media/segment_index.js +50 -14
- package/lib/media/segment_prefetch.js +277 -0
- package/lib/media/segment_reference.js +70 -4
- package/lib/media/streaming_engine.js +258 -81
- package/lib/media/video_wrapper.js +15 -7
- package/lib/mss/content_protection.js +353 -0
- package/lib/mss/mss_parser.js +1081 -0
- package/lib/net/networking_engine.js +60 -10
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +6 -0
- package/lib/offline/storage.js +2 -4
- package/lib/player.js +309 -105
- package/lib/polyfill/media_capabilities.js +43 -3
- package/lib/polyfill/patchedmediakeys_apple.js +5 -0
- package/lib/polyfill/patchedmediakeys_nop.js +5 -0
- package/lib/polyfill/patchedmediakeys_webkit.js +5 -0
- package/lib/text/cue.js +208 -130
- package/lib/text/lrc_text_parser.js +2 -2
- package/lib/text/mp4_vtt_parser.js +2 -2
- package/lib/text/sbv_text_parser.js +1 -1
- package/lib/text/simple_text_displayer.js +2 -1
- package/lib/text/srt_text_parser.js +9 -1
- package/lib/text/ssa_text_parser.js +2 -2
- package/lib/text/text_engine.js +3 -21
- package/lib/text/text_utils.js +71 -20
- package/lib/text/ui_text_displayer.js +14 -14
- package/lib/text/vtt_text_parser.js +22 -14
- package/lib/transmuxer/aac_transmuxer.js +224 -0
- package/lib/transmuxer/ac3.js +142 -0
- package/lib/transmuxer/ac3_transmuxer.js +212 -0
- package/lib/transmuxer/adts.js +232 -0
- package/lib/transmuxer/ec3.js +103 -0
- package/lib/transmuxer/ec3_transmuxer.js +212 -0
- package/lib/transmuxer/h264.js +324 -0
- package/lib/transmuxer/mp3_transmuxer.js +204 -0
- package/lib/transmuxer/mpeg_audio.js +196 -0
- package/lib/transmuxer/mpeg_ts_transmuxer.js +182 -0
- package/lib/transmuxer/mss_transmuxer.js +389 -0
- package/lib/{media/transmuxer.js → transmuxer/muxjs_transmuxer.js} +34 -80
- package/lib/transmuxer/transmuxer_engine.js +161 -0
- package/lib/transmuxer/ts_transmuxer.js +738 -0
- package/lib/util/cmcd_manager.js +131 -71
- package/lib/util/error.js +62 -26
- package/lib/util/exp_golomb.js +220 -0
- package/lib/util/fairplay_utils.js +64 -13
- package/lib/util/id3_utils.js +56 -3
- package/lib/util/language_utils.js +11 -8
- package/lib/util/manifest_parser_utils.js +3 -0
- package/lib/util/mime_utils.js +44 -7
- package/lib/util/mp4_box_parsers.js +233 -5
- package/lib/util/mp4_generator.js +1381 -0
- package/lib/util/periods.js +40 -34
- package/lib/util/platform.js +25 -3
- package/lib/util/player_configuration.js +38 -1
- package/lib/util/stream_utils.js +138 -27
- package/lib/util/text_parser.js +1 -1
- package/lib/util/ts_parser.js +470 -47
- package/lib/util/xml_utils.js +16 -3
- package/maintained-branches.md +2 -2
- package/package.json +4 -2
- package/roadmap.md +21 -6
- package/shaka-player.uncompiled.js +18 -0
- package/test/abr/simple_abr_manager_unit.js +32 -4
- package/test/ads/ad_manager_unit.js +18 -2
- package/test/cast/cast_utils_unit.js +7 -2
- package/test/cea/cea608_memory_unit.js +24 -0
- package/test/cea/cea_decoder_unit.js +33 -0
- package/test/dash/dash_parser_content_protection_unit.js +93 -3
- package/test/dash/dash_parser_live_unit.js +56 -13
- package/test/dash/dash_parser_manifest_unit.js +70 -2
- package/test/dash/dash_parser_segment_base_unit.js +14 -9
- package/test/dash/dash_parser_segment_template_unit.js +286 -6
- package/test/demo/demo_unit.js +5 -1
- package/test/hls/hls_live_unit.js +188 -28
- package/test/hls/hls_parser_unit.js +250 -109
- package/test/hls/manifest_text_parser_unit.js +18 -13
- package/test/media/adaptation_set_criteria_unit.js +46 -14
- package/test/media/adaptation_set_unit.js +2 -0
- package/test/media/drm_engine_integration.js +11 -8
- package/test/media/drm_engine_unit.js +220 -7
- package/test/media/media_source_engine_integration.js +122 -38
- package/test/media/media_source_engine_unit.js +133 -153
- package/test/media/playhead_unit.js +3 -0
- package/test/media/presentation_timeline_unit.js +51 -0
- package/test/media/segment_index_unit.js +52 -0
- package/test/media/segment_prefetch_unit.js +243 -0
- package/test/media/streaming_engine_integration.js +9 -3
- package/test/media/streaming_engine_unit.js +440 -59
- package/test/mss/mss_parser_content_protection_unit.js +49 -0
- package/test/mss/mss_parser_unit.js +472 -0
- package/test/mss/mss_player_integration.js +123 -0
- package/test/offline/manifest_convert_unit.js +9 -0
- package/test/offline/storage_integration.js +6 -1
- package/test/player_integration.js +4 -1
- package/test/player_unit.js +386 -133
- package/test/polyfill/media_capabilities_unit.js +18 -0
- package/test/test/assets/hls-raw-aac/fileSequence0.aac +0 -0
- package/test/test/assets/hls-raw-aac/fileSequence1.aac +0 -0
- package/test/test/assets/hls-raw-aac/fileSequence2.aac +0 -0
- package/test/test/assets/hls-raw-aac/fileSequence3.aac +0 -0
- package/test/test/assets/hls-raw-aac/manifest.m3u8 +4 -0
- package/test/test/assets/hls-raw-aac/stream.m4a.m3u8 +14 -0
- package/test/test/assets/hls-raw-ac3/fileSequence0.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence1.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence2.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence3.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence4.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence5.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence6.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence7.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/prog_index.m3u8 +31 -0
- package/test/test/assets/hls-raw-ec3/fileSequence0.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence1.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence2.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence3.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence4.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence5.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence6.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence7.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/prog_index.m3u8 +31 -0
- package/test/test/assets/hls-raw-mp3/chunklist_w905519204.m3u8 +13 -0
- package/test/test/assets/hls-raw-mp3/media_w905519204_0.mp3 +0 -0
- package/test/test/assets/hls-raw-mp3/media_w905519204_1.mp3 +0 -0
- package/test/test/assets/hls-raw-mp3/media_w905519204_2.mp3 +0 -0
- package/test/test/assets/hls-raw-mp3/media_w905519204_3.mp3 +0 -0
- package/test/test/assets/hls-raw-mp3/playlist.m3u8 +4 -0
- package/test/test/assets/hls-ts-aac/playlist.m3u8 +23 -0
- package/test/test/assets/hls-ts-aac/segment_0.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_1.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_2.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_3.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_4.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_5.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_6.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_7.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0004.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0005.ts +0 -0
- package/test/test/assets/hls-ts-ac3/prog_index.m3u8 +19 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0004.ts +0 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0005.ts +0 -0
- package/test/test/assets/hls-ts-ec3/prog_index.m3u8 +19 -0
- package/test/test/assets/hls-ts-h264/fileSequence0.ts +0 -0
- package/test/test/assets/hls-ts-h264/fileSequence1.ts +0 -0
- package/test/test/assets/hls-ts-h264/fileSequence2.ts +0 -0
- package/test/test/assets/hls-ts-h264/fileSequence3.ts +0 -0
- package/test/test/assets/hls-ts-h264/fileSequence4.ts +0 -0
- package/test/test/assets/hls-ts-h264/fileSequence5.ts +0 -0
- package/test/test/assets/hls-ts-h264/prog_index.m3u8 +25 -0
- package/test/test/assets/hls-ts-mp3/manifest.m3u8 +13 -0
- package/test/test/assets/hls-ts-mp3/media_w239891843_0.ts +0 -0
- package/test/test/assets/hls-ts-mp3/media_w239891843_1.ts +0 -0
- package/test/test/assets/hls-ts-mp3/media_w239891843_2.ts +0 -0
- package/test/test/assets/hls-ts-mp3/media_w239891843_3.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/chunk.m3u8 +17 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_0_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_1_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_2_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_3_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_4_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_5_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/playlist.m3u8 +4 -0
- package/test/test/boot.js +7 -2
- package/test/test/util/fake_ad.js +99 -0
- package/test/test/util/fake_ad_manager.js +7 -1
- package/test/test/util/fake_networking_engine.js +41 -14
- package/test/test/util/fake_segment_prefetch.js +81 -0
- package/test/test/util/manifest_generator.js +19 -5
- package/test/test/util/mss_parser_util.js +115 -0
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/simple_fakes.js +12 -3
- package/test/test/util/streaming_engine_util.js +14 -4
- package/test/test/util/ttml_utils.js +2 -2
- package/test/test/util/ui_utils.js +5 -1
- package/test/text/cue_integration.js +1 -1
- package/test/text/srt_text_parser_unit.js +78 -0
- package/test/text/text_engine_unit.js +17 -8
- package/test/text/ui_text_displayer_unit.js +4 -4
- package/test/text/vtt_text_parser_unit.js +59 -40
- package/test/text/web_vtt_generator_unit.js +9 -3
- package/test/{media/transmuxer_integration.js → transmuxer/muxjs_transmuxer_integration.js} +30 -33
- package/test/transmuxer/transmuxer_engine_integration.js +60 -0
- package/test/transmuxer/transmuxer_integration.js +296 -0
- package/test/util/cmcd_manager_unit.js +162 -13
- package/test/util/language_utils_unit.js +9 -2
- package/test/util/mp4_box_parsers_unit.js +39 -4
- package/test/util/periods_unit.js +34 -26
- package/test/util/stream_utils_unit.js +60 -107
- package/ui/controls.js +19 -1
- package/ui/controls.less +1 -0
- package/ui/externs/ui.js +13 -3
- package/ui/language_utils.js +15 -0
- package/ui/less/thumbnails.less +26 -0
- package/ui/locales/oc.json +42 -0
- package/ui/pip_button.js +83 -2
- package/ui/range_element.js +15 -0
- package/ui/resolution_selection.js +9 -2
- package/ui/seek_bar.js +230 -1
- package/ui/ui.js +5 -0
- package/lib/cea/i_caption_decoder.js +0 -51
- package/lib/cea/i_cea_parser.js +0 -68
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Test DRM-related parsing.
|
|
8
|
+
describe('MssParser ContentProtection', () => {
|
|
9
|
+
const ContentProtection = shaka.mss.ContentProtection;
|
|
10
|
+
|
|
11
|
+
const strToXml = (str) => {
|
|
12
|
+
const parser = new DOMParser();
|
|
13
|
+
return parser.parseFromString(str, 'application/xml').documentElement;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
it('getPlayReadyLicenseURL', () => {
|
|
17
|
+
const laurl = [
|
|
18
|
+
'<WRMHEADER>',
|
|
19
|
+
' <DATA>',
|
|
20
|
+
' <LA_URL>www.example.com</LA_URL>',
|
|
21
|
+
' </DATA>',
|
|
22
|
+
'</WRMHEADER>',
|
|
23
|
+
].join('\n');
|
|
24
|
+
const laurlCodes = laurl.split('').map((c) => {
|
|
25
|
+
return c.charCodeAt();
|
|
26
|
+
});
|
|
27
|
+
const prBytes = new Uint16Array([
|
|
28
|
+
// pr object size (in num bytes).
|
|
29
|
+
// + 10 for PRO size, count, and type
|
|
30
|
+
laurl.length * 2 + 10, 0,
|
|
31
|
+
// record count
|
|
32
|
+
1,
|
|
33
|
+
// type
|
|
34
|
+
ContentProtection.PLAYREADY_RECORD_TYPES.RIGHTS_MANAGEMENT,
|
|
35
|
+
// record size (in num bytes)
|
|
36
|
+
laurl.length * 2,
|
|
37
|
+
// value
|
|
38
|
+
].concat(laurlCodes));
|
|
39
|
+
|
|
40
|
+
const encodedPrObject = shaka.util.Uint8ArrayUtils.toBase64(prBytes);
|
|
41
|
+
const input = strToXml([
|
|
42
|
+
'<ProtectionHeader SystemID="9a04f079-9840-4286-ab92-e65be0885f95">',
|
|
43
|
+
encodedPrObject,
|
|
44
|
+
'</ProtectionHeader>',
|
|
45
|
+
].join('\n'));
|
|
46
|
+
const actual = ContentProtection.getPlayReadyLicenseUrl(input);
|
|
47
|
+
expect(actual).toBe('www.example.com');
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Test basic manifest parsing functionality.
|
|
8
|
+
describe('MssParser Manifest', () => {
|
|
9
|
+
// const ManifestParser = shaka.test.ManifestParser;
|
|
10
|
+
const Mss = shaka.test.Mss;
|
|
11
|
+
|
|
12
|
+
/** @type {!shaka.test.FakeNetworkingEngine} */
|
|
13
|
+
let fakeNetEngine;
|
|
14
|
+
/** @type {!shaka.mss.MssParser} */
|
|
15
|
+
let parser;
|
|
16
|
+
/** @type {!jasmine.Spy} */
|
|
17
|
+
let onEventSpy;
|
|
18
|
+
/** @type {shaka.extern.ManifestParser.PlayerInterface} */
|
|
19
|
+
let playerInterface;
|
|
20
|
+
|
|
21
|
+
const h264CodecPrivateData = '000000016764001FAC2CA5014016EFFC100010014808' +
|
|
22
|
+
'080A000007D200017700C100005A648000B4C9FE31C6080002D3240005A64FF18E1DA' +
|
|
23
|
+
'12251600000000168E9093525';
|
|
24
|
+
|
|
25
|
+
const aacCodecPrivateData = '1210';
|
|
26
|
+
|
|
27
|
+
// From https://test.playready.microsoft.com/smoothstreaming/SSWSS720H264PR/S
|
|
28
|
+
// uperSpeedway_720.ism/Manifest
|
|
29
|
+
const protectionHeader = 'jAMAAAEAAQCCAzwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0A' +
|
|
30
|
+
'bABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzA' +
|
|
31
|
+
'G8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQ' +
|
|
32
|
+
'BhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4' +
|
|
33
|
+
'AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZ' +
|
|
34
|
+
'AEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQ' +
|
|
35
|
+
'wBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AE' +
|
|
36
|
+
'sASQBEAD4AQQBtAGYAagBDAFQATwBQAGIARQBPAGwAMwBXAEQALwA1AG0AYwBlAGMAQQA' +
|
|
37
|
+
'9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBCAEcAdwAxAGEAWQBaADEA' +
|
|
38
|
+
'WQBYAE0APQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABDAFUAUwBUAE8ATQBBAFQAVABSA' +
|
|
39
|
+
'EkAQgBVAFQARQBTAD4APABJAEkAUwBfAEQAUgBNAF8AVgBFAFIAUwBJAE8ATgA+ADcALg' +
|
|
40
|
+
'AxAC4AMQAwADYANAAuADAAPAAvAEkASQBTAF8ARABSAE0AXwBWAEUAUgBTAEkATwBOAD4' +
|
|
41
|
+
'APAAvAEMAVQBTAFQATwBNAEEAVABUAFIASQBCAFUAVABFAFMAPgA8AEwAQQBfAFUAUgBM' +
|
|
42
|
+
'AD4AaAB0AHQAcAA6AC8ALwBwAGwAYQB5AHIAZQBhAGQAeQAuAGQAaQByAGUAYwB0AHQAY' +
|
|
43
|
+
'QBwAHMALgBuAGUAdAAvAHAAcgAvAHMAdgBjAC8AcgBpAGcAaAB0AHMAbQBhAG4AYQBnAG' +
|
|
44
|
+
'UAcgAuAGEAcwBtAHgAPAAvAEwAQQBfAFUAUgBMAD4APABEAFMAXwBJAEQAPgBBAEgAKwA' +
|
|
45
|
+
'wADMAagB1AEsAYgBVAEcAYgBIAGwAMQBWAC8AUQBJAHcAUgBBAD0APQA8AC8ARABTAF8A' +
|
|
46
|
+
'SQBEAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=';
|
|
47
|
+
|
|
48
|
+
/** @param {!shaka.extern.Manifest} manifest */
|
|
49
|
+
async function loadAllStreamsFor(manifest) {
|
|
50
|
+
const promises = [];
|
|
51
|
+
for (const variant of manifest.variants) {
|
|
52
|
+
for (const stream of [variant.video, variant.audio]) {
|
|
53
|
+
if (stream) {
|
|
54
|
+
promises.push(stream.createSegmentIndex());
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const text of manifest.textStreams) {
|
|
59
|
+
promises.push(text.createSegmentIndex());
|
|
60
|
+
}
|
|
61
|
+
await Promise.all(promises);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
fakeNetEngine = new shaka.test.FakeNetworkingEngine();
|
|
66
|
+
parser = Mss.makeMssParser();
|
|
67
|
+
onEventSpy = jasmine.createSpy('onEvent');
|
|
68
|
+
playerInterface = {
|
|
69
|
+
networkingEngine: fakeNetEngine,
|
|
70
|
+
modifyManifestRequest: (request, manifestInfo) => {},
|
|
71
|
+
modifySegmentRequest: (request, segmentInfo) => {},
|
|
72
|
+
filter: (manifest) => Promise.resolve(),
|
|
73
|
+
makeTextStreamsForClosedCaptions: (manifest) => {},
|
|
74
|
+
onTimelineRegionAdded: fail, // Should not have any EventStream elements.
|
|
75
|
+
onEvent: shaka.test.Util.spyFunc(onEventSpy),
|
|
76
|
+
onError: fail,
|
|
77
|
+
isLowLatencyMode: () => false,
|
|
78
|
+
isAutoLowLatencyMode: () => false,
|
|
79
|
+
enableLowLatencyMode: () => {},
|
|
80
|
+
updateDuration: () => {},
|
|
81
|
+
newDrmInfo: (stream) => {},
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('fails for', () => {
|
|
86
|
+
it('invalid XML', async () => {
|
|
87
|
+
const source = '<not XML';
|
|
88
|
+
const error = new shaka.util.Error(
|
|
89
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
90
|
+
shaka.util.Error.Category.MANIFEST,
|
|
91
|
+
shaka.util.Error.Code.MSS_INVALID_XML,
|
|
92
|
+
'dummy://foo');
|
|
93
|
+
await Mss.testFails(source, error);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('XML with inner errors', async () => {
|
|
97
|
+
const source = [
|
|
98
|
+
'<SmoothStreamingMedia Duration="1209510000">',
|
|
99
|
+
' <StreamIndex Name="audio" Type="audio" Url="uri">',
|
|
100
|
+
' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
|
|
101
|
+
aacCodecPrivateData,
|
|
102
|
+
'" FourCC="AACL"/>',
|
|
103
|
+
' <c d="20201360"/>',
|
|
104
|
+
' </StreamIndex', // Missing a close bracket.
|
|
105
|
+
'</SmoothStreamingMedia>',
|
|
106
|
+
].join('\n');
|
|
107
|
+
const error = new shaka.util.Error(
|
|
108
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
109
|
+
shaka.util.Error.Category.MANIFEST,
|
|
110
|
+
shaka.util.Error.Code.MSS_INVALID_XML,
|
|
111
|
+
'dummy://foo');
|
|
112
|
+
await Mss.testFails(source, error);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('failed network requests', async () => {
|
|
116
|
+
const expectedError = new shaka.util.Error(
|
|
117
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
118
|
+
shaka.util.Error.Category.NETWORK,
|
|
119
|
+
shaka.util.Error.Code.BAD_HTTP_STATUS);
|
|
120
|
+
|
|
121
|
+
fakeNetEngine.request.and.returnValue(
|
|
122
|
+
shaka.util.AbortableOperation.failed(expectedError));
|
|
123
|
+
await expectAsync(parser.start('', playerInterface))
|
|
124
|
+
.toBeRejectedWith(shaka.test.Util.jasmineError(expectedError));
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('missing SmoothStreamingMedia element', async () => {
|
|
128
|
+
const source = '<XML></XML>';
|
|
129
|
+
const error = new shaka.util.Error(
|
|
130
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
131
|
+
shaka.util.Error.Category.MANIFEST,
|
|
132
|
+
shaka.util.Error.Code.MSS_INVALID_XML,
|
|
133
|
+
'dummy://foo');
|
|
134
|
+
await Mss.testFails(source, error);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('live content ', async () => {
|
|
138
|
+
const source = [
|
|
139
|
+
'<SmoothStreamingMedia Duration="1209510000" IsLive="true">',
|
|
140
|
+
' <StreamIndex Name="audio" Type="audio" Url="uri">',
|
|
141
|
+
' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
|
|
142
|
+
aacCodecPrivateData,
|
|
143
|
+
'" FourCC="AACL"/>',
|
|
144
|
+
' <c d="20201360"/>',
|
|
145
|
+
' </StreamIndex>',
|
|
146
|
+
'</SmoothStreamingMedia>',
|
|
147
|
+
].join('\n');
|
|
148
|
+
const error = new shaka.util.Error(
|
|
149
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
150
|
+
shaka.util.Error.Category.MANIFEST,
|
|
151
|
+
shaka.util.Error.Code.MSS_LIVE_CONTENT_NOT_SUPPORTED);
|
|
152
|
+
await Mss.testFails(source, error);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('Disable audio does not create audio streams', async () => {
|
|
157
|
+
const manifestText = [
|
|
158
|
+
'<SmoothStreamingMedia Duration="1209510000">',
|
|
159
|
+
' <StreamIndex Type="video" Url="uri">',
|
|
160
|
+
' <QualityLevel Bitrate="2962000" CodecPrivateData="',
|
|
161
|
+
h264CodecPrivateData,
|
|
162
|
+
'" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
|
|
163
|
+
' <c d="20020000"/>',
|
|
164
|
+
' </StreamIndex>',
|
|
165
|
+
' <StreamIndex Name="audio" Type="audio" Url="uri">',
|
|
166
|
+
' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
|
|
167
|
+
aacCodecPrivateData,
|
|
168
|
+
'" FourCC="AACL"/>',
|
|
169
|
+
' <c d="20201360"/>',
|
|
170
|
+
' </StreamIndex>',
|
|
171
|
+
'</SmoothStreamingMedia>',
|
|
172
|
+
].join('\n');
|
|
173
|
+
|
|
174
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
175
|
+
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
176
|
+
config.disableAudio = true;
|
|
177
|
+
parser.configure(config);
|
|
178
|
+
|
|
179
|
+
/** @type {shaka.extern.Manifest} */
|
|
180
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
181
|
+
const variant = manifest.variants[0];
|
|
182
|
+
expect(variant.audio).toBe(null);
|
|
183
|
+
expect(variant.video).toBeTruthy();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('Disable video does not create video streams', async () => {
|
|
187
|
+
const manifestText = [
|
|
188
|
+
'<SmoothStreamingMedia Duration="1209510000">',
|
|
189
|
+
' <StreamIndex Type="video" Url="uri">',
|
|
190
|
+
' <QualityLevel Bitrate="2962000" CodecPrivateData="',
|
|
191
|
+
h264CodecPrivateData,
|
|
192
|
+
'" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
|
|
193
|
+
' <c d="20020000"/>',
|
|
194
|
+
' </StreamIndex>',
|
|
195
|
+
' <StreamIndex Name="audio" Type="audio" Url="uri">',
|
|
196
|
+
' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
|
|
197
|
+
aacCodecPrivateData,
|
|
198
|
+
'" FourCC="AACL"/>',
|
|
199
|
+
' <c d="20201360"/>',
|
|
200
|
+
' </StreamIndex>',
|
|
201
|
+
'</SmoothStreamingMedia>',
|
|
202
|
+
].join('\n');
|
|
203
|
+
|
|
204
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
205
|
+
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
206
|
+
config.disableVideo = true;
|
|
207
|
+
parser.configure(config);
|
|
208
|
+
|
|
209
|
+
/** @type {shaka.extern.Manifest} */
|
|
210
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
211
|
+
const variant = manifest.variants[0];
|
|
212
|
+
expect(variant.audio).toBeTruthy();
|
|
213
|
+
expect(variant.video).toBe(null);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('Disable text does not create text streams', async () => {
|
|
217
|
+
const manifestText = [
|
|
218
|
+
'<SmoothStreamingMedia Duration="1209510000">',
|
|
219
|
+
' <StreamIndex Type="video" Url="uri">',
|
|
220
|
+
' <QualityLevel Bitrate="2962000" CodecPrivateData="',
|
|
221
|
+
h264CodecPrivateData,
|
|
222
|
+
'" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
|
|
223
|
+
' <c d="20020000"/>',
|
|
224
|
+
' </StreamIndex>',
|
|
225
|
+
' <StreamIndex Name="audio" Type="audio" Url="uri">',
|
|
226
|
+
' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
|
|
227
|
+
aacCodecPrivateData,
|
|
228
|
+
'" FourCC="AACL"/>',
|
|
229
|
+
' <c d="20201360"/>',
|
|
230
|
+
' </StreamIndex>',
|
|
231
|
+
' <StreamIndex Name="text" Type="text" Url="uri">',
|
|
232
|
+
' <QualityLevel Bitrate="1000" FourCC="TTML"/>',
|
|
233
|
+
' <c d="20201360"/>',
|
|
234
|
+
' </StreamIndex>',
|
|
235
|
+
'</SmoothStreamingMedia>',
|
|
236
|
+
].join('\n');
|
|
237
|
+
|
|
238
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
239
|
+
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
240
|
+
config.disableText = true;
|
|
241
|
+
parser.configure(config);
|
|
242
|
+
|
|
243
|
+
/** @type {shaka.extern.Manifest} */
|
|
244
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
245
|
+
const stream = manifest.textStreams[0];
|
|
246
|
+
expect(stream).toBeUndefined();
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('Invokes manifestPreprocessor in config', async () => {
|
|
250
|
+
const manifestText = [
|
|
251
|
+
'<SmoothStreamingMedia Duration="1209510000">',
|
|
252
|
+
' <StreamIndex Type="video" Url="uri">',
|
|
253
|
+
' <QualityLevel Bitrate="2962000" CodecPrivateData="',
|
|
254
|
+
h264CodecPrivateData,
|
|
255
|
+
'" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
|
|
256
|
+
' <c d="20020000"/>',
|
|
257
|
+
' </StreamIndex>',
|
|
258
|
+
' <StreamIndex Name="audio" Type="audio" Url="uri">',
|
|
259
|
+
' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
|
|
260
|
+
aacCodecPrivateData,
|
|
261
|
+
'" FourCC="AACL"/>',
|
|
262
|
+
' <c d="20201360"/>',
|
|
263
|
+
' </StreamIndex>',
|
|
264
|
+
' <StreamIndex Name="text" Type="text" Url="uri">',
|
|
265
|
+
' <QualityLevel Bitrate="1000" FourCC="TTML"/>',
|
|
266
|
+
' <c d="20201360"/>',
|
|
267
|
+
' </StreamIndex>',
|
|
268
|
+
'</SmoothStreamingMedia>',
|
|
269
|
+
].join('\n');
|
|
270
|
+
|
|
271
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
272
|
+
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
273
|
+
config.mss.manifestPreprocessor = (mss) => {
|
|
274
|
+
const selector = 'StreamIndex[Name="text"';
|
|
275
|
+
const vttElements = mss.querySelectorAll(selector);
|
|
276
|
+
for (const element of vttElements) {
|
|
277
|
+
element.parentNode.removeChild(element);
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
parser.configure(config);
|
|
281
|
+
|
|
282
|
+
/** @type {shaka.extern.Manifest} */
|
|
283
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
284
|
+
const stream = manifest.textStreams[0];
|
|
285
|
+
expect(stream).toBeUndefined();
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('generate a fake init segment', async () => {
|
|
289
|
+
const manifestText = [
|
|
290
|
+
'<SmoothStreamingMedia Duration="3600000000">',
|
|
291
|
+
' <StreamIndex Name="audio" Type="audio" Url="{bitrate}/{start time}">',
|
|
292
|
+
' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
|
|
293
|
+
aacCodecPrivateData,
|
|
294
|
+
'" FourCC="AACL"/>',
|
|
295
|
+
' <c t="0" d="30000000" r="12"/>',
|
|
296
|
+
' </StreamIndex>',
|
|
297
|
+
'</SmoothStreamingMedia>',
|
|
298
|
+
].join('\n');
|
|
299
|
+
|
|
300
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
301
|
+
|
|
302
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
303
|
+
const segmentReference =
|
|
304
|
+
await Mss.getFirstAudioSegmentReference(manifest);
|
|
305
|
+
const initSegmentReference = segmentReference.initSegmentReference;
|
|
306
|
+
expect(initSegmentReference.getUris()).toEqual([]);
|
|
307
|
+
expect(initSegmentReference.getStartByte()).toBe(0);
|
|
308
|
+
expect(initSegmentReference.getEndByte()).toBe(null);
|
|
309
|
+
expect(initSegmentReference.getSegmentData()).toBeDefined();
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it('skip video stream without CodecPrivateData', async () => {
|
|
313
|
+
const manifestText = [
|
|
314
|
+
'<SmoothStreamingMedia Duration="1209510000">',
|
|
315
|
+
' <StreamIndex Type="video" Url="uri">',
|
|
316
|
+
' <QualityLevel Bitrate="2962000" FourCC="H264" MaxHeight="720" ',
|
|
317
|
+
' MaxWidth="1280"/>',
|
|
318
|
+
' <c d="20020000"/>',
|
|
319
|
+
' </StreamIndex>',
|
|
320
|
+
' <StreamIndex Name="audio" Type="audio" Url="uri">',
|
|
321
|
+
' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
|
|
322
|
+
aacCodecPrivateData,
|
|
323
|
+
'" FourCC="AACL"/>',
|
|
324
|
+
' <c d="20201360"/>',
|
|
325
|
+
' </StreamIndex>',
|
|
326
|
+
'</SmoothStreamingMedia>',
|
|
327
|
+
].join('\n');
|
|
328
|
+
|
|
329
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
330
|
+
|
|
331
|
+
/** @type {shaka.extern.Manifest} */
|
|
332
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
333
|
+
const variant = manifest.variants[0];
|
|
334
|
+
expect(variant.audio).toBeTruthy();
|
|
335
|
+
expect(variant.video).toBe(null);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('skip video stream without FourCC', async () => {
|
|
339
|
+
const manifestText = [
|
|
340
|
+
'<SmoothStreamingMedia Duration="1209510000">',
|
|
341
|
+
' <StreamIndex Type="video" Url="uri">',
|
|
342
|
+
' <QualityLevel Bitrate="2962000" CodecPrivateData="',
|
|
343
|
+
h264CodecPrivateData,
|
|
344
|
+
'" MaxHeight="720" MaxWidth="1280"/>',
|
|
345
|
+
' <c d="20020000"/>',
|
|
346
|
+
' </StreamIndex>',
|
|
347
|
+
' <StreamIndex Name="audio" Type="audio" Url="uri">',
|
|
348
|
+
' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
|
|
349
|
+
aacCodecPrivateData,
|
|
350
|
+
'" FourCC="AACL"/>',
|
|
351
|
+
' <c d="20201360"/>',
|
|
352
|
+
' </StreamIndex>',
|
|
353
|
+
'</SmoothStreamingMedia>',
|
|
354
|
+
].join('\n');
|
|
355
|
+
|
|
356
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
357
|
+
|
|
358
|
+
/** @type {shaka.extern.Manifest} */
|
|
359
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
360
|
+
const variant = manifest.variants[0];
|
|
361
|
+
expect(variant.audio).toBeTruthy();
|
|
362
|
+
expect(variant.video).toBe(null);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it('supports audio stream without FourCC', async () => {
|
|
366
|
+
const manifestText = [
|
|
367
|
+
'<SmoothStreamingMedia Duration="1209510000">',
|
|
368
|
+
' <StreamIndex Type="video" Url="uri">',
|
|
369
|
+
' <QualityLevel Bitrate="2962000" CodecPrivateData="',
|
|
370
|
+
h264CodecPrivateData,
|
|
371
|
+
'" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
|
|
372
|
+
' <c d="20020000"/>',
|
|
373
|
+
' </StreamIndex>',
|
|
374
|
+
' <StreamIndex Name="audio" Type="audio" Url="uri">',
|
|
375
|
+
' <QualityLevel Bitrate="128000" Channels="2" CodecPrivateData="',
|
|
376
|
+
aacCodecPrivateData,
|
|
377
|
+
'"/>',
|
|
378
|
+
' <c d="20201360"/>',
|
|
379
|
+
' </StreamIndex>',
|
|
380
|
+
'</SmoothStreamingMedia>',
|
|
381
|
+
].join('\n');
|
|
382
|
+
|
|
383
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
384
|
+
|
|
385
|
+
/** @type {shaka.extern.Manifest} */
|
|
386
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
387
|
+
const variant = manifest.variants[0];
|
|
388
|
+
expect(variant.audio).toBeTruthy();
|
|
389
|
+
expect(variant.video).toBeTruthy();
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it('supports AACL stream without CodecPrivateData', async () => {
|
|
393
|
+
const manifestText = [
|
|
394
|
+
'<SmoothStreamingMedia Duration="1209510000">',
|
|
395
|
+
' <StreamIndex Type="video" Url="uri">',
|
|
396
|
+
' <QualityLevel Bitrate="2962000" CodecPrivateData="',
|
|
397
|
+
h264CodecPrivateData,
|
|
398
|
+
'" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
|
|
399
|
+
' <c d="20020000"/>',
|
|
400
|
+
' </StreamIndex>',
|
|
401
|
+
' <StreamIndex Name="audio" Type="audio" Url="uri">',
|
|
402
|
+
' <QualityLevel Bitrate="128000" Channels="2" FourCC="AACL"/>',
|
|
403
|
+
' <c d="20201360"/>',
|
|
404
|
+
' </StreamIndex>',
|
|
405
|
+
'</SmoothStreamingMedia>',
|
|
406
|
+
].join('\n');
|
|
407
|
+
|
|
408
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
409
|
+
|
|
410
|
+
/** @type {shaka.extern.Manifest} */
|
|
411
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
412
|
+
const variant = manifest.variants[0];
|
|
413
|
+
expect(variant.audio).toBeTruthy();
|
|
414
|
+
expect(variant.video).toBeTruthy();
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('supports AACH stream without CodecPrivateData', async () => {
|
|
418
|
+
const manifestText = [
|
|
419
|
+
'<SmoothStreamingMedia Duration="1209510000">',
|
|
420
|
+
' <StreamIndex Type="video" Url="uri">',
|
|
421
|
+
' <QualityLevel Bitrate="2962000" CodecPrivateData="',
|
|
422
|
+
h264CodecPrivateData,
|
|
423
|
+
'" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
|
|
424
|
+
' <c d="20020000"/>',
|
|
425
|
+
' </StreamIndex>',
|
|
426
|
+
' <StreamIndex Name="audio" Type="audio" Url="uri">',
|
|
427
|
+
' <QualityLevel Bitrate="128000" Channels="2" FourCC="AACH"/>',
|
|
428
|
+
' <c d="20201360"/>',
|
|
429
|
+
' </StreamIndex>',
|
|
430
|
+
'</SmoothStreamingMedia>',
|
|
431
|
+
].join('\n');
|
|
432
|
+
|
|
433
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
434
|
+
|
|
435
|
+
/** @type {shaka.extern.Manifest} */
|
|
436
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
437
|
+
const variant = manifest.variants[0];
|
|
438
|
+
expect(variant.audio).toBeTruthy();
|
|
439
|
+
expect(variant.video).toBeTruthy();
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
it('recognizes PlayReady System ID with mixed cases', async () => {
|
|
443
|
+
const manifestText = [
|
|
444
|
+
'<SmoothStreamingMedia Duration="1209510000">',
|
|
445
|
+
' <StreamIndex Type="video" Url="uri">',
|
|
446
|
+
' <QualityLevel Bitrate="2962000" CodecPrivateData="',
|
|
447
|
+
h264CodecPrivateData,
|
|
448
|
+
'" FourCC="H264" MaxHeight="720" MaxWidth="1280"/>',
|
|
449
|
+
' <c d="20020000"/>',
|
|
450
|
+
' </StreamIndex>',
|
|
451
|
+
' <Protection>',
|
|
452
|
+
' <ProtectionHeader SystemID="9a04F079-9840-4286-aB92-e65BE0885f95">',
|
|
453
|
+
protectionHeader,
|
|
454
|
+
' </ProtectionHeader>',
|
|
455
|
+
' </Protection>',
|
|
456
|
+
'</SmoothStreamingMedia>',
|
|
457
|
+
].join('\n');
|
|
458
|
+
|
|
459
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
460
|
+
|
|
461
|
+
/** @type {shaka.extern.Manifest} */
|
|
462
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
463
|
+
const variant = manifest.variants[0];
|
|
464
|
+
expect(variant.video.drmInfos.length).toBe(1);
|
|
465
|
+
expect(variant.video.drmInfos[0].keySystem).toBe('com.microsoft.playready');
|
|
466
|
+
// Also able to parse KID correctly
|
|
467
|
+
expect(variant.video.drmInfos[0].keyIds.size).toBe(1);
|
|
468
|
+
// Expected KID: https://testweb.playready.microsoft.com/Content/Content2X
|
|
469
|
+
expect([...(variant.video.drmInfos[0].keyIds.values())][0]).toBe(
|
|
470
|
+
'09E367028F33436CA5DD60FFE6671E70'.toLowerCase());
|
|
471
|
+
});
|
|
472
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
describe('MSS Player', () => {
|
|
8
|
+
const Util = shaka.test.Util;
|
|
9
|
+
|
|
10
|
+
/** @type {!jasmine.Spy} */
|
|
11
|
+
let onErrorSpy;
|
|
12
|
+
|
|
13
|
+
/** @type {!HTMLVideoElement} */
|
|
14
|
+
let video;
|
|
15
|
+
/** @type {shaka.Player} */
|
|
16
|
+
let player;
|
|
17
|
+
/** @type {!shaka.util.EventManager} */
|
|
18
|
+
let eventManager;
|
|
19
|
+
|
|
20
|
+
let compiledShaka;
|
|
21
|
+
|
|
22
|
+
/** @type {!shaka.test.Waiter} */
|
|
23
|
+
let waiter;
|
|
24
|
+
|
|
25
|
+
// eslint-disable-next-line max-len
|
|
26
|
+
const url = 'https://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/Manifest';
|
|
27
|
+
|
|
28
|
+
// eslint-disable-next-line max-len
|
|
29
|
+
const playreadyUrl = 'https://playready.directtaps.net/smoothstreaming/SSWSS720H264/SuperSpeedway_720.ism/Manifest';
|
|
30
|
+
|
|
31
|
+
// eslint-disable-next-line max-len
|
|
32
|
+
const playreadyLicenseUrl = 'https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)';
|
|
33
|
+
|
|
34
|
+
beforeAll(async () => {
|
|
35
|
+
video = shaka.test.UiUtils.createVideoElement();
|
|
36
|
+
document.body.appendChild(video);
|
|
37
|
+
compiledShaka =
|
|
38
|
+
await shaka.test.Loader.loadShaka(getClientArg('uncompiled'));
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
player = new compiledShaka.Player(video);
|
|
43
|
+
|
|
44
|
+
// Make sure we are playing the lowest res available to avoid test flake
|
|
45
|
+
// based on network issues. Note that disabling ABR and setting a low
|
|
46
|
+
// abr.defaultBandwidthEstimate would not be sufficient, because it
|
|
47
|
+
// would only affect the choice of track on the first period. When we
|
|
48
|
+
// cross a period boundary, the default bandwidth estimate will no
|
|
49
|
+
// longer be in effect, and AbrManager may choose higher res tracks for
|
|
50
|
+
// the new period. Using abr.restrictions.maxHeight will let us force
|
|
51
|
+
// AbrManager to the lowest resolution, which is its fallback when these
|
|
52
|
+
// soft restrictions cannot be met.
|
|
53
|
+
player.configure('abr.restrictions.maxHeight', 1);
|
|
54
|
+
|
|
55
|
+
// Disable stall detection, which can interfere with playback tests.
|
|
56
|
+
player.configure('streaming.stallEnabled', false);
|
|
57
|
+
|
|
58
|
+
// Grab event manager from the uncompiled library:
|
|
59
|
+
eventManager = new shaka.util.EventManager();
|
|
60
|
+
waiter = new shaka.test.Waiter(eventManager);
|
|
61
|
+
waiter.setPlayer(player);
|
|
62
|
+
|
|
63
|
+
onErrorSpy = jasmine.createSpy('onError');
|
|
64
|
+
onErrorSpy.and.callFake((event) => fail(event.detail));
|
|
65
|
+
eventManager.listen(player, 'error', Util.spyFunc(onErrorSpy));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
afterEach(async () => {
|
|
69
|
+
eventManager.release();
|
|
70
|
+
await player.destroy();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
afterAll(() => {
|
|
74
|
+
document.body.removeChild(video);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('MSS VoD', async () => {
|
|
78
|
+
await player.load(url, /* startTime= */ null,
|
|
79
|
+
/* mimeType= */ 'application/vnd.ms-sstr+xml');
|
|
80
|
+
await video.play();
|
|
81
|
+
expect(player.isLive()).toBe(false);
|
|
82
|
+
|
|
83
|
+
// Wait for the video to start playback. If it takes longer than 10
|
|
84
|
+
// seconds, fail the test.
|
|
85
|
+
await waiter.waitForMovementOrFailOnTimeout(video, 10);
|
|
86
|
+
|
|
87
|
+
// Play for 5 seconds, but stop early if the video ends. If it takes
|
|
88
|
+
// longer than 10 seconds, fail the test.
|
|
89
|
+
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 5, 10);
|
|
90
|
+
|
|
91
|
+
await player.unload();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('MSS VoD PlayReady', async () => {
|
|
95
|
+
const support = await shaka.media.DrmEngine.probeSupport();
|
|
96
|
+
if (!support['com.microsoft.playready']) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
player.configure({
|
|
101
|
+
drm: {
|
|
102
|
+
servers: {
|
|
103
|
+
'com.microsoft.playready': playreadyLicenseUrl,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
await player.load(playreadyUrl, /* startTime= */ null,
|
|
109
|
+
/* mimeType= */ 'application/vnd.ms-sstr+xml');
|
|
110
|
+
await video.play();
|
|
111
|
+
expect(player.isLive()).toBe(false);
|
|
112
|
+
|
|
113
|
+
// Wait for the video to start playback. If it takes longer than 10
|
|
114
|
+
// seconds, fail the test.
|
|
115
|
+
await waiter.waitForMovementOrFailOnTimeout(video, 10);
|
|
116
|
+
|
|
117
|
+
// Play for 5 seconds, but stop early if the video ends. If it takes
|
|
118
|
+
// longer than 10 seconds, fail the test.
|
|
119
|
+
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 5, 10);
|
|
120
|
+
|
|
121
|
+
await player.unload();
|
|
122
|
+
});
|
|
123
|
+
});
|