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
|
@@ -42,7 +42,13 @@ describe('MediaSourceEngine', () => {
|
|
|
42
42
|
const originalCreateMediaSource =
|
|
43
43
|
// eslint-disable-next-line no-restricted-syntax
|
|
44
44
|
shaka.media.MediaSourceEngine.prototype.createMediaSource;
|
|
45
|
-
|
|
45
|
+
|
|
46
|
+
const originalFindTransmuxer =
|
|
47
|
+
shaka.transmuxer.TransmuxerEngine.findTransmuxer;
|
|
48
|
+
const originalConvertCodecs =
|
|
49
|
+
shaka.transmuxer.TransmuxerEngine.convertCodecs;
|
|
50
|
+
const originalIsSupported =
|
|
51
|
+
shaka.transmuxer.TransmuxerEngine.isSupported;
|
|
46
52
|
|
|
47
53
|
// Jasmine Spies don't handle toHaveBeenCalledWith well with objects, so use
|
|
48
54
|
// some numbers instead.
|
|
@@ -50,11 +56,14 @@ describe('MediaSourceEngine', () => {
|
|
|
50
56
|
const buffer2 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (2));
|
|
51
57
|
const buffer3 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (3));
|
|
52
58
|
|
|
53
|
-
const fakeVideoStream = {mimeType: 'video/
|
|
54
|
-
const fakeAudioStream = {mimeType: 'audio/
|
|
55
|
-
const fakeTextStream = {mimeType: 'text/
|
|
59
|
+
const fakeVideoStream = {mimeType: 'video/mp4', drmInfos: [{}]};
|
|
60
|
+
const fakeAudioStream = {mimeType: 'audio/mp4', drmInfos: []};
|
|
61
|
+
const fakeTextStream = {mimeType: 'text/mp4', drmInfos: []};
|
|
56
62
|
const fakeTransportStream = {mimeType: 'tsMimetype', drmInfos: []};
|
|
57
63
|
|
|
64
|
+
/** @type {shaka.extern.Stream} */
|
|
65
|
+
const fakeStream = shaka.test.StreamingEngineUtil.createMockVideoStream(1);
|
|
66
|
+
|
|
58
67
|
let audioSourceBuffer;
|
|
59
68
|
let videoSourceBuffer;
|
|
60
69
|
let mockVideo;
|
|
@@ -73,6 +82,10 @@ describe('MediaSourceEngine', () => {
|
|
|
73
82
|
|
|
74
83
|
/** @type {!jasmine.Spy} */
|
|
75
84
|
let createMediaSourceSpy;
|
|
85
|
+
/** @type {!jasmine.Spy} */
|
|
86
|
+
let requiresEncryptionInfoInAllInitSegmentsSpy;
|
|
87
|
+
/** @type {!jasmine.Spy} */
|
|
88
|
+
let fakeEncryptionSpy;
|
|
76
89
|
|
|
77
90
|
/** @type {!shaka.media.MediaSourceEngine} */
|
|
78
91
|
let mediaSourceEngine;
|
|
@@ -89,7 +102,12 @@ describe('MediaSourceEngine', () => {
|
|
|
89
102
|
|
|
90
103
|
afterAll(() => {
|
|
91
104
|
window.MediaSource.isTypeSupported = originalIsTypeSupported;
|
|
92
|
-
shaka.
|
|
105
|
+
shaka.transmuxer.TransmuxerEngine.findTransmuxer =
|
|
106
|
+
originalFindTransmuxer;
|
|
107
|
+
shaka.transmuxer.TransmuxerEngine.convertCodecs =
|
|
108
|
+
originalConvertCodecs;
|
|
109
|
+
shaka.transmuxer.TransmuxerEngine.isSupported =
|
|
110
|
+
originalIsSupported;
|
|
93
111
|
});
|
|
94
112
|
|
|
95
113
|
beforeEach(/** @suppress {invalidCasts} */ () => {
|
|
@@ -101,17 +119,18 @@ describe('MediaSourceEngine', () => {
|
|
|
101
119
|
return type == 'audio' ? audioSourceBuffer : videoSourceBuffer;
|
|
102
120
|
});
|
|
103
121
|
mockTransmuxer = new shaka.test.FakeTransmuxer();
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
shaka.
|
|
113
|
-
|
|
114
|
-
|
|
122
|
+
shaka.transmuxer.TransmuxerEngine.findTransmuxer =
|
|
123
|
+
(mimeType) => {
|
|
124
|
+
return () => mockTransmuxer;
|
|
125
|
+
};
|
|
126
|
+
shaka.transmuxer.TransmuxerEngine.convertCodecs =
|
|
127
|
+
(mimeType, contentType) => {
|
|
128
|
+
return 'video/mp4; codecs="avc1.42E01E"';
|
|
129
|
+
};
|
|
130
|
+
shaka.transmuxer.TransmuxerEngine.isSupported =
|
|
131
|
+
(mimeType, contentType) => {
|
|
132
|
+
return mimeType == 'tsMimetype';
|
|
133
|
+
};
|
|
115
134
|
|
|
116
135
|
shaka.text.TextEngine = createMockTextEngineCtor();
|
|
117
136
|
|
|
@@ -124,6 +143,12 @@ describe('MediaSourceEngine', () => {
|
|
|
124
143
|
shaka.media.MediaSourceEngine.prototype.createMediaSource =
|
|
125
144
|
Util.spyFunc(createMediaSourceSpy);
|
|
126
145
|
|
|
146
|
+
requiresEncryptionInfoInAllInitSegmentsSpy = spyOn(shaka.util.Platform,
|
|
147
|
+
'requiresEncryptionInfoInAllInitSegments').and.returnValue(false);
|
|
148
|
+
|
|
149
|
+
fakeEncryptionSpy = spyOn(shaka.media.ContentWorkarounds, 'fakeEncryption')
|
|
150
|
+
.and.callFake((data) => data + 100);
|
|
151
|
+
|
|
127
152
|
// MediaSourceEngine uses video to:
|
|
128
153
|
// - set src attribute
|
|
129
154
|
// - read error codes when operations fail
|
|
@@ -254,8 +279,8 @@ describe('MediaSourceEngine', () => {
|
|
|
254
279
|
initObject.set(ContentType.AUDIO, fakeAudioStream);
|
|
255
280
|
initObject.set(ContentType.VIDEO, fakeVideoStream);
|
|
256
281
|
await mediaSourceEngine.init(initObject, false);
|
|
257
|
-
expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('audio/
|
|
258
|
-
expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('video/
|
|
282
|
+
expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('audio/mp4');
|
|
283
|
+
expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledWith('video/mp4');
|
|
259
284
|
expect(shaka.text.TextEngine).not.toHaveBeenCalled();
|
|
260
285
|
});
|
|
261
286
|
|
|
@@ -381,9 +406,45 @@ describe('MediaSourceEngine', () => {
|
|
|
381
406
|
await mediaSourceEngine.init(initObject, false);
|
|
382
407
|
});
|
|
383
408
|
|
|
409
|
+
it('should apply fake encryption by default', async () => {
|
|
410
|
+
requiresEncryptionInfoInAllInitSegmentsSpy.and.returnValue(true);
|
|
411
|
+
|
|
412
|
+
const p = mediaSourceEngine.appendBuffer(
|
|
413
|
+
ContentType.VIDEO, buffer, null, fakeStream,
|
|
414
|
+
/* hasClosedCaptions= */ false);
|
|
415
|
+
|
|
416
|
+
expect(fakeEncryptionSpy).toHaveBeenCalled();
|
|
417
|
+
|
|
418
|
+
expect(videoSourceBuffer.appendBuffer)
|
|
419
|
+
.toHaveBeenCalledWith((buffer + 100));
|
|
420
|
+
videoSourceBuffer.updateend();
|
|
421
|
+
|
|
422
|
+
await p;
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
it('should not apply fake encryption when config is off', async () => {
|
|
426
|
+
requiresEncryptionInfoInAllInitSegmentsSpy.and.returnValue(true);
|
|
427
|
+
|
|
428
|
+
const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
|
|
429
|
+
config.insertFakeEncryptionInInit = false;
|
|
430
|
+
|
|
431
|
+
mediaSourceEngine.configure(config);
|
|
432
|
+
|
|
433
|
+
const p = mediaSourceEngine.appendBuffer(
|
|
434
|
+
ContentType.VIDEO, buffer, null, fakeStream,
|
|
435
|
+
/* hasClosedCaptions= */ false);
|
|
436
|
+
|
|
437
|
+
expect(fakeEncryptionSpy).not.toHaveBeenCalled();
|
|
438
|
+
|
|
439
|
+
expect(videoSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
|
|
440
|
+
videoSourceBuffer.updateend();
|
|
441
|
+
|
|
442
|
+
await p;
|
|
443
|
+
});
|
|
444
|
+
|
|
384
445
|
it('appends the given data', async () => {
|
|
385
446
|
const p = mediaSourceEngine.appendBuffer(
|
|
386
|
-
ContentType.AUDIO, buffer, null,
|
|
447
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
387
448
|
/* hasClosedCaptions= */ false);
|
|
388
449
|
expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
|
|
389
450
|
audioSourceBuffer.updateend();
|
|
@@ -392,15 +453,16 @@ describe('MediaSourceEngine', () => {
|
|
|
392
453
|
|
|
393
454
|
it('rejects promise when operation throws', async () => {
|
|
394
455
|
audioSourceBuffer.appendBuffer.and.throwError('fail!');
|
|
395
|
-
mockVideo.error = {code: 5};
|
|
456
|
+
mockVideo.error = {code: 5, message: 'something failed'};
|
|
396
457
|
const expected = Util.jasmineError(new shaka.util.Error(
|
|
397
458
|
shaka.util.Error.Severity.CRITICAL,
|
|
398
459
|
shaka.util.Error.Category.MEDIA,
|
|
399
460
|
shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_THREW,
|
|
400
|
-
jasmine.objectContaining({message: 'fail!'})
|
|
461
|
+
jasmine.objectContaining({message: 'fail!'}),
|
|
462
|
+
{code: 5, message: 'something failed'}));
|
|
401
463
|
await expectAsync(
|
|
402
464
|
mediaSourceEngine.appendBuffer(
|
|
403
|
-
ContentType.AUDIO, buffer, null,
|
|
465
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
404
466
|
/* hasClosedCaptions= */ false))
|
|
405
467
|
.toBeRejectedWith(expected);
|
|
406
468
|
expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
|
|
@@ -419,7 +481,7 @@ describe('MediaSourceEngine', () => {
|
|
|
419
481
|
ContentType.AUDIO));
|
|
420
482
|
await expectAsync(
|
|
421
483
|
mediaSourceEngine.appendBuffer(
|
|
422
|
-
ContentType.AUDIO, buffer, null,
|
|
484
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
423
485
|
/* hasClosedCaptions= */ false))
|
|
424
486
|
.toBeRejectedWith(expected);
|
|
425
487
|
expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
|
|
@@ -440,10 +502,10 @@ describe('MediaSourceEngine', () => {
|
|
|
440
502
|
ContentType.AUDIO));
|
|
441
503
|
|
|
442
504
|
const p1 = mediaSourceEngine.appendBuffer(
|
|
443
|
-
ContentType.AUDIO, buffer, null,
|
|
505
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
444
506
|
/* hasClosedCaptions= */ false);
|
|
445
507
|
const p2 = mediaSourceEngine.appendBuffer(
|
|
446
|
-
ContentType.AUDIO, buffer, null,
|
|
508
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
447
509
|
/* hasClosedCaptions= */ false);
|
|
448
510
|
audioSourceBuffer.updateend();
|
|
449
511
|
await expectAsync(p1).toBeResolved();
|
|
@@ -453,7 +515,7 @@ describe('MediaSourceEngine', () => {
|
|
|
453
515
|
it('rejects the promise if this operation fails async', async () => {
|
|
454
516
|
mockVideo.error = {code: 5};
|
|
455
517
|
const p = mediaSourceEngine.appendBuffer(
|
|
456
|
-
ContentType.AUDIO, buffer, null,
|
|
518
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
457
519
|
/* hasClosedCaptions= */ false);
|
|
458
520
|
audioSourceBuffer.error();
|
|
459
521
|
audioSourceBuffer.updateend();
|
|
@@ -470,11 +532,11 @@ describe('MediaSourceEngine', () => {
|
|
|
470
532
|
it('queues operations on a single SourceBuffer', async () => {
|
|
471
533
|
/** @type {!shaka.test.StatusPromise} */
|
|
472
534
|
const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
|
|
473
|
-
ContentType.AUDIO, buffer, null,
|
|
535
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
474
536
|
/* hasClosedCaptions= */ false));
|
|
475
537
|
/** @type {!shaka.test.StatusPromise} */
|
|
476
538
|
const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
|
|
477
|
-
ContentType.AUDIO, buffer2, null,
|
|
539
|
+
ContentType.AUDIO, buffer2, null, fakeStream,
|
|
478
540
|
/* hasClosedCaptions= */ false));
|
|
479
541
|
|
|
480
542
|
expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
|
|
@@ -493,15 +555,15 @@ describe('MediaSourceEngine', () => {
|
|
|
493
555
|
it('queues operations independently for different types', async () => {
|
|
494
556
|
/** @type {!shaka.test.StatusPromise} */
|
|
495
557
|
const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
|
|
496
|
-
ContentType.AUDIO, buffer, null,
|
|
558
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
497
559
|
/* hasClosedCaptions= */ false));
|
|
498
560
|
/** @type {!shaka.test.StatusPromise} */
|
|
499
561
|
const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
|
|
500
|
-
ContentType.AUDIO, buffer2, null,
|
|
562
|
+
ContentType.AUDIO, buffer2, null, fakeStream,
|
|
501
563
|
/* hasClosedCaptions= */ false));
|
|
502
564
|
/** @type {!shaka.test.StatusPromise} */
|
|
503
565
|
const p3 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
|
|
504
|
-
ContentType.VIDEO, buffer3, null,
|
|
566
|
+
ContentType.VIDEO, buffer3, null, fakeStream,
|
|
505
567
|
/* hasClosedCaptions= */ false));
|
|
506
568
|
|
|
507
569
|
expect(audioSourceBuffer.appendBuffer).toHaveBeenCalledWith(buffer);
|
|
@@ -536,13 +598,13 @@ describe('MediaSourceEngine', () => {
|
|
|
536
598
|
});
|
|
537
599
|
|
|
538
600
|
const p1 = mediaSourceEngine.appendBuffer(
|
|
539
|
-
ContentType.AUDIO, buffer, null,
|
|
601
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
540
602
|
/* hasClosedCaptions= */ false);
|
|
541
603
|
const p2 = mediaSourceEngine.appendBuffer(
|
|
542
|
-
ContentType.AUDIO, buffer2, null,
|
|
604
|
+
ContentType.AUDIO, buffer2, null, fakeStream,
|
|
543
605
|
/* hasClosedCaptions= */ false);
|
|
544
606
|
const p3 = mediaSourceEngine.appendBuffer(
|
|
545
|
-
ContentType.AUDIO, buffer3, null,
|
|
607
|
+
ContentType.AUDIO, buffer3, null, fakeStream,
|
|
546
608
|
/* hasClosedCaptions= */ false);
|
|
547
609
|
|
|
548
610
|
await expectAsync(p1).toBeResolved();
|
|
@@ -558,12 +620,13 @@ describe('MediaSourceEngine', () => {
|
|
|
558
620
|
expect(mockTextEngine.appendBuffer).not.toHaveBeenCalled();
|
|
559
621
|
const reference = dummyReference(0, 10);
|
|
560
622
|
await mediaSourceEngine.appendBuffer(
|
|
561
|
-
ContentType.TEXT, data, reference,
|
|
623
|
+
ContentType.TEXT, data, reference, fakeStream,
|
|
624
|
+
/* hasClosedCaptions= */ false);
|
|
562
625
|
expect(mockTextEngine.appendBuffer).toHaveBeenCalledWith(
|
|
563
626
|
data, 0, 10);
|
|
564
627
|
});
|
|
565
628
|
|
|
566
|
-
it('appends transmuxed data
|
|
629
|
+
it('appends transmuxed data', async () => {
|
|
567
630
|
const initObject = new Map();
|
|
568
631
|
initObject.set(ContentType.VIDEO, fakeTransportStream);
|
|
569
632
|
|
|
@@ -576,9 +639,8 @@ describe('MediaSourceEngine', () => {
|
|
|
576
639
|
const init = async () => {
|
|
577
640
|
await mediaSourceEngine.init(initObject, false);
|
|
578
641
|
await mediaSourceEngine.appendBuffer(
|
|
579
|
-
ContentType.VIDEO, buffer, null,
|
|
642
|
+
ContentType.VIDEO, buffer, null, fakeStream,
|
|
580
643
|
/* hasClosedCaptions= */ false);
|
|
581
|
-
expect(mockTextEngine.storeAndAppendClosedCaptions).toHaveBeenCalled();
|
|
582
644
|
expect(videoSourceBuffer.appendBuffer).toHaveBeenCalled();
|
|
583
645
|
};
|
|
584
646
|
|
|
@@ -593,38 +655,6 @@ describe('MediaSourceEngine', () => {
|
|
|
593
655
|
await Promise.all([init(), delay()]);
|
|
594
656
|
});
|
|
595
657
|
|
|
596
|
-
it('appends only transmuxed data without embedded text', async () => {
|
|
597
|
-
const initObject = new Map();
|
|
598
|
-
initObject.set(ContentType.VIDEO, fakeTransportStream);
|
|
599
|
-
|
|
600
|
-
const output = {
|
|
601
|
-
data: new Uint8Array(1),
|
|
602
|
-
captions: [],
|
|
603
|
-
};
|
|
604
|
-
mockTransmuxer.transmux.and.returnValue(Promise.resolve(output));
|
|
605
|
-
|
|
606
|
-
const init = async () => {
|
|
607
|
-
await mediaSourceEngine.init(initObject, false);
|
|
608
|
-
await mediaSourceEngine.appendBuffer(
|
|
609
|
-
ContentType.VIDEO, buffer, null,
|
|
610
|
-
/* hasClosedCaptions= */ false);
|
|
611
|
-
expect(mockTextEngine.storeAndAppendClosedCaptions)
|
|
612
|
-
.not.toHaveBeenCalled();
|
|
613
|
-
expect(videoSourceBuffer.appendBuffer)
|
|
614
|
-
.toHaveBeenCalledWith(output.data);
|
|
615
|
-
};
|
|
616
|
-
|
|
617
|
-
// The 'updateend' event fires once the data is done appending to the
|
|
618
|
-
// media source. We only append to the media source once transmuxing is
|
|
619
|
-
// done. Since transmuxing is done using Promises, we need to delay the
|
|
620
|
-
// event until MediaSourceEngine calls appendBuffer.
|
|
621
|
-
const delay = async () => {
|
|
622
|
-
await Util.shortDelay();
|
|
623
|
-
videoSourceBuffer.updateend();
|
|
624
|
-
};
|
|
625
|
-
await Promise.all([init(), delay()]);
|
|
626
|
-
});
|
|
627
|
-
|
|
628
658
|
it('appends parsed closed captions from CaptionParser', async () => {
|
|
629
659
|
const initObject = new Map();
|
|
630
660
|
initObject.set(ContentType.VIDEO, fakeVideoStream);
|
|
@@ -637,7 +667,7 @@ describe('MediaSourceEngine', () => {
|
|
|
637
667
|
|
|
638
668
|
// Initialize the closed caption parser.
|
|
639
669
|
const appendInit = mediaSourceEngine.appendBuffer(
|
|
640
|
-
ContentType.VIDEO, buffer, null,
|
|
670
|
+
ContentType.VIDEO, buffer, null, fakeStream,
|
|
641
671
|
/* hasClosedCaptions= */ true);
|
|
642
672
|
// In MediaSourceEngine, appendBuffer() is async and Promise-based, but
|
|
643
673
|
// at the browser level, it's event-based.
|
|
@@ -653,7 +683,8 @@ describe('MediaSourceEngine', () => {
|
|
|
653
683
|
// Parse and append the closed captions embedded in video stream.
|
|
654
684
|
const reference = dummyReference(0, 1000);
|
|
655
685
|
const appendVideo = mediaSourceEngine.appendBuffer(
|
|
656
|
-
ContentType.VIDEO, buffer, reference,
|
|
686
|
+
ContentType.VIDEO, buffer, reference, fakeStream,
|
|
687
|
+
/* hasClosedCaptions= */ true);
|
|
657
688
|
videoSourceBuffer.updateend();
|
|
658
689
|
await appendVideo;
|
|
659
690
|
|
|
@@ -665,8 +696,7 @@ describe('MediaSourceEngine', () => {
|
|
|
665
696
|
initObject.set(ContentType.VIDEO, fakeVideoStream);
|
|
666
697
|
videoSourceBuffer.mode = 'sequence';
|
|
667
698
|
|
|
668
|
-
await mediaSourceEngine.init(
|
|
669
|
-
initObject, /* forceTransmux= */ false, /* sequenceMode= */ true);
|
|
699
|
+
await mediaSourceEngine.init(initObject, /* sequenceMode= */ true);
|
|
670
700
|
|
|
671
701
|
expect(videoSourceBuffer.timestampOffset).toBe(0);
|
|
672
702
|
|
|
@@ -675,67 +705,14 @@ describe('MediaSourceEngine', () => {
|
|
|
675
705
|
const reference = dummyReference(0, 1000);
|
|
676
706
|
reference.startTime = 0.50;
|
|
677
707
|
const appendVideo = mediaSourceEngine.appendBuffer(
|
|
678
|
-
ContentType.VIDEO, buffer, reference,
|
|
708
|
+
ContentType.VIDEO, buffer, reference, fakeStream,
|
|
709
|
+
/* hasClosedCaptions= */ false,
|
|
679
710
|
/* seeked= */ false, /* adaptation= */ true);
|
|
680
711
|
videoSourceBuffer.updateend();
|
|
681
712
|
await appendVideo;
|
|
682
713
|
|
|
683
714
|
expect(videoSourceBuffer.timestampOffset).toBe(0.50);
|
|
684
715
|
});
|
|
685
|
-
|
|
686
|
-
it('calls abort before setting timestampOffset', async () => {
|
|
687
|
-
const simulateUpdate = async () => {
|
|
688
|
-
await Util.shortDelay();
|
|
689
|
-
videoSourceBuffer.updateend();
|
|
690
|
-
};
|
|
691
|
-
const initObject = new Map();
|
|
692
|
-
initObject.set(ContentType.VIDEO, fakeVideoStream);
|
|
693
|
-
|
|
694
|
-
await mediaSourceEngine.init(
|
|
695
|
-
initObject, /* forceTransmux= */ false, /* sequenceMode= */ true);
|
|
696
|
-
|
|
697
|
-
// First, mock the scenario where timestampOffset is set to help align
|
|
698
|
-
// text segments. In this case, SourceBuffer mode is still 'segments'.
|
|
699
|
-
let reference = dummyReference(0, 1000);
|
|
700
|
-
let appendVideo = mediaSourceEngine.appendBuffer(
|
|
701
|
-
ContentType.VIDEO, buffer, reference, /* hasClosedCaptions= */ false);
|
|
702
|
-
// Wait for the first appendBuffer(), in segments mode.
|
|
703
|
-
await simulateUpdate();
|
|
704
|
-
// Next, wait for abort(), used to reset the parser state for a safe
|
|
705
|
-
// setting of timestampOffset. Shaka fakes an updateend event on abort(),
|
|
706
|
-
// so simulateUpdate() isn't needed.
|
|
707
|
-
await Util.shortDelay();
|
|
708
|
-
// Next, wait for remove(), used to clear the SourceBuffer from the
|
|
709
|
-
// initial append.
|
|
710
|
-
await simulateUpdate();
|
|
711
|
-
// Next, wait for the second appendBuffer(), falling through to normal
|
|
712
|
-
// operations.
|
|
713
|
-
await simulateUpdate();
|
|
714
|
-
// Lastly, wait for the function-scoped MediaSourceEngine#appendBuffer()
|
|
715
|
-
// promise to resolve.
|
|
716
|
-
await appendVideo;
|
|
717
|
-
expect(videoSourceBuffer.abort).toHaveBeenCalledTimes(1);
|
|
718
|
-
|
|
719
|
-
// Second, mock the scenario where timestampOffset is set during an
|
|
720
|
-
// unbuffered seek or adaptation. SourceBuffer mode is 'sequence' now.
|
|
721
|
-
reference = dummyReference(0, 1000);
|
|
722
|
-
appendVideo = mediaSourceEngine.appendBuffer(
|
|
723
|
-
ContentType.VIDEO, buffer, reference, /* hasClosedCaptions= */ false,
|
|
724
|
-
/* seeked= */ true);
|
|
725
|
-
// First, wait for abort(), used to reset the parser state for a safe
|
|
726
|
-
// setting of timestampOffset.
|
|
727
|
-
await Util.shortDelay();
|
|
728
|
-
// The subsequent setTimestampOffset() fakes an updateend event for us, so
|
|
729
|
-
// simulateUpdate() isn't needed.
|
|
730
|
-
await Util.shortDelay();
|
|
731
|
-
// Next, wait for the second appendBuffer(), falling through to normal
|
|
732
|
-
// operations.
|
|
733
|
-
await simulateUpdate();
|
|
734
|
-
// Lastly, wait for the function-scoped MediaSourceEngine#appendBuffer()
|
|
735
|
-
// promise to resolve.
|
|
736
|
-
await appendVideo;
|
|
737
|
-
expect(videoSourceBuffer.abort).toHaveBeenCalledTimes(2);
|
|
738
|
-
});
|
|
739
716
|
});
|
|
740
717
|
|
|
741
718
|
describe('remove', () => {
|
|
@@ -765,7 +742,8 @@ describe('MediaSourceEngine', () => {
|
|
|
765
742
|
shaka.util.Error.Severity.CRITICAL,
|
|
766
743
|
shaka.util.Error.Category.MEDIA,
|
|
767
744
|
shaka.util.Error.Code.MEDIA_SOURCE_OPERATION_THREW,
|
|
768
|
-
jasmine.objectContaining({message: 'fail!'})
|
|
745
|
+
jasmine.objectContaining({message: 'fail!'}),
|
|
746
|
+
{code: 5}));
|
|
769
747
|
await expectAsync(mediaSourceEngine.remove(ContentType.AUDIO, 1, 5))
|
|
770
748
|
.toBeRejectedWith(expected);
|
|
771
749
|
expect(audioSourceBuffer.remove).toHaveBeenCalledWith(1, 5);
|
|
@@ -930,7 +908,9 @@ describe('MediaSourceEngine', () => {
|
|
|
930
908
|
/* timestampOffset= */ 10,
|
|
931
909
|
/* appendWindowStart= */ 0,
|
|
932
910
|
/* appendWindowEnd= */ 20,
|
|
933
|
-
/* sequenceMode= */ false
|
|
911
|
+
/* sequenceMode= */ false,
|
|
912
|
+
fakeStream,
|
|
913
|
+
/* streamsByType= */ new Map());
|
|
934
914
|
expect(mockTextEngine.setTimestampOffset).toHaveBeenCalledWith(10);
|
|
935
915
|
expect(mockTextEngine.setAppendWindow).toHaveBeenCalledWith(0, 20);
|
|
936
916
|
});
|
|
@@ -954,11 +934,11 @@ describe('MediaSourceEngine', () => {
|
|
|
954
934
|
it('waits for all previous operations to complete', async () => {
|
|
955
935
|
/** @type {!shaka.test.StatusPromise} */
|
|
956
936
|
const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
|
|
957
|
-
ContentType.AUDIO, buffer, null,
|
|
937
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
958
938
|
/* hasClosedCaptions= */ false));
|
|
959
939
|
/** @type {!shaka.test.StatusPromise} */
|
|
960
940
|
const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
|
|
961
|
-
ContentType.VIDEO, buffer, null,
|
|
941
|
+
ContentType.VIDEO, buffer, null, fakeStream,
|
|
962
942
|
/* hasClosedCaptions= */ false));
|
|
963
943
|
/** @type {!shaka.test.StatusPromise} */
|
|
964
944
|
const p3 = new shaka.test.StatusPromise(mediaSourceEngine.endOfStream());
|
|
@@ -982,11 +962,11 @@ describe('MediaSourceEngine', () => {
|
|
|
982
962
|
/** @type {!Promise} */
|
|
983
963
|
const p1 = mediaSourceEngine.endOfStream();
|
|
984
964
|
mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
|
|
985
|
-
/* hasClosedCaptions= */ false);
|
|
965
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
986
966
|
mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
|
|
987
|
-
/* hasClosedCaptions= */ false);
|
|
967
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
988
968
|
mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer2, null,
|
|
989
|
-
/* hasClosedCaptions= */ false);
|
|
969
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
990
970
|
|
|
991
971
|
// endOfStream hasn't been called yet because blocking multiple queues
|
|
992
972
|
// takes an extra tick, even when they are empty.
|
|
@@ -1014,7 +994,7 @@ describe('MediaSourceEngine', () => {
|
|
|
1014
994
|
/** @type {!Promise} */
|
|
1015
995
|
const p1 = mediaSourceEngine.endOfStream();
|
|
1016
996
|
mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
|
|
1017
|
-
/* hasClosedCaptions= */ false);
|
|
997
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
1018
998
|
|
|
1019
999
|
expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalled();
|
|
1020
1000
|
|
|
@@ -1045,11 +1025,11 @@ describe('MediaSourceEngine', () => {
|
|
|
1045
1025
|
it('waits for all previous operations to complete', async () => {
|
|
1046
1026
|
/** @type {!shaka.test.StatusPromise} */
|
|
1047
1027
|
const p1 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
|
|
1048
|
-
ContentType.AUDIO, buffer, null,
|
|
1028
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
1049
1029
|
/* hasClosedCaptions= */ false));
|
|
1050
1030
|
/** @type {!shaka.test.StatusPromise} */
|
|
1051
1031
|
const p2 = new shaka.test.StatusPromise(mediaSourceEngine.appendBuffer(
|
|
1052
|
-
ContentType.VIDEO, buffer, null,
|
|
1032
|
+
ContentType.VIDEO, buffer, null, fakeStream,
|
|
1053
1033
|
/* hasClosedCaptions= */ false));
|
|
1054
1034
|
/** @type {!shaka.test.StatusPromise} */
|
|
1055
1035
|
const p3 =
|
|
@@ -1074,11 +1054,11 @@ describe('MediaSourceEngine', () => {
|
|
|
1074
1054
|
/** @type {!Promise} */
|
|
1075
1055
|
const p1 = mediaSourceEngine.setDuration(100);
|
|
1076
1056
|
mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
|
|
1077
|
-
/* hasClosedCaptions= */ false);
|
|
1057
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
1078
1058
|
mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
|
|
1079
|
-
/* hasClosedCaptions= */ false);
|
|
1059
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
1080
1060
|
mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer2, null,
|
|
1081
|
-
/* hasClosedCaptions= */ false);
|
|
1061
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
1082
1062
|
|
|
1083
1063
|
// The setter hasn't been called yet because blocking multiple queues
|
|
1084
1064
|
// takes an extra tick, even when they are empty.
|
|
@@ -1107,7 +1087,7 @@ describe('MediaSourceEngine', () => {
|
|
|
1107
1087
|
/** @type {!Promise} */
|
|
1108
1088
|
const p1 = mediaSourceEngine.setDuration(100);
|
|
1109
1089
|
mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
|
|
1110
|
-
/* hasClosedCaptions= */ false);
|
|
1090
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
1111
1091
|
|
|
1112
1092
|
expect(audioSourceBuffer.appendBuffer).not.toHaveBeenCalled();
|
|
1113
1093
|
|
|
@@ -1146,9 +1126,9 @@ describe('MediaSourceEngine', () => {
|
|
|
1146
1126
|
// This is tested because shrinking duration generates 'updateend'
|
|
1147
1127
|
// events, and we want to show that the queue still operates correctly.
|
|
1148
1128
|
const a1 = mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
|
|
1149
|
-
/* hasClosedCaptions= */ false);
|
|
1129
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
1150
1130
|
const a2 = mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
|
|
1151
|
-
/* hasClosedCaptions= */ false);
|
|
1131
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
1152
1132
|
|
|
1153
1133
|
await p1;
|
|
1154
1134
|
await a1;
|
|
@@ -1168,9 +1148,9 @@ describe('MediaSourceEngine', () => {
|
|
|
1168
1148
|
|
|
1169
1149
|
it('waits for all operations to complete', async () => {
|
|
1170
1150
|
mediaSourceEngine.appendBuffer(ContentType.AUDIO, buffer, null,
|
|
1171
|
-
/* hasClosedCaptions= */ false);
|
|
1151
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
1172
1152
|
mediaSourceEngine.appendBuffer(ContentType.VIDEO, buffer, null,
|
|
1173
|
-
/* hasClosedCaptions= */ false);
|
|
1153
|
+
fakeStream, /* hasClosedCaptions= */ false);
|
|
1174
1154
|
|
|
1175
1155
|
/** @type {!shaka.test.StatusPromise} */
|
|
1176
1156
|
const d = new shaka.test.StatusPromise(mediaSourceEngine.destroy());
|
|
@@ -1187,7 +1167,7 @@ describe('MediaSourceEngine', () => {
|
|
|
1187
1167
|
|
|
1188
1168
|
it('resolves even when a pending operation fails', async () => {
|
|
1189
1169
|
const p = mediaSourceEngine.appendBuffer(
|
|
1190
|
-
ContentType.AUDIO, buffer, null,
|
|
1170
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
1191
1171
|
/* hasClosedCaptions= */ false);
|
|
1192
1172
|
const d = mediaSourceEngine.destroy();
|
|
1193
1173
|
|
|
@@ -1212,10 +1192,10 @@ describe('MediaSourceEngine', () => {
|
|
|
1212
1192
|
|
|
1213
1193
|
it('cancels operations that have not yet started', async () => {
|
|
1214
1194
|
mediaSourceEngine.appendBuffer(
|
|
1215
|
-
ContentType.AUDIO, buffer, null,
|
|
1195
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
1216
1196
|
/* hasClosedCaptions= */ false);
|
|
1217
1197
|
const rejected = mediaSourceEngine.appendBuffer(
|
|
1218
|
-
ContentType.AUDIO, buffer2, null,
|
|
1198
|
+
ContentType.AUDIO, buffer2, null, fakeStream,
|
|
1219
1199
|
/* hasClosedCaptions= */ false);
|
|
1220
1200
|
// Create the expectation first so we don't get unhandled rejection errors
|
|
1221
1201
|
const expected = expectAsync(rejected).toBeRejected();
|
|
@@ -1239,7 +1219,7 @@ describe('MediaSourceEngine', () => {
|
|
|
1239
1219
|
|
|
1240
1220
|
it('cancels blocking operations that have not yet started', async () => {
|
|
1241
1221
|
const p1 = mediaSourceEngine.appendBuffer(
|
|
1242
|
-
ContentType.AUDIO, buffer, null,
|
|
1222
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
1243
1223
|
/* hasClosedCaptions= */ false);
|
|
1244
1224
|
const p2 = mediaSourceEngine.endOfStream();
|
|
1245
1225
|
const d = mediaSourceEngine.destroy();
|
|
@@ -1254,7 +1234,7 @@ describe('MediaSourceEngine', () => {
|
|
|
1254
1234
|
const d = mediaSourceEngine.destroy();
|
|
1255
1235
|
await expectAsync(
|
|
1256
1236
|
mediaSourceEngine.appendBuffer(
|
|
1257
|
-
ContentType.AUDIO, buffer, null,
|
|
1237
|
+
ContentType.AUDIO, buffer, null, fakeStream,
|
|
1258
1238
|
/* hasClosedCaptions= */ false))
|
|
1259
1239
|
.toBeRejected();
|
|
1260
1240
|
await d;
|
|
@@ -1328,7 +1308,7 @@ describe('MediaSourceEngine', () => {
|
|
|
1328
1308
|
mockTextEngine = jasmine.createSpyObj('TextEngine', [
|
|
1329
1309
|
'initParser', 'destroy', 'appendBuffer', 'remove', 'setTimestampOffset',
|
|
1330
1310
|
'setAppendWindow', 'bufferStart', 'bufferEnd', 'bufferedAheadOf',
|
|
1331
|
-
'storeAndAppendClosedCaptions',
|
|
1311
|
+
'storeAndAppendClosedCaptions',
|
|
1332
1312
|
]);
|
|
1333
1313
|
|
|
1334
1314
|
const resolve = () => Promise.resolve();
|
|
@@ -134,6 +134,9 @@ describe('Playhead', () => {
|
|
|
134
134
|
minBufferTime: 10,
|
|
135
135
|
offlineSessionIds: [],
|
|
136
136
|
sequenceMode: false,
|
|
137
|
+
ignoreManifestTimestampsInSegmentsMode: false,
|
|
138
|
+
type: 'UNKNOWN',
|
|
139
|
+
serviceDescription: null,
|
|
137
140
|
};
|
|
138
141
|
|
|
139
142
|
config = shaka.util.PlayerConfiguration.createDefault().streaming;
|
|
@@ -114,6 +114,57 @@ describe('PresentationTimeline', () => {
|
|
|
114
114
|
return timeline;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
const makeTimeRange = (startTime, endTime) => {
|
|
118
|
+
return {
|
|
119
|
+
start: startTime,
|
|
120
|
+
end: endTime,
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
describe('notifyTimeRange', () => {
|
|
125
|
+
it('calculates time based on segment times when available', () => {
|
|
126
|
+
const timeline = makeLiveTimeline(/* availability= */ 20);
|
|
127
|
+
|
|
128
|
+
const timeRanges = [
|
|
129
|
+
makeTimeRange(0, 10),
|
|
130
|
+
makeTimeRange(10, 20),
|
|
131
|
+
makeTimeRange(20, 30),
|
|
132
|
+
makeTimeRange(30, 40),
|
|
133
|
+
makeTimeRange(40, 50),
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
// In spite of the current time, the explicit segment times will decide
|
|
138
|
+
// the availability window.
|
|
139
|
+
// See https://github.com/shaka-project/shaka-player/issues/999
|
|
140
|
+
setElapsed(1000);
|
|
141
|
+
timeline.notifyTimeRange(timeRanges, 0);
|
|
142
|
+
|
|
143
|
+
// last segment time (50) - availability (20)
|
|
144
|
+
expect(timeline.getSegmentAvailabilityStart()).toBe(30);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('ignores segment times when configured to', () => {
|
|
148
|
+
const timeline = makeLiveTimeline(
|
|
149
|
+
/* availability= */ 20, /* drift= */ 0,
|
|
150
|
+
/* autoCorrectDrift= */ false);
|
|
151
|
+
|
|
152
|
+
const timeRanges = [
|
|
153
|
+
makeTimeRange(0, 10),
|
|
154
|
+
makeTimeRange(10, 20),
|
|
155
|
+
makeTimeRange(20, 30),
|
|
156
|
+
makeTimeRange(30, 40),
|
|
157
|
+
makeTimeRange(40, 50),
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
setElapsed(100);
|
|
161
|
+
timeline.notifyTimeRange(timeRanges, 0);
|
|
162
|
+
|
|
163
|
+
// now (100) - max segment duration (10) - availability start time (0)
|
|
164
|
+
expect(timeline.getSegmentAvailabilityEnd()).toBe(90);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
117
168
|
describe('getSegmentAvailabilityStart', () => {
|
|
118
169
|
it('returns 0 for VOD and IPR', () => {
|
|
119
170
|
const timeline1 = makeVodTimeline(/* duration= */ 60);
|