shaka-player 4.4.2 → 4.5.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/release-please.yaml +2 -27
- package/CHANGELOG.md +67 -25
- package/README.md +16 -10
- package/demo/asset_card.js +18 -21
- package/demo/cast_receiver/index.html +0 -1
- package/demo/close_button.js +0 -3
- package/demo/common/asset.js +27 -5
- package/demo/common/assets.js +150 -52
- package/demo/config.js +192 -253
- package/demo/custom.js +39 -98
- package/demo/front.js +7 -10
- package/demo/index.html +19 -22
- package/demo/input.js +6 -11
- package/demo/input_container.js +8 -9
- package/demo/main.js +52 -124
- package/demo/search.js +23 -35
- package/demo/service_worker.js +0 -3
- package/demo/tooltip.js +3 -5
- package/demo/visualizer.js +3 -5
- package/demo/visualizer_button.js +1 -20
- package/dist/demo.compiled.debug.js +187 -211
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +187 -211
- package/dist/demo.compiled.map +4 -4
- package/dist/deps.js +27 -24
- package/dist/locales.js +31 -31
- package/dist/receiver.compiled.debug.js +42 -61
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +42 -61
- package/dist/receiver.compiled.map +4 -4
- package/dist/shaka-player.compiled.d.ts +728 -365
- package/dist/shaka-player.compiled.debug.d.ts +728 -365
- package/dist/shaka-player.compiled.debug.externs.js +475 -51
- package/dist/shaka-player.compiled.debug.js +576 -480
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +475 -51
- package/dist/shaka-player.compiled.js +1117 -1056
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +783 -410
- package/dist/shaka-player.ui.debug.d.ts +783 -410
- package/dist/shaka-player.ui.debug.externs.js +496 -51
- package/dist/shaka-player.ui.debug.js +647 -542
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +496 -51
- package/dist/shaka-player.ui.js +1260 -1194
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-integration.md +14 -14
- package/docs/tutorials/faq.md +27 -55
- package/docs/tutorials/index.json +2 -1
- package/docs/tutorials/lcevc.md +118 -0
- package/docs/tutorials/offline.md +1 -1
- package/docs/tutorials/ui-customization.md +4 -0
- package/externs/css_style_declaration.js +19 -0
- package/externs/lcevc.js +37 -13
- package/externs/media_remote.js +68 -0
- package/externs/mediatailor.js +193 -0
- package/externs/pictureinpicture.js +11 -0
- package/externs/shaka/ads.js +27 -0
- package/externs/shaka/manifest.js +10 -5
- package/externs/shaka/manifest_parser.js +7 -1
- package/externs/shaka/offline.js +4 -0
- package/externs/shaka/player.js +12 -1
- package/karma.conf.js +7 -3
- package/lib/abr/simple_abr_manager.js +43 -3
- package/lib/ads/ad_manager.js +104 -50
- package/lib/ads/media_tailor_ad.js +297 -0
- package/lib/ads/media_tailor_ad_manager.js +828 -0
- package/lib/cea/ts_cea_parser.js +15 -2
- package/lib/config/codec_switching_strategy.js +24 -0
- package/lib/dash/content_protection.js +120 -2
- package/lib/dash/dash_parser.js +79 -13
- package/lib/dash/mpd_utils.js +10 -6
- package/lib/dash/segment_base.js +13 -5
- package/lib/dash/segment_list.js +13 -5
- package/lib/dash/segment_template.js +43 -85
- package/lib/dependencies/all.js +8 -7
- package/lib/hls/hls_parser.js +101 -37
- package/lib/lcevc/lcevc_dec.js +220 -0
- package/lib/media/adaptation_set.js +22 -11
- package/lib/media/adaptation_set_criteria.js +25 -7
- package/lib/media/media_source_engine.js +215 -27
- package/lib/media/segment_index.js +5 -5
- package/lib/media/segment_reference.js +10 -5
- package/lib/media/streaming_engine.js +44 -39
- package/lib/mss/mss_parser.js +1 -0
- package/lib/net/networking_engine.js +1 -0
- 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 +1 -0
- package/lib/offline/storage.js +3 -0
- package/lib/player.js +142 -72
- package/lib/routing/payload.js +5 -1
- package/lib/text/cue.js +62 -47
- package/lib/text/ttml_text_parser.js +17 -0
- package/lib/text/ui_text_displayer.js +4 -0
- package/lib/text/vtt_text_parser.js +35 -22
- package/lib/transmuxer/h265.js +862 -0
- package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
- package/lib/transmuxer/ts_transmuxer.js +160 -15
- package/lib/util/cmcd_manager.js +6 -1
- package/lib/util/error.js +28 -9
- package/lib/util/exp_golomb.js +30 -2
- package/lib/util/fake_event.js +3 -0
- package/lib/util/manifest_parser_utils.js +10 -4
- package/lib/util/mp4_generator.js +4 -4
- package/lib/util/periods.js +2 -0
- package/lib/util/platform.js +54 -0
- package/lib/util/player_configuration.js +8 -0
- package/lib/util/state_history.js +6 -2
- package/lib/util/stream_utils.js +133 -217
- package/lib/util/ts_parser.js +229 -43
- package/maintained-branches.md +3 -2
- package/package.json +4 -6
- package/roadmap.md +15 -5
- package/shaka-player.uncompiled.js +2 -1
- package/support.html +0 -1
- package/test/cast/cast_receiver_integration.js +47 -0
- package/test/codec_switching/codec_switching_integration.js +181 -0
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_integration.js +73 -0
- package/test/dash/dash_parser_live_unit.js +2 -0
- package/test/dash/dash_parser_manifest_unit.js +47 -0
- package/test/dash/dash_parser_segment_base_unit.js +7 -0
- package/test/dash/dash_parser_segment_list_unit.js +23 -17
- package/test/dash/dash_parser_segment_template_unit.js +49 -0
- package/test/demo/demo_unit.js +0 -16
- package/test/hls/hls_live_unit.js +35 -0
- package/test/hls/hls_parser_unit.js +8 -61
- package/test/media/adaptation_set_criteria_unit.js +118 -0
- package/test/media/adaptation_set_unit.js +1 -0
- package/test/media/media_source_engine_unit.js +165 -1
- package/test/media/segment_index_unit.js +4 -4
- package/test/media/segment_prefetch_unit.js +1 -1
- package/test/media/streaming_engine_unit.js +17 -17
- package/test/mss/mss_parser_unit.js +2 -0
- package/test/offline/manifest_convert_unit.js +5 -0
- package/test/offline/storage_integration.js +1 -4
- package/test/player_unit.js +102 -131
- package/test/routing/walker_unit.js +1 -0
- package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/dash.mpd +18 -0
- package/test/test/assets/dash-aes-128/license +1 -0
- package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
- package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
- package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
- package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
- package/test/test/assets/hls-ts-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
- package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
- package/test/test/util/dash_parser_util.js +20 -7
- package/test/test/util/fake_ad_manager.js +20 -0
- package/test/test/util/fake_media_source_engine.js +8 -2
- package/test/test/util/manifest_generator.js +7 -3
- package/test/test/util/mss_parser_util.js +4 -0
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/streaming_engine_util.js +7 -4
- package/test/text/ttml_text_parser_unit.js +52 -0
- package/test/text/vtt_text_parser_unit.js +105 -48
- package/test/transmuxer/transmuxer_integration.js +121 -4
- package/test/ui/ui_unit.js +3 -10
- package/test/util/stream_utils_unit.js +208 -74
- package/test/util/ts_parser_unit.js +1 -1
- package/ui/controls.js +125 -0
- package/ui/externs/ui.js +8 -1
- package/ui/pip_button.js +22 -120
- package/ui/remote_button.js +201 -0
- package/ui/ui.js +5 -2
- package/demo/common/message_ids.js +0 -309
- package/demo/locales/en.json +0 -287
- package/demo/locales/source.json +0 -1142
- package/externs/mux.js +0 -69
- package/lib/lcevc/lcevc_dil.js +0 -152
- package/lib/transmuxer/muxjs_transmuxer.js +0 -242
- package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
|
@@ -49,6 +49,90 @@ describe('AdaptationSetCriteria', () => {
|
|
|
49
49
|
]);
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
+
it('should not filter varaints when codec switching startegy is smooth '+
|
|
53
|
+
'and changeType is supported', () => {
|
|
54
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
55
|
+
manifest.addVariant(1, (variant) => {
|
|
56
|
+
variant.addAudio(10, (stream) => {
|
|
57
|
+
stream.codecs = 'mp4a.69';
|
|
58
|
+
});
|
|
59
|
+
variant.addVideo(11, (stream) => {
|
|
60
|
+
stream.codecs = 'avc1';
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
manifest.addVariant(2, (variant) => {
|
|
64
|
+
variant.addAudio(12, (stream) => {
|
|
65
|
+
stream.codecs = 'mp4a.66';
|
|
66
|
+
});
|
|
67
|
+
variant.addVideo(13, (stream) => {
|
|
68
|
+
stream.codecs = 'hvc1';
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
manifest.addVariant(3, (variant) => {
|
|
72
|
+
variant.addAudio(14, (stream) => {
|
|
73
|
+
stream.codecs = 'mp4a.a6';
|
|
74
|
+
});
|
|
75
|
+
variant.addVideo(14, (stream) => {
|
|
76
|
+
stream.codecs = 'dvh1';
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const originalIsChangeTypeSupported = shaka.media.Capabilities
|
|
82
|
+
.isChangeTypeSupported;
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
shaka.media.Capabilities.isChangeTypeSupported = () => {
|
|
86
|
+
return true;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const builder = new shaka.media.PreferenceBasedCriteria('en', '', 0, '',
|
|
90
|
+
undefined, shaka.config.CodecSwitchingStrategy.SMOOTH);
|
|
91
|
+
const set = builder.create(manifest.variants);
|
|
92
|
+
|
|
93
|
+
expect(Array.from(set.values()).length).toBe(3);
|
|
94
|
+
} finally {
|
|
95
|
+
shaka.media.Capabilities
|
|
96
|
+
.isChangeTypeSupported = originalIsChangeTypeSupported;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should filter varaints when codec switching startegy'+
|
|
101
|
+
'is not SMOOTH', () => {
|
|
102
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
103
|
+
manifest.addVariant(1, (variant) => {
|
|
104
|
+
variant.addAudio(10, (stream) => {
|
|
105
|
+
stream.codecs = 'mp4a.69';
|
|
106
|
+
});
|
|
107
|
+
variant.addVideo(11, (stream) => {
|
|
108
|
+
stream.codecs = 'avc1';
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
manifest.addVariant(2, (variant) => {
|
|
112
|
+
variant.addAudio(12, (stream) => {
|
|
113
|
+
stream.codecs = 'mp4a.66';
|
|
114
|
+
});
|
|
115
|
+
variant.addVideo(13, (stream) => {
|
|
116
|
+
stream.codecs = 'hvc1';
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
manifest.addVariant(3, (variant) => {
|
|
120
|
+
variant.addAudio(14, (stream) => {
|
|
121
|
+
stream.codecs = 'mp4a.a6';
|
|
122
|
+
});
|
|
123
|
+
variant.addVideo(14, (stream) => {
|
|
124
|
+
stream.codecs = 'dvh1';
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const builder = new shaka.media.PreferenceBasedCriteria('en', '', 0, '',
|
|
130
|
+
undefined, shaka.config.CodecSwitchingStrategy.RELOAD);
|
|
131
|
+
const set = builder.create(manifest.variants);
|
|
132
|
+
|
|
133
|
+
expect(Array.from(set.values()).length).toBe(1);
|
|
134
|
+
});
|
|
135
|
+
|
|
52
136
|
it('chooses variants in preferred language and role', () => {
|
|
53
137
|
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
54
138
|
manifest.addVariant(1, (variant) => {
|
|
@@ -524,6 +608,40 @@ describe('AdaptationSetCriteria', () => {
|
|
|
524
608
|
manifest.variants[2],
|
|
525
609
|
]);
|
|
526
610
|
});
|
|
611
|
+
|
|
612
|
+
it('filters by audio group if present', () => {
|
|
613
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
614
|
+
manifest.addVariant(1, (variant) => {
|
|
615
|
+
variant.language = 'en';
|
|
616
|
+
variant.bandwidth = 300;
|
|
617
|
+
variant.addAudio(10, (stream) => {
|
|
618
|
+
stream.groupId = '1';
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
manifest.addVariant(2, (variant) => {
|
|
622
|
+
variant.language = 'en';
|
|
623
|
+
variant.bandwidth = 400;
|
|
624
|
+
variant.addAudio(11, (stream) => {
|
|
625
|
+
stream.groupId = '2';
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
manifest.addVariant(3, (variant) => {
|
|
629
|
+
variant.language = 'en';
|
|
630
|
+
variant.bandwidth = 500;
|
|
631
|
+
variant.addAudio(12, (stream) => {
|
|
632
|
+
stream.groupId = '1';
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
const builder = new shaka.media.PreferenceBasedCriteria('en', '', 0, '');
|
|
638
|
+
const set = builder.create(manifest.variants);
|
|
639
|
+
|
|
640
|
+
checkSet(set, [
|
|
641
|
+
manifest.variants[0],
|
|
642
|
+
manifest.variants[2],
|
|
643
|
+
]);
|
|
644
|
+
});
|
|
527
645
|
});
|
|
528
646
|
|
|
529
647
|
/**
|
|
@@ -116,7 +116,13 @@ describe('MediaSourceEngine', () => {
|
|
|
116
116
|
mockMediaSource = createMockMediaSource();
|
|
117
117
|
mockMediaSource.addSourceBuffer.and.callFake((mimeType) => {
|
|
118
118
|
const type = mimeType.split('/')[0];
|
|
119
|
-
|
|
119
|
+
const buffer = type == 'audio' ? audioSourceBuffer : videoSourceBuffer;
|
|
120
|
+
// reset buffer params
|
|
121
|
+
buffer.timestampOffset = 0;
|
|
122
|
+
buffer.appendWindowEnd = Infinity;
|
|
123
|
+
buffer.appendWindowStart = 0;
|
|
124
|
+
|
|
125
|
+
return buffer;
|
|
120
126
|
});
|
|
121
127
|
mockTransmuxer = new shaka.test.FakeTransmuxer();
|
|
122
128
|
shaka.transmuxer.TransmuxerEngine.findTransmuxer =
|
|
@@ -167,10 +173,12 @@ describe('MediaSourceEngine', () => {
|
|
|
167
173
|
goog.asserts.assert(attr == 'src', 'Unexpected removeAttribute() call');
|
|
168
174
|
mockVideo.src = '';
|
|
169
175
|
},
|
|
176
|
+
addEventListener: jasmine.createSpy('addVideoEventListener'),
|
|
170
177
|
load: /** @this {HTMLVideoElement} */ () => {
|
|
171
178
|
// This assertion alerts us if the requirements for this mock change.
|
|
172
179
|
goog.asserts.assert(mockVideo.src == '', 'Unexpected load() call');
|
|
173
180
|
},
|
|
181
|
+
play: jasmine.createSpy('play'),
|
|
174
182
|
};
|
|
175
183
|
video = /** @type {HTMLMediaElement} */(mockVideo);
|
|
176
184
|
mockClosedCaptionParser = new shaka.test.FakeClosedCaptionParser();
|
|
@@ -1136,6 +1144,161 @@ describe('MediaSourceEngine', () => {
|
|
|
1136
1144
|
});
|
|
1137
1145
|
});
|
|
1138
1146
|
|
|
1147
|
+
describe('reload codec switching', () => {
|
|
1148
|
+
beforeEach(
|
|
1149
|
+
/** @suppress {visibility, checkTypes} */
|
|
1150
|
+
() => {
|
|
1151
|
+
mediaSourceEngine.eventManager_.listenOnce =
|
|
1152
|
+
jasmine.createSpy('listener');
|
|
1153
|
+
mediaSourceEngine.eventManager_.listen =
|
|
1154
|
+
jasmine.createSpy('eventListener');
|
|
1155
|
+
});
|
|
1156
|
+
const initObject = new Map();
|
|
1157
|
+
initObject.set(ContentType.VIDEO, fakeVideoStream);
|
|
1158
|
+
initObject.set(ContentType.AUDIO, fakeAudioStream);
|
|
1159
|
+
|
|
1160
|
+
it('should re-create a new MediaSource',
|
|
1161
|
+
/** @suppress {visibility} */ async () => {
|
|
1162
|
+
await mediaSourceEngine.init(initObject, false);
|
|
1163
|
+
mediaSourceEngine.reset_(initObject);
|
|
1164
|
+
expect(createMediaSourceSpy).toHaveBeenCalled();
|
|
1165
|
+
});
|
|
1166
|
+
|
|
1167
|
+
it('should re-create the audio & video source buffers',
|
|
1168
|
+
/** @suppress {invalidCasts, visibility, checkTypes} */ async () => {
|
|
1169
|
+
await mediaSourceEngine.init(initObject, false);
|
|
1170
|
+
mediaSourceEngine.reset_(initObject);
|
|
1171
|
+
expect(mockMediaSource.addSourceBuffer).toHaveBeenCalledTimes(2);
|
|
1172
|
+
});
|
|
1173
|
+
|
|
1174
|
+
it('should persist the previous source buffer parameters',
|
|
1175
|
+
/** @suppress {invalidCasts, visibility, checkTypes} */async () => {
|
|
1176
|
+
await mediaSourceEngine.init(initObject, false);
|
|
1177
|
+
|
|
1178
|
+
audioSourceBuffer.timestampOffset = 10;
|
|
1179
|
+
audioSourceBuffer.appendWindowStart = 5;
|
|
1180
|
+
audioSourceBuffer.appendWindowEnd = 20;
|
|
1181
|
+
|
|
1182
|
+
videoSourceBuffer.timestampOffset = 20;
|
|
1183
|
+
videoSourceBuffer.appendWindowStart = 15;
|
|
1184
|
+
videoSourceBuffer.appendWindowEnd = 30;
|
|
1185
|
+
|
|
1186
|
+
mediaSourceEngine.reset_(initObject);
|
|
1187
|
+
|
|
1188
|
+
expect(audioSourceBuffer.timestampOffset).toBe(10);
|
|
1189
|
+
expect(audioSourceBuffer.appendWindowStart).toBe(5);
|
|
1190
|
+
expect(audioSourceBuffer.appendWindowEnd).toBe(20);
|
|
1191
|
+
|
|
1192
|
+
expect(videoSourceBuffer.timestampOffset).toBe(20);
|
|
1193
|
+
expect(videoSourceBuffer.appendWindowStart).toBe(15);
|
|
1194
|
+
expect(videoSourceBuffer.appendWindowEnd).toBe(30);
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
it('should preserve autoplay state',
|
|
1198
|
+
/** @suppress {invalidCasts, visibility, checkTypes} */
|
|
1199
|
+
async () => {
|
|
1200
|
+
const originalInitSourceBuffer = mediaSourceEngine.initSourceBuffer_;
|
|
1201
|
+
try {
|
|
1202
|
+
await mediaSourceEngine.init(initObject, false);
|
|
1203
|
+
video.autoplay = true;
|
|
1204
|
+
video.paused = true;
|
|
1205
|
+
const playSpy = /** @type {jasmine.Spy} */ (video.play);
|
|
1206
|
+
const addListenOnceSpy =
|
|
1207
|
+
/** @type {jasmine.Spy} */
|
|
1208
|
+
(mediaSourceEngine.eventManager_.listenOnce);
|
|
1209
|
+
const addEventListenerSpy =
|
|
1210
|
+
/** @type {jasmine.Spy} */
|
|
1211
|
+
(mediaSourceEngine.eventManager_.listen);
|
|
1212
|
+
mediaSourceEngine.playbackHasBegun_ = true;
|
|
1213
|
+
mediaSourceEngine.initSourceBuffer_ =
|
|
1214
|
+
jasmine.createSpy('initSourceBuffer');
|
|
1215
|
+
const initSourceBufferSpy =
|
|
1216
|
+
/** @type {jasmine.Spy} */
|
|
1217
|
+
(mediaSourceEngine.initSourceBuffer_);
|
|
1218
|
+
addEventListenerSpy.and.callFake((o, e, c) => {
|
|
1219
|
+
c(); // audio
|
|
1220
|
+
c(); // video
|
|
1221
|
+
});
|
|
1222
|
+
await mediaSourceEngine.reset_(initObject);
|
|
1223
|
+
const callback = addListenOnceSpy.calls.argsFor(0)[2];
|
|
1224
|
+
callback();
|
|
1225
|
+
expect(initSourceBufferSpy).toHaveBeenCalled();
|
|
1226
|
+
expect(addListenOnceSpy.calls.argsFor(0)[1]).toBe('canplay');
|
|
1227
|
+
expect(video.autoplay).toBe(true);
|
|
1228
|
+
expect(playSpy).not.toHaveBeenCalled();
|
|
1229
|
+
} finally {
|
|
1230
|
+
mediaSourceEngine.initSourceBuffer_ = originalInitSourceBuffer;
|
|
1231
|
+
}
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
it('should not set autoplay to false if playback has not begun',
|
|
1235
|
+
/** @suppress {invalidCasts, visibility, checkTypes} */
|
|
1236
|
+
async () => {
|
|
1237
|
+
const originalInitSourceBuffer = mediaSourceEngine.initSourceBuffer_;
|
|
1238
|
+
try {
|
|
1239
|
+
await mediaSourceEngine.init(initObject, false);
|
|
1240
|
+
video.autoplay = true;
|
|
1241
|
+
let setCount = 0;
|
|
1242
|
+
const addEventListenerSpy =
|
|
1243
|
+
/** @type {jasmine.Spy} */
|
|
1244
|
+
(mediaSourceEngine.eventManager_.listen);
|
|
1245
|
+
addEventListenerSpy.and.callFake((o, e, c) => {
|
|
1246
|
+
c(); // audio
|
|
1247
|
+
c(); // video
|
|
1248
|
+
});
|
|
1249
|
+
mediaSourceEngine.initSourceBuffer_ =
|
|
1250
|
+
jasmine.createSpy('initSourceBuffer');
|
|
1251
|
+
Object.defineProperty(video, 'autoplay', {
|
|
1252
|
+
get: () => true,
|
|
1253
|
+
set: () => {
|
|
1254
|
+
setCount++;
|
|
1255
|
+
},
|
|
1256
|
+
});
|
|
1257
|
+
await mediaSourceEngine.reset_(initObject);
|
|
1258
|
+
expect(setCount).toBe(0);
|
|
1259
|
+
} finally {
|
|
1260
|
+
mediaSourceEngine.initSourceBuffer_ = originalInitSourceBuffer;
|
|
1261
|
+
}
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
it('should preserve playing state',
|
|
1265
|
+
/** @suppress {invalidCasts, visibility, checkTypes} */
|
|
1266
|
+
async () => {
|
|
1267
|
+
const originalInitSourceBuffer = mediaSourceEngine.initSourceBuffer_;
|
|
1268
|
+
try {
|
|
1269
|
+
await mediaSourceEngine.init(initObject, false);
|
|
1270
|
+
video.autoplay = false;
|
|
1271
|
+
video.paused = false;
|
|
1272
|
+
const playSpy = /** @type {jasmine.Spy} */ (video.play);
|
|
1273
|
+
const addListenOnceSpy =
|
|
1274
|
+
/** @type {jasmine.Spy} */
|
|
1275
|
+
(mediaSourceEngine.eventManager_.listenOnce);
|
|
1276
|
+
const addEventListenerSpy =
|
|
1277
|
+
/** @type {jasmine.Spy} */
|
|
1278
|
+
(mediaSourceEngine.eventManager_.listen);
|
|
1279
|
+
mediaSourceEngine.playbackHasBegun_ = true;
|
|
1280
|
+
mediaSourceEngine.initSourceBuffer_ =
|
|
1281
|
+
jasmine.createSpy('initSourceBuffer');
|
|
1282
|
+
const initSourceBufferSpy =
|
|
1283
|
+
/** @type {jasmine.Spy} */
|
|
1284
|
+
(mediaSourceEngine.initSourceBuffer_);
|
|
1285
|
+
addEventListenerSpy.and.callFake((o, e, c) => {
|
|
1286
|
+
c(); // audio
|
|
1287
|
+
c(); // video
|
|
1288
|
+
});
|
|
1289
|
+
await mediaSourceEngine.reset_(initObject);
|
|
1290
|
+
const callback = addListenOnceSpy.calls.argsFor(0)[2];
|
|
1291
|
+
callback();
|
|
1292
|
+
expect(initSourceBufferSpy).toHaveBeenCalled();
|
|
1293
|
+
expect(addListenOnceSpy.calls.argsFor(0)[1]).toBe('canplay');
|
|
1294
|
+
expect(video.autoplay).toBe(false);
|
|
1295
|
+
expect(playSpy).toHaveBeenCalled();
|
|
1296
|
+
} finally {
|
|
1297
|
+
mediaSourceEngine.initSourceBuffer_ = originalInitSourceBuffer;
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
});
|
|
1301
|
+
|
|
1139
1302
|
describe('destroy', () => {
|
|
1140
1303
|
beforeEach(async () => {
|
|
1141
1304
|
captureEvents(audioSourceBuffer, ['updateend', 'error']);
|
|
@@ -1259,6 +1422,7 @@ describe('MediaSourceEngine', () => {
|
|
|
1259
1422
|
function createMockMediaSource() {
|
|
1260
1423
|
const mediaSource = {
|
|
1261
1424
|
readyState: 'open',
|
|
1425
|
+
sourceBuffers: document.createElement('div'),
|
|
1262
1426
|
addSourceBuffer: jasmine.createSpy('addSourceBuffer'),
|
|
1263
1427
|
endOfStream: jasmine.createSpy('endOfStream'),
|
|
1264
1428
|
durationGetter: jasmine.createSpy('duration getter'),
|
|
@@ -223,7 +223,7 @@ describe('SegmentIndex', /** @suppress {accessControls} */ () => {
|
|
|
223
223
|
|
|
224
224
|
index.fit(/* windowStart= */ 0, /* windowEnd= */ 10);
|
|
225
225
|
expect(
|
|
226
|
-
index.references[index.references.length - 1].
|
|
226
|
+
index.references[index.references.length - 1].aes128Key,
|
|
227
227
|
).toEqual({method: 'AES-128', firstMediaSequenceNumber: 0});
|
|
228
228
|
});
|
|
229
229
|
});
|
|
@@ -1054,11 +1054,11 @@ describe('SegmentIndex', /** @suppress {accessControls} */ () => {
|
|
|
1054
1054
|
* @param {number} startTime
|
|
1055
1055
|
* @param {number} endTime
|
|
1056
1056
|
* @param {!Array.<!shaka.media.SegmentReference>=} partialReferences
|
|
1057
|
-
* @param {?shaka.extern.
|
|
1057
|
+
* @param {?shaka.extern.aes128Key=} aes128Key
|
|
1058
1058
|
* @return {shaka.media.SegmentReference}
|
|
1059
1059
|
*/
|
|
1060
1060
|
function makeReference(uri, startTime, endTime, partialReferences = [],
|
|
1061
|
-
|
|
1061
|
+
aes128Key = null) {
|
|
1062
1062
|
return new shaka.media.SegmentReference(
|
|
1063
1063
|
startTime,
|
|
1064
1064
|
endTime,
|
|
@@ -1074,6 +1074,6 @@ describe('SegmentIndex', /** @suppress {accessControls} */ () => {
|
|
|
1074
1074
|
/* tileDuration= */ undefined,
|
|
1075
1075
|
/* syncTime= */ undefined,
|
|
1076
1076
|
/* status= */ undefined,
|
|
1077
|
-
/*
|
|
1077
|
+
/* aes128Key= */ aes128Key);
|
|
1078
1078
|
}
|
|
1079
1079
|
});
|
|
@@ -109,10 +109,10 @@ describe('StreamingEngine', () => {
|
|
|
109
109
|
/**
|
|
110
110
|
* @param {boolean=} trickMode
|
|
111
111
|
* @param {number=} mediaOffset The offset from 0 for the segment start times
|
|
112
|
-
* @param {shaka.extern.
|
|
112
|
+
* @param {shaka.extern.aes128Key=} aes128Key The AES-128 key to put in
|
|
113
113
|
* the manifest, if one should exist
|
|
114
114
|
*/
|
|
115
|
-
function setupVod(trickMode, mediaOffset,
|
|
115
|
+
function setupVod(trickMode, mediaOffset, aes128Key) {
|
|
116
116
|
// For VOD, we fake a presentation that has 2 Periods of equal duration
|
|
117
117
|
// (20 seconds), where each Period has 1 Variant and 1 text stream.
|
|
118
118
|
//
|
|
@@ -219,7 +219,7 @@ describe('StreamingEngine', () => {
|
|
|
219
219
|
/* firstPeriodStartTime= */ 0,
|
|
220
220
|
/* secondPeriodStartTime= */ 20,
|
|
221
221
|
/* presentationDuration= */ 40,
|
|
222
|
-
|
|
222
|
+
aes128Key);
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
function setupLive() {
|
|
@@ -370,11 +370,11 @@ describe('StreamingEngine', () => {
|
|
|
370
370
|
* @param {number} firstPeriodStartTime
|
|
371
371
|
* @param {number} secondPeriodStartTime
|
|
372
372
|
* @param {number} presentationDuration
|
|
373
|
-
* @param {shaka.extern.
|
|
373
|
+
* @param {shaka.extern.aes128Key=} aes128Key
|
|
374
374
|
*/
|
|
375
375
|
function setupManifest(
|
|
376
376
|
firstPeriodStartTime, secondPeriodStartTime, presentationDuration,
|
|
377
|
-
|
|
377
|
+
aes128Key) {
|
|
378
378
|
const segmentDurations = {
|
|
379
379
|
audio: segmentData[ContentType.AUDIO].segmentDuration,
|
|
380
380
|
video: segmentData[ContentType.VIDEO].segmentDuration,
|
|
@@ -397,7 +397,7 @@ describe('StreamingEngine', () => {
|
|
|
397
397
|
/** @type {!shaka.media.PresentationTimeline} */(timeline),
|
|
398
398
|
[firstPeriodStartTime, secondPeriodStartTime],
|
|
399
399
|
presentationDuration, segmentDurations, initSegmentRanges,
|
|
400
|
-
timestampOffsets,
|
|
400
|
+
timestampOffsets, aes128Key);
|
|
401
401
|
|
|
402
402
|
audioStream = manifest.variants[0].audio;
|
|
403
403
|
videoStream = manifest.variants[0].video;
|
|
@@ -3809,8 +3809,8 @@ describe('StreamingEngine', () => {
|
|
|
3809
3809
|
|
|
3810
3810
|
describe('AES-128', () => {
|
|
3811
3811
|
let key;
|
|
3812
|
-
/** @type {!shaka.extern.
|
|
3813
|
-
let
|
|
3812
|
+
/** @type {!shaka.extern.aes128Key} */
|
|
3813
|
+
let aes128Key;
|
|
3814
3814
|
|
|
3815
3815
|
beforeEach(async () => {
|
|
3816
3816
|
// Get a key.
|
|
@@ -3823,10 +3823,10 @@ describe('StreamingEngine', () => {
|
|
|
3823
3823
|
// Set up a manifest with AES-128 key info.
|
|
3824
3824
|
// We don't actually provide the imported key OR the key fetching function
|
|
3825
3825
|
// here, though, so that the individual tests can choose what the starting
|
|
3826
|
-
// state of the
|
|
3827
|
-
|
|
3826
|
+
// state of the aes128Key object is.
|
|
3827
|
+
aes128Key = {method: 'AES-128', firstMediaSequenceNumber: 0};
|
|
3828
3828
|
|
|
3829
|
-
setupVod(false, 0,
|
|
3829
|
+
setupVod(false, 0, aes128Key);
|
|
3830
3830
|
mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData);
|
|
3831
3831
|
presentationTimeInSeconds = 0;
|
|
3832
3832
|
createStreamingEngine();
|
|
@@ -3851,22 +3851,22 @@ describe('StreamingEngine', () => {
|
|
|
3851
3851
|
}
|
|
3852
3852
|
|
|
3853
3853
|
it('decrypts segments', async () => {
|
|
3854
|
-
|
|
3854
|
+
aes128Key.cryptoKey = key;
|
|
3855
3855
|
await runTest();
|
|
3856
3856
|
});
|
|
3857
3857
|
|
|
3858
3858
|
it('downloads key if not pre-filled', async () => {
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3859
|
+
aes128Key.fetchKey = () => {
|
|
3860
|
+
aes128Key.cryptoKey = key;
|
|
3861
|
+
aes128Key.fetchKey = undefined;
|
|
3862
3862
|
return Promise.resolve();
|
|
3863
3863
|
};
|
|
3864
3864
|
|
|
3865
3865
|
await runTest();
|
|
3866
3866
|
|
|
3867
3867
|
// The key should have been fetched.
|
|
3868
|
-
expect(
|
|
3869
|
-
expect(
|
|
3868
|
+
expect(aes128Key.cryptoKey).not.toBeUndefined();
|
|
3869
|
+
expect(aes128Key.fetchKey).toBeUndefined();
|
|
3870
3870
|
});
|
|
3871
3871
|
});
|
|
3872
3872
|
|
|
@@ -298,6 +298,7 @@ describe('ManifestConverter', () => {
|
|
|
298
298
|
const streamDB = {
|
|
299
299
|
id,
|
|
300
300
|
originalId: id.toString(),
|
|
301
|
+
groupId: null,
|
|
301
302
|
primary: false,
|
|
302
303
|
type,
|
|
303
304
|
mimeType: '',
|
|
@@ -355,6 +356,7 @@ describe('ManifestConverter', () => {
|
|
|
355
356
|
return {
|
|
356
357
|
id,
|
|
357
358
|
originalId: id.toString(),
|
|
359
|
+
groupId: null,
|
|
358
360
|
primary: false,
|
|
359
361
|
type: ContentType.VIDEO,
|
|
360
362
|
mimeType: 'video/mp4',
|
|
@@ -407,6 +409,7 @@ describe('ManifestConverter', () => {
|
|
|
407
409
|
return {
|
|
408
410
|
id,
|
|
409
411
|
originalId: id.toString(),
|
|
412
|
+
groupId: null,
|
|
410
413
|
primary: false,
|
|
411
414
|
type: ContentType.AUDIO,
|
|
412
415
|
mimeType: 'audio/mp4',
|
|
@@ -458,6 +461,7 @@ describe('ManifestConverter', () => {
|
|
|
458
461
|
return {
|
|
459
462
|
id,
|
|
460
463
|
originalId: id.toString(),
|
|
464
|
+
groupId: null,
|
|
461
465
|
primary: false,
|
|
462
466
|
type: ContentType.TEXT,
|
|
463
467
|
mimeType: 'text/vtt',
|
|
@@ -516,6 +520,7 @@ describe('ManifestConverter', () => {
|
|
|
516
520
|
const expectedStream = {
|
|
517
521
|
id: jasmine.any(Number),
|
|
518
522
|
originalId: jasmine.any(String),
|
|
523
|
+
groupId: streamDb.groupId,
|
|
519
524
|
createSegmentIndex: jasmine.any(Function),
|
|
520
525
|
segmentIndex: jasmine.any(shaka.media.SegmentIndex),
|
|
521
526
|
mimeType: streamDb.mimeType,
|
|
@@ -1530,10 +1530,7 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
1530
1530
|
manifest.addVariant(3, (variant) => {
|
|
1531
1531
|
variant.language = frenchCanadian;
|
|
1532
1532
|
variant.bandwidth = kbps(13);
|
|
1533
|
-
variant.
|
|
1534
|
-
stream.bandwidth = kbps(10);
|
|
1535
|
-
stream.size(100, 200);
|
|
1536
|
-
});
|
|
1533
|
+
variant.addExistingStream(1);
|
|
1537
1534
|
variant.addAudio(5, (stream) => {
|
|
1538
1535
|
stream.language = frenchCanadian;
|
|
1539
1536
|
stream.bandwidth = kbps(3);
|