shaka-player 3.1.4 → 3.3.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/ISSUE_TEMPLATE/bug_report.md +1 -1
- package/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
- package/.github/ISSUE_TEMPLATE/question.md +1 -1
- package/AUTHORS +6 -5
- package/CHANGELOG.md +363 -0
- package/CONTRIBUTORS +4 -2
- package/README.md +4 -4
- package/build/types/core +3 -0
- package/build/types/offline +1 -0
- package/build/types/polyfill +2 -0
- package/build/types/ui +2 -0
- package/demo/common/asset.js +9 -7
- package/demo/common/assets.js +28 -1
- package/demo/common/message_ids.js +15 -2
- package/demo/config.js +35 -2
- package/demo/index.html +1 -1
- package/demo/locales/en.json +14 -1
- package/demo/locales/source.json +56 -4
- package/demo/main.js +2 -1
- package/dist/controls.css +26 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +24 -21
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +24 -21
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +33 -25
- package/dist/locales.js +31 -29
- package/dist/receiver.compiled.debug.js +14 -12
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +14 -12
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +258 -20
- package/dist/shaka-player.compiled.debug.d.ts +258 -20
- package/dist/shaka-player.compiled.debug.externs.js +1005 -695
- package/dist/shaka-player.compiled.debug.js +720 -640
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +1005 -695
- package/dist/shaka-player.compiled.js +850 -817
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +274 -21
- package/dist/shaka-player.ui.debug.d.ts +274 -21
- package/dist/shaka-player.ui.debug.externs.js +766 -429
- package/dist/shaka-player.ui.debug.js +863 -765
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +766 -429
- package/dist/shaka-player.ui.js +1042 -996
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/bg-fetch-after.gv +29 -0
- package/docs/design/bg-fetch-after.gv.png +0 -0
- package/docs/design/bg-fetch-before.gv +18 -0
- package/docs/design/bg-fetch-before.gv.png +0 -0
- package/docs/design/bg-fetch.md +134 -0
- package/docs/tutorials/blob-url.md +15 -0
- package/docs/tutorials/index.json +1 -0
- package/docs/tutorials/ui-customization.md +66 -0
- package/docs/tutorials/ui.md +5 -5
- package/externs/aria.js +6 -0
- package/externs/ima.js +3 -0
- package/externs/shaka/ads.js +29 -1
- package/externs/shaka/manifest.js +18 -2
- package/externs/shaka/manifest_parser.js +10 -1
- package/externs/shaka/net.js +20 -4
- package/externs/shaka/offline.js +36 -2
- package/externs/shaka/player.js +182 -13
- package/externs/shaka/text.js +24 -10
- package/externs/texttrack.js +3 -0
- package/externs/webcrypto.js +18 -0
- package/lib/abr/ewma.js +14 -0
- package/lib/abr/ewma_bandwidth_estimator.js +16 -2
- package/lib/abr/simple_abr_manager.js +6 -0
- package/lib/ads/ad_manager.js +16 -15
- package/lib/ads/client_side_ad.js +8 -0
- package/lib/ads/client_side_ad_manager.js +14 -6
- package/lib/ads/server_side_ad.js +7 -0
- package/lib/ads/server_side_ad_manager.js +19 -2
- package/lib/cast/cast_proxy.js +8 -0
- package/lib/cast/cast_utils.js +7 -1
- package/lib/cea/cea608_data_channel.js +56 -56
- package/lib/cea/cea608_memory.js +33 -33
- package/lib/cea/cea708_service.js +43 -43
- package/lib/cea/cea708_window.js +38 -38
- package/lib/cea/cea_decoder.js +13 -14
- package/lib/cea/cea_utils.js +23 -23
- package/lib/cea/dtvcc_packet_builder.js +7 -7
- package/lib/cea/i_caption_decoder.js +2 -3
- package/lib/cea/i_cea_parser.js +2 -2
- package/lib/cea/mp4_cea_parser.js +6 -6
- package/lib/dash/dash_parser.js +53 -14
- package/lib/dash/segment_base.js +25 -1
- package/lib/dash/segment_list.js +18 -9
- package/lib/dash/segment_template.js +23 -10
- package/lib/hls/hls_parser.js +210 -30
- package/lib/media/closed_caption_parser.js +1 -2
- package/lib/media/drm_engine.js +162 -192
- package/lib/media/quality_observer.js +291 -0
- package/lib/media/segment_index.js +9 -1
- package/lib/media/segment_reference.js +37 -5
- package/lib/media/streaming_engine.js +48 -10
- package/lib/net/http_fetch_plugin.js +31 -11
- package/lib/net/http_plugin_utils.js +1 -0
- package/lib/net/http_xhr_plugin.js +40 -14
- package/lib/net/networking_engine.js +82 -18
- package/lib/offline/download_info.js +68 -0
- package/lib/offline/download_manager.js +14 -7
- package/lib/offline/indexeddb/base_storage_cell.js +35 -0
- package/lib/offline/indexeddb/storage_mechanism.js +1 -1
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v5_storage_cell.js +5 -0
- package/lib/offline/manifest_converter.js +3 -1
- package/lib/offline/storage.js +404 -297
- package/lib/offline/stored_content_utils.js +2 -0
- package/lib/player.js +622 -153
- package/lib/polyfill/aria.js +82 -0
- package/lib/polyfill/random_uuid.js +52 -0
- package/lib/routing/walker.js +2 -3
- package/lib/text/cue.js +12 -0
- package/lib/text/srt_text_parser.js +4 -4
- package/lib/text/text_engine.js +2 -2
- package/lib/text/ttml_text_parser.js +25 -2
- package/lib/text/ui_text_displayer.js +2 -2
- package/lib/text/vtt_text_parser.js +2 -2
- package/lib/text/web_vtt_generator.js +55 -12
- package/lib/util/cmcd_manager.js +826 -0
- package/lib/util/error.js +12 -0
- package/lib/util/language_utils.js +12 -0
- package/lib/util/manifest_parser_utils.js +1 -0
- package/lib/util/mp4_box_parsers.js +20 -20
- package/lib/util/multi_map.js +8 -0
- package/lib/util/mutex.js +52 -0
- package/lib/util/periods.js +98 -64
- package/lib/util/player_configuration.js +31 -1
- package/lib/util/stream_utils.js +140 -85
- package/lib/util/xml_utils.js +31 -12
- package/package.json +1 -1
- package/roadmap.md +24 -22
- package/shaka-player.uncompiled.js +4 -0
- package/test/cast/cast_utils_unit.js +1 -0
- package/test/cea/cea608_memory_unit.js +1 -1
- package/test/cea/cea708_service_unit.js +8 -8
- package/test/cea/cea708_window_unit.js +6 -6
- package/test/cea/cea_decoder_unit.js +1 -1
- package/test/cea/dtvcc_packet_builder_unit.js +2 -2
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_live_unit.js +101 -1
- package/test/dash/dash_parser_manifest_unit.js +78 -2
- package/test/dash/dash_parser_segment_base_unit.js +2 -0
- package/test/dash/dash_parser_segment_list_unit.js +2 -1
- package/test/dash/dash_parser_segment_template_unit.js +2 -1
- package/test/hls/hls_live_unit.js +2 -0
- package/test/hls/hls_parser_unit.js +252 -0
- package/test/media/drm_engine_integration.js +86 -12
- package/test/media/drm_engine_unit.js +310 -450
- package/test/media/quality_observer_unit.js +139 -0
- package/test/media/segment_reference_unit.js +16 -1
- package/test/media/streaming_engine_integration.js +2 -1
- package/test/media/streaming_engine_unit.js +2 -0
- package/test/net/http_plugin_unit.js +20 -15
- package/test/offline/manifest_convert_unit.js +2 -0
- package/test/offline/storage_integration.js +117 -23
- package/test/player_integration.js +151 -0
- package/test/player_src_equals_integration.js +52 -0
- package/test/player_unit.js +11 -33
- package/test/test/assets/chapters.srt +11 -0
- package/test/test/assets/chapters.vtt +10 -0
- package/test/test/util/cea_utils.js +12 -12
- package/test/test/util/dash_parser_util.js +4 -0
- package/test/test/util/fake_ad.js +7 -0
- package/test/test/util/fake_ad_manager.js +7 -0
- package/test/test/util/fake_drm_engine.js +9 -2
- package/test/test/util/manifest_generator.js +5 -2
- package/test/test/util/manifest_parser_util.js +3 -1
- package/test/test/util/test_scheme.js +14 -1
- package/test/text/ttml_text_parser_unit.js +47 -0
- package/test/text/web_vtt_generator_unit.js +81 -7
- package/test/ui/ui_unit.js +250 -0
- package/test/util/cmcd_manager_unit.js +277 -0
- package/test/util/stream_utils_unit.js +118 -10
- package/ui/airplay_button.js +2 -1
- package/ui/audio_language_selection.js +9 -5
- package/ui/cast_button.js +5 -6
- package/ui/constants.js +0 -3
- package/ui/context_menu.js +109 -0
- package/ui/controls.js +41 -7
- package/ui/controls.less +1 -0
- package/ui/enums.js +4 -0
- package/ui/externs/ui.js +28 -1
- package/ui/fast_forward_button.js +16 -8
- package/ui/fullscreen_button.js +2 -3
- package/ui/language_utils.js +1 -1
- package/ui/less/buttons.less +0 -4
- package/ui/less/containers.less +74 -0
- package/ui/less/overflow_menu.less +0 -10
- package/ui/less/tooltip.less +97 -0
- package/ui/locales/en.json +1 -0
- package/ui/locales/source.json +4 -0
- package/ui/loop_button.js +6 -3
- package/ui/mute_button.js +3 -4
- package/ui/overflow_menu.js +7 -28
- package/ui/pip_button.js +10 -7
- package/ui/play_button.js +2 -2
- package/ui/playback_rate_selection.js +11 -15
- package/ui/presentation_time.js +1 -3
- package/ui/resolution_selection.js +11 -7
- package/ui/rewind_button.js +17 -9
- package/ui/seek_bar.js +6 -6
- package/ui/settings_menu.js +36 -4
- package/ui/small_play_button.js +1 -0
- package/ui/spacer.js +1 -1
- package/ui/statistics_button.js +253 -0
- package/ui/text_selection.js +19 -15
- package/ui/ui.js +30 -0
- package/ui/ui_utils.js +1 -1
- package/ui/volume_bar.js +2 -4
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
goog.require('shaka.media.QualityObserver');
|
|
8
|
+
goog.require('shaka.test.Util');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
describe('QualityObserver', () => {
|
|
12
|
+
/** @type {!shaka.media.QualityObserver} */
|
|
13
|
+
let observer;
|
|
14
|
+
|
|
15
|
+
/** @type {!jasmine.Spy} */
|
|
16
|
+
let onQualityChange;
|
|
17
|
+
|
|
18
|
+
const createQualityInfo = (contentType, bandwidth) => {
|
|
19
|
+
return {
|
|
20
|
+
bandwidth: bandwidth,
|
|
21
|
+
audioSamplingRate: 444000,
|
|
22
|
+
codecs: 'my codec',
|
|
23
|
+
contentType: contentType,
|
|
24
|
+
frameRate: 30,
|
|
25
|
+
height: 720,
|
|
26
|
+
mimeType: 'mime type',
|
|
27
|
+
channelsCount: 2,
|
|
28
|
+
pixelAspectRatio: '1:1',
|
|
29
|
+
width: 1280,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
let emptyBuffer = true;
|
|
33
|
+
let bufferStart = 0;
|
|
34
|
+
let bufferEnd = 0;
|
|
35
|
+
|
|
36
|
+
const quality1 = createQualityInfo('video', 1);
|
|
37
|
+
const quality2 = createQualityInfo('video', 2);
|
|
38
|
+
|
|
39
|
+
const getBufferedInfo = () => {
|
|
40
|
+
if (emptyBuffer) {
|
|
41
|
+
return {
|
|
42
|
+
video: [],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
video: [{start: bufferStart, end: bufferEnd}],
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
onQualityChange = jasmine.createSpy('onQualityChange');
|
|
52
|
+
observer = new shaka.media.QualityObserver(getBufferedInfo);
|
|
53
|
+
observer.setListeners(shaka.test.Util.spyFunc(onQualityChange));
|
|
54
|
+
emptyBuffer = true;
|
|
55
|
+
bufferStart = 0;
|
|
56
|
+
bufferEnd = 0;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('does not call onQualityChange when there are no quality changes', () => {
|
|
60
|
+
observer.poll(10, false);
|
|
61
|
+
expect(onQualityChange).not.toHaveBeenCalled();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('calls onQualityChange when position is after 1st quality change', () => {
|
|
65
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
66
|
+
emptyBuffer = false;
|
|
67
|
+
bufferStart = 10;
|
|
68
|
+
bufferEnd = 20;
|
|
69
|
+
observer.poll(10, false);
|
|
70
|
+
expect(onQualityChange).toHaveBeenCalledWith(quality1, 10);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('does not call onQualityChange when pos advances with no change', () => {
|
|
74
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
75
|
+
emptyBuffer = false;
|
|
76
|
+
bufferStart = 10;
|
|
77
|
+
bufferEnd = 20;
|
|
78
|
+
observer.poll(10, false);
|
|
79
|
+
expect(onQualityChange).toHaveBeenCalledWith(quality1, 10);
|
|
80
|
+
observer.poll(11, false);
|
|
81
|
+
expect(onQualityChange).toHaveBeenCalledTimes(1);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('does not call onQualityChange on seek to unbuffered position', () => {
|
|
85
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
86
|
+
emptyBuffer = false;
|
|
87
|
+
bufferStart = 10;
|
|
88
|
+
bufferEnd = 20;
|
|
89
|
+
observer.poll(15, false);
|
|
90
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality1, 15]);
|
|
91
|
+
observer.addMediaQualityChange(quality2, 20);
|
|
92
|
+
observer.poll(25, true);
|
|
93
|
+
expect(onQualityChange).not.toHaveBeenCalledOnceMore();
|
|
94
|
+
bufferEnd = 30;
|
|
95
|
+
observer.poll(26, false);
|
|
96
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality2, 26]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('calls onQualityChange when position advances over 2nd quality change',
|
|
100
|
+
() => {
|
|
101
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
102
|
+
emptyBuffer = false;
|
|
103
|
+
bufferStart = 10;
|
|
104
|
+
bufferEnd = 20;
|
|
105
|
+
observer.poll(10, false);
|
|
106
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality1, 10]);
|
|
107
|
+
observer.addMediaQualityChange(quality2, 20);
|
|
108
|
+
bufferStart = 10;
|
|
109
|
+
bufferEnd = 30;
|
|
110
|
+
observer.poll(20, false);
|
|
111
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality2, 20]);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('calls onQualityChange when position moves back over a quality chanage',
|
|
115
|
+
() => {
|
|
116
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
117
|
+
emptyBuffer = false;
|
|
118
|
+
bufferStart = 10;
|
|
119
|
+
bufferEnd = 20;
|
|
120
|
+
observer.addMediaQualityChange(quality2, 20);
|
|
121
|
+
bufferStart = 10;
|
|
122
|
+
bufferEnd = 30;
|
|
123
|
+
observer.poll(25, false);
|
|
124
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality2, 25]);
|
|
125
|
+
observer.poll(15, false);
|
|
126
|
+
expect(onQualityChange).toHaveBeenCalledOnceMoreWith([quality1, 15]);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('uses last applied quality when there are two at the same position',
|
|
130
|
+
() => {
|
|
131
|
+
observer.addMediaQualityChange(quality1, 10);
|
|
132
|
+
observer.addMediaQualityChange(quality2, 10);
|
|
133
|
+
emptyBuffer = false;
|
|
134
|
+
bufferStart = 10;
|
|
135
|
+
bufferEnd = 20;
|
|
136
|
+
observer.poll(15, false);
|
|
137
|
+
expect(onQualityChange).toHaveBeenCalledWith(quality2, 15);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -38,14 +38,29 @@ describe('SegmentReference', () => {
|
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
describe('InitSegmentReference', () => {
|
|
41
|
+
const mediaQuality = {
|
|
42
|
+
bandwidth: 1,
|
|
43
|
+
audioSamplingRate: 444000,
|
|
44
|
+
codecs: 'my codec',
|
|
45
|
+
contentType: 'video',
|
|
46
|
+
frameRate: 30,
|
|
47
|
+
height: 720,
|
|
48
|
+
mimeType: 'mime type',
|
|
49
|
+
channelsCount: 2,
|
|
50
|
+
pixelAspectRatio: '1:1',
|
|
51
|
+
width: 1280,
|
|
52
|
+
};
|
|
53
|
+
|
|
41
54
|
it('returns in getters values from constructor parameters', () => {
|
|
42
55
|
const reference = new shaka.media.InitSegmentReference(
|
|
43
56
|
/* getUris= */ () => ['x', 'y'],
|
|
44
57
|
/* startByte= */ 4,
|
|
45
|
-
/* endByte= */ 5
|
|
58
|
+
/* endByte= */ 5,
|
|
59
|
+
mediaQuality);
|
|
46
60
|
|
|
47
61
|
expect(reference.getUris()).toEqual(['x', 'y']);
|
|
48
62
|
expect(reference.getStartByte()).toBe(4);
|
|
49
63
|
expect(reference.getEndByte()).toBe(5);
|
|
64
|
+
expect(reference.getMediaQuality()).toBe(mediaQuality);
|
|
50
65
|
});
|
|
51
66
|
});
|
|
@@ -60,7 +60,6 @@ describe('StreamingEngine', () => {
|
|
|
60
60
|
/** @type {!shaka.media.StreamingEngine} */
|
|
61
61
|
let streamingEngine;
|
|
62
62
|
|
|
63
|
-
|
|
64
63
|
/** @type {shaka.extern.Variant} */
|
|
65
64
|
let variant;
|
|
66
65
|
|
|
@@ -262,6 +261,7 @@ describe('StreamingEngine', () => {
|
|
|
262
261
|
|
|
263
262
|
function createStreamingEngine() {
|
|
264
263
|
const playerInterface = {
|
|
264
|
+
modifySegmentRequest: (request, segmentInfo) => {},
|
|
265
265
|
getPresentationTime: () => playhead.getTime(),
|
|
266
266
|
getBandwidthEstimate: () => 1e6,
|
|
267
267
|
mediaSourceEngine: mediaSourceEngine,
|
|
@@ -270,6 +270,7 @@ describe('StreamingEngine', () => {
|
|
|
270
270
|
onEvent: Util.spyFunc(onEvent),
|
|
271
271
|
onManifestUpdate: () => {},
|
|
272
272
|
onSegmentAppended: () => playhead.notifyOfBufferingChange(),
|
|
273
|
+
onInitSegmentAppended: () => {},
|
|
273
274
|
};
|
|
274
275
|
streamingEngine = new shaka.media.StreamingEngine(
|
|
275
276
|
/** @type {shaka.extern.Manifest} */(manifest), playerInterface);
|
|
@@ -451,6 +451,7 @@ describe('StreamingEngine', () => {
|
|
|
451
451
|
presentationTimeInSeconds != undefined,
|
|
452
452
|
'All tests should have defined an initial presentation time by now!');
|
|
453
453
|
const playerInterface = {
|
|
454
|
+
modifySegmentRequest: (request, segmentInfo) => {},
|
|
454
455
|
getPresentationTime: () => presentationTimeInSeconds,
|
|
455
456
|
getBandwidthEstimate: Util.spyFunc(getBandwidthEstimate),
|
|
456
457
|
mediaSourceEngine: mediaSourceEngine,
|
|
@@ -459,6 +460,7 @@ describe('StreamingEngine', () => {
|
|
|
459
460
|
onEvent: Util.spyFunc(onEvent),
|
|
460
461
|
onManifestUpdate: Util.spyFunc(onManifestUpdate),
|
|
461
462
|
onSegmentAppended: Util.spyFunc(onSegmentAppended),
|
|
463
|
+
onInitSegmentAppended: () => {},
|
|
462
464
|
};
|
|
463
465
|
streamingEngine = new shaka.media.StreamingEngine(
|
|
464
466
|
/** @type {shaka.extern.Manifest} */(manifest), playerInterface);
|
|
@@ -26,6 +26,9 @@ function httpPluginTests(usingFetch) {
|
|
|
26
26
|
// A dummy progress callback.
|
|
27
27
|
const progressUpdated = (elapsedMs, bytes, bytesRemaining) => {};
|
|
28
28
|
|
|
29
|
+
// A dummy headers callback.
|
|
30
|
+
const headersReceived = (headers) => {};
|
|
31
|
+
|
|
29
32
|
/** @type {shaka.extern.RetryParameters} */
|
|
30
33
|
let retryParameters;
|
|
31
34
|
|
|
@@ -168,7 +171,8 @@ function httpPluginTests(usingFetch) {
|
|
|
168
171
|
request.method = 'POST';
|
|
169
172
|
request.headers['BAZ'] = '123';
|
|
170
173
|
|
|
171
|
-
await plugin(
|
|
174
|
+
await plugin(
|
|
175
|
+
request.uris[0], request, requestType, progressUpdated, headersReceived)
|
|
172
176
|
.promise;
|
|
173
177
|
|
|
174
178
|
const actual = mostRecentRequest();
|
|
@@ -189,8 +193,8 @@ function httpPluginTests(usingFetch) {
|
|
|
189
193
|
request.body = null;
|
|
190
194
|
request.method = 'GET';
|
|
191
195
|
|
|
192
|
-
await plugin(request.uris[0], request, requestType, progressUpdated
|
|
193
|
-
.promise;
|
|
196
|
+
await plugin(request.uris[0], request, requestType, progressUpdated,
|
|
197
|
+
headersReceived).promise;
|
|
194
198
|
|
|
195
199
|
const actual = jasmine.Fetch.requests.mostRecent();
|
|
196
200
|
expect(actual).toBeTruthy();
|
|
@@ -205,8 +209,8 @@ function httpPluginTests(usingFetch) {
|
|
|
205
209
|
|
|
206
210
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
207
211
|
[uri], retryParameters, Util.spyFunc(streamDataCallback));
|
|
208
|
-
const response =
|
|
209
|
-
|
|
212
|
+
const response = await plugin(
|
|
213
|
+
uri, request, requestType, progressUpdated, headersReceived).promise;
|
|
210
214
|
|
|
211
215
|
expect(mostRecentRequest().url).toBe(uri);
|
|
212
216
|
expect(response).toBeTruthy();
|
|
@@ -297,9 +301,9 @@ function httpPluginTests(usingFetch) {
|
|
|
297
301
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
298
302
|
['https://foo.bar/cache'], retryParameters);
|
|
299
303
|
|
|
300
|
-
const response =
|
|
301
|
-
|
|
302
|
-
|
|
304
|
+
const response = await plugin(
|
|
305
|
+
request.uris[0], request, requestType, progressUpdated, headersReceived)
|
|
306
|
+
.promise;
|
|
303
307
|
expect(response).toBeTruthy();
|
|
304
308
|
expect(response.fromCache).toBe(true);
|
|
305
309
|
});
|
|
@@ -312,8 +316,8 @@ function httpPluginTests(usingFetch) {
|
|
|
312
316
|
uri = 'https://foo.bar/timeout';
|
|
313
317
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
314
318
|
[uri], retryParameters);
|
|
315
|
-
const operation = plugin(
|
|
316
|
-
|
|
319
|
+
const operation = plugin(request.uris[0], request, requestType,
|
|
320
|
+
progressUpdated, headersReceived);
|
|
317
321
|
|
|
318
322
|
/** @type {jasmine.Fetch.RequestStub} */
|
|
319
323
|
const actual = jasmine.Fetch.requests.mostRecent();
|
|
@@ -354,8 +358,8 @@ function httpPluginTests(usingFetch) {
|
|
|
354
358
|
uri = 'https://foo.bar/';
|
|
355
359
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
356
360
|
[uri], retryParameters);
|
|
357
|
-
operation = plugin(
|
|
358
|
-
|
|
361
|
+
operation = plugin(request.uris[0], request, requestType, progressUpdated,
|
|
362
|
+
headersReceived);
|
|
359
363
|
requestPromise = operation.promise;
|
|
360
364
|
}
|
|
361
365
|
|
|
@@ -388,8 +392,8 @@ function httpPluginTests(usingFetch) {
|
|
|
388
392
|
async function testSucceeds(uri, overrideUri) {
|
|
389
393
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
390
394
|
[uri], retryParameters);
|
|
391
|
-
const response =
|
|
392
|
-
|
|
395
|
+
const response = await plugin(
|
|
396
|
+
uri, request, requestType, progressUpdated, headersReceived).promise;
|
|
393
397
|
|
|
394
398
|
expect(mostRecentRequest().url).toBe(uri);
|
|
395
399
|
expect(response).toBeTruthy();
|
|
@@ -410,7 +414,8 @@ function httpPluginTests(usingFetch) {
|
|
|
410
414
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
411
415
|
[uri], retryParameters);
|
|
412
416
|
|
|
413
|
-
const p = plugin(
|
|
417
|
+
const p = plugin(
|
|
418
|
+
uri, request, requestType, progressUpdated, headersReceived).promise;
|
|
414
419
|
if (expected.code == shaka.util.Error.Code.TIMEOUT) {
|
|
415
420
|
jasmine.clock().tick(5000);
|
|
416
421
|
}
|
|
@@ -101,6 +101,7 @@ describe('ManifestConverter', () => {
|
|
|
101
101
|
audioRobustness: 'very',
|
|
102
102
|
videoRobustness: 'kinda_sorta',
|
|
103
103
|
serverCertificate: new Uint8Array([1, 2, 3]),
|
|
104
|
+
serverCertificateUri: '',
|
|
104
105
|
sessionType: '',
|
|
105
106
|
initData: [{
|
|
106
107
|
initData: new Uint8Array([4, 5, 6]),
|
|
@@ -316,6 +317,7 @@ describe('ManifestConverter', () => {
|
|
|
316
317
|
appendWindowStart: 0,
|
|
317
318
|
appendWindowEnd: Infinity,
|
|
318
319
|
timestampOffset: 0,
|
|
320
|
+
tilesLayout: '',
|
|
319
321
|
};
|
|
320
322
|
|
|
321
323
|
return segment;
|
|
@@ -22,10 +22,12 @@ goog.require('shaka.test.ManifestGenerator');
|
|
|
22
22
|
goog.require('shaka.test.TestScheme');
|
|
23
23
|
goog.require('shaka.test.Util');
|
|
24
24
|
goog.require('shaka.util.AbortableOperation');
|
|
25
|
+
goog.require('shaka.util.BufferUtils');
|
|
25
26
|
goog.require('shaka.util.Error');
|
|
26
27
|
goog.require('shaka.util.EventManager');
|
|
27
28
|
goog.require('shaka.util.PlayerConfiguration');
|
|
28
29
|
goog.require('shaka.util.PublicPromise');
|
|
30
|
+
goog.require('shaka.util.Uint8ArrayUtils');
|
|
29
31
|
goog.requireType('shaka.media.SegmentReference');
|
|
30
32
|
|
|
31
33
|
/** @return {boolean} */
|
|
@@ -58,12 +60,16 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
58
60
|
const manifestWithNonZeroStartUri = 'fake:manifest-with-non-zero-start';
|
|
59
61
|
const manifestWithLiveTimelineUri = 'fake:manifest-with-live-timeline';
|
|
60
62
|
const manifestWithAlternateSegmentsUri = 'fake:manifest-with-alt-segments';
|
|
63
|
+
const manifestWithVideoInitSegmentsUri =
|
|
64
|
+
'fake:manifest-with-video-init-segments';
|
|
61
65
|
|
|
66
|
+
const initSegmentUri = 'fake:init-segment';
|
|
62
67
|
const segment1Uri = 'fake:segment-1';
|
|
63
68
|
const segment2Uri = 'fake:segment-2';
|
|
64
69
|
const segment3Uri = 'fake:segment-3';
|
|
65
70
|
const segment4Uri = 'fake:segment-4';
|
|
66
71
|
|
|
72
|
+
const alternateInitSegmentUri = 'fake:alt-init-segment';
|
|
67
73
|
const alternateSegment1Uri = 'fake:alt-segment-1';
|
|
68
74
|
const alternateSegment2Uri = 'fake:alt-segment-2';
|
|
69
75
|
const alternateSegment3Uri = 'fake:alt-segment-3';
|
|
@@ -147,15 +153,7 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
147
153
|
}
|
|
148
154
|
});
|
|
149
155
|
|
|
150
|
-
|
|
151
|
-
const isEnabled = useMediaCapabilities ? 'enabled' : 'disabled';
|
|
152
|
-
filterDescribe('persistent license with MediaCapabilities ' + isEnabled,
|
|
153
|
-
drmStorageSupport, () => {
|
|
154
|
-
testPersistentLicense(useMediaCapabilities);
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function testPersistentLicense(useMediaCapabilities) {
|
|
156
|
+
filterDescribe('persistent license', drmStorageSupport, () => {
|
|
159
157
|
/** @type {!shaka.Player} */
|
|
160
158
|
let player;
|
|
161
159
|
/** @type {!shaka.offline.Storage} */
|
|
@@ -166,7 +164,6 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
166
164
|
// networking engine. This allows us to use Player.configure in these
|
|
167
165
|
// tests.
|
|
168
166
|
player = new shaka.Player();
|
|
169
|
-
player.configure({'useMediaCapabilities': useMediaCapabilities});
|
|
170
167
|
storage = new shaka.offline.Storage(player);
|
|
171
168
|
});
|
|
172
169
|
|
|
@@ -201,7 +198,7 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
201
198
|
expect(manifest.offlineSessionIds.length).toBeTruthy();
|
|
202
199
|
|
|
203
200
|
// PART 2 - Check that the licences are stored.
|
|
204
|
-
await withDrm(player, manifest,
|
|
201
|
+
await withDrm(player, manifest, (drm) => {
|
|
205
202
|
return Promise.all(manifest.offlineSessionIds.map(async (session) => {
|
|
206
203
|
const foundSession = await loadOfflineSession(drm, session);
|
|
207
204
|
expect(foundSession).toBeTruthy();
|
|
@@ -213,7 +210,7 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
213
210
|
await storage.remove(uri.toString());
|
|
214
211
|
|
|
215
212
|
// PART 4 - Check that the licenses were removed.
|
|
216
|
-
const p = withDrm(player, manifest,
|
|
213
|
+
const p = withDrm(player, manifest, (drm) => {
|
|
217
214
|
return Promise.all(manifest.offlineSessionIds.map(async (session) => {
|
|
218
215
|
const notFoundSession = await loadOfflineSession(drm, session);
|
|
219
216
|
expect(notFoundSession).toBeFalsy();
|
|
@@ -257,7 +254,7 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
257
254
|
const storedContents = await storage.list();
|
|
258
255
|
expect(storedContents).toEqual([]);
|
|
259
256
|
|
|
260
|
-
await withDrm(player, manifest,
|
|
257
|
+
await withDrm(player, manifest, (drm) => {
|
|
261
258
|
return Promise.all(manifest.offlineSessionIds.map(async (session) => {
|
|
262
259
|
const foundSession = await loadOfflineSession(drm, session);
|
|
263
260
|
expect(foundSession).toBeTruthy();
|
|
@@ -270,7 +267,7 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
270
267
|
expect(didRemoveAll).toBe(true);
|
|
271
268
|
|
|
272
269
|
// PART 6 - Check that the licenses were removed.
|
|
273
|
-
const p = withDrm(player, manifest,
|
|
270
|
+
const p = withDrm(player, manifest, (drm) => {
|
|
274
271
|
return Promise.all(manifest.offlineSessionIds.map(async (session) => {
|
|
275
272
|
const notFoundSession = await loadOfflineSession(drm, session);
|
|
276
273
|
expect(notFoundSession).toBeFalsy();
|
|
@@ -282,7 +279,7 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
282
279
|
shaka.util.Error.Code.OFFLINE_SESSION_REMOVED));
|
|
283
280
|
await expectAsync(p).toBeRejectedWith(expected);
|
|
284
281
|
});
|
|
285
|
-
}
|
|
282
|
+
});
|
|
286
283
|
|
|
287
284
|
describe('default track selection callback', () => {
|
|
288
285
|
const PlayerConfiguration = shaka.util.PlayerConfiguration;
|
|
@@ -954,6 +951,46 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
954
951
|
}
|
|
955
952
|
});
|
|
956
953
|
|
|
954
|
+
it('can extract DRM info from segments', async () => {
|
|
955
|
+
const pssh1 =
|
|
956
|
+
'00000028' + // atom size
|
|
957
|
+
'70737368' + // atom type='pssh'
|
|
958
|
+
'00000000' + // v0, flags=0
|
|
959
|
+
'edef8ba979d64acea3c827dcd51d21ed' + // system id (Widevine)
|
|
960
|
+
'00000008' + // data size
|
|
961
|
+
'0102030405060708'; // data
|
|
962
|
+
const psshData1 = shaka.util.Uint8ArrayUtils.fromHex(pssh1);
|
|
963
|
+
const pssh2 =
|
|
964
|
+
'00000028' + // atom size
|
|
965
|
+
'70737368' + // atom type='pssh'
|
|
966
|
+
'00000000' + // v0, flags=0
|
|
967
|
+
'edef8ba979d64acea3c827dcd51d21ed' + // system id (Widevine)
|
|
968
|
+
'00000008' + // data size
|
|
969
|
+
'1337420123456789'; // data
|
|
970
|
+
const psshData2 = shaka.util.Uint8ArrayUtils.fromHex(pssh2);
|
|
971
|
+
netEngine.setResponseValue(initSegmentUri,
|
|
972
|
+
shaka.util.BufferUtils.toArrayBuffer(psshData1));
|
|
973
|
+
netEngine.setResponseValue(alternateInitSegmentUri,
|
|
974
|
+
shaka.util.BufferUtils.toArrayBuffer(psshData2));
|
|
975
|
+
|
|
976
|
+
const drm = new shaka.test.FakeDrmEngine();
|
|
977
|
+
const drmInfo = makeDrmInfo();
|
|
978
|
+
drmInfo.keySystem = 'com.widevine.alpha';
|
|
979
|
+
drm.setDrmInfo(drmInfo);
|
|
980
|
+
overrideDrmAndManifest(
|
|
981
|
+
storage,
|
|
982
|
+
drm,
|
|
983
|
+
makeManifestWithVideoInitSegments());
|
|
984
|
+
|
|
985
|
+
const stored = await storage.store(
|
|
986
|
+
manifestWithVideoInitSegmentsUri, noMetadata, fakeMimeType).promise;
|
|
987
|
+
goog.asserts.assert(stored.offlineUri != null, 'URI should not be null!');
|
|
988
|
+
|
|
989
|
+
// The manifest chooses the alternate stream, so expect only the alt init
|
|
990
|
+
// segment.
|
|
991
|
+
expect(drm.newInitData).toHaveBeenCalledWith('cenc', psshData2);
|
|
992
|
+
});
|
|
993
|
+
|
|
957
994
|
it('can store multiple assets at once', async () => {
|
|
958
995
|
// Block the network so that we won't finish the first store command.
|
|
959
996
|
/** @type {!shaka.util.PublicPromise} */
|
|
@@ -1243,11 +1280,11 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
1243
1280
|
goog.asserts.assert(
|
|
1244
1281
|
content.offlineUri != null, 'URI should not be null!');
|
|
1245
1282
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1283
|
+
// We expect 5 progress events because there are 4 unique segments, plus
|
|
1284
|
+
// the manifest.
|
|
1285
|
+
/** @type {!Array.<number>}*/
|
|
1249
1286
|
const progressSteps = [
|
|
1250
|
-
0.
|
|
1287
|
+
0.2, 0.4, 0.6, 0.8, 1,
|
|
1251
1288
|
];
|
|
1252
1289
|
|
|
1253
1290
|
const progressCallback = (content, progress) => {
|
|
@@ -1408,6 +1445,62 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
1408
1445
|
};
|
|
1409
1446
|
}
|
|
1410
1447
|
|
|
1448
|
+
/** @return {shaka.extern.Manifest} */
|
|
1449
|
+
function makeManifestWithVideoInitSegments() {
|
|
1450
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
1451
|
+
manifest.presentationTimeline.setDuration(20);
|
|
1452
|
+
|
|
1453
|
+
manifest.addVariant(0, (variant) => {
|
|
1454
|
+
variant.bandwidth = kbps(13);
|
|
1455
|
+
variant.addVideo(1, (stream) => {
|
|
1456
|
+
stream.bandwidth = kbps(13);
|
|
1457
|
+
stream.size(100, 200);
|
|
1458
|
+
});
|
|
1459
|
+
});
|
|
1460
|
+
manifest.addVariant(2, (variant) => {
|
|
1461
|
+
variant.bandwidth = kbps(20);
|
|
1462
|
+
variant.addVideo(3, (stream) => {
|
|
1463
|
+
stream.bandwidth = kbps(20);
|
|
1464
|
+
stream.size(200, 400);
|
|
1465
|
+
});
|
|
1466
|
+
});
|
|
1467
|
+
});
|
|
1468
|
+
|
|
1469
|
+
const stream = manifest.variants[0].video;
|
|
1470
|
+
goog.asserts.assert(stream, 'The first stream should exist');
|
|
1471
|
+
stream.encrypted = true;
|
|
1472
|
+
const init = new shaka.media.InitSegmentReference(
|
|
1473
|
+
() => [initSegmentUri], 0, null);
|
|
1474
|
+
const refs = [
|
|
1475
|
+
makeReference(segment1Uri, 0, 1),
|
|
1476
|
+
makeReference(segment2Uri, 1, 2),
|
|
1477
|
+
makeReference(segment3Uri, 2, 3),
|
|
1478
|
+
makeReference(segment4Uri, 3, 4),
|
|
1479
|
+
];
|
|
1480
|
+
for (const ref of refs) {
|
|
1481
|
+
ref.initSegmentReference = init;
|
|
1482
|
+
}
|
|
1483
|
+
overrideSegmentIndex(stream, refs);
|
|
1484
|
+
|
|
1485
|
+
const streamAlt = manifest.variants[1].video;
|
|
1486
|
+
goog.asserts.assert(streamAlt, 'The second stream should exist');
|
|
1487
|
+
streamAlt.encrypted = true;
|
|
1488
|
+
const initAlt = new shaka.media.InitSegmentReference(
|
|
1489
|
+
() => [alternateInitSegmentUri], 0, null);
|
|
1490
|
+
const refsAlt = [
|
|
1491
|
+
makeReference(alternateSegment1Uri, 0, 1),
|
|
1492
|
+
makeReference(alternateSegment2Uri, 1, 2),
|
|
1493
|
+
makeReference(alternateSegment3Uri, 2, 3),
|
|
1494
|
+
makeReference(alternateSegment4Uri, 3, 4),
|
|
1495
|
+
];
|
|
1496
|
+
for (const ref of refsAlt) {
|
|
1497
|
+
ref.initSegmentReference = initAlt;
|
|
1498
|
+
}
|
|
1499
|
+
overrideSegmentIndex(streamAlt, refsAlt);
|
|
1500
|
+
|
|
1501
|
+
return manifest;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1411
1504
|
/** @return {shaka.extern.Manifest} */
|
|
1412
1505
|
function makeManifestWithPerStreamBandwidth() {
|
|
1413
1506
|
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
@@ -1598,6 +1691,7 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
1598
1691
|
keyIds: null,
|
|
1599
1692
|
sessionType: 'temporary',
|
|
1600
1693
|
serverCertificate: null,
|
|
1694
|
+
serverCertificateUri: '',
|
|
1601
1695
|
audioRobustness: 'HARDY',
|
|
1602
1696
|
videoRobustness: 'OTHER',
|
|
1603
1697
|
};
|
|
@@ -1620,6 +1714,8 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
1620
1714
|
makeManifestWithLiveTimeline();
|
|
1621
1715
|
this.map_[manifestWithAlternateSegmentsUri] =
|
|
1622
1716
|
makeManifestWithAlternateSegments();
|
|
1717
|
+
this.map_[manifestWithVideoInitSegmentsUri] =
|
|
1718
|
+
makeManifestWithVideoInitSegments();
|
|
1623
1719
|
}
|
|
1624
1720
|
|
|
1625
1721
|
/** @override */
|
|
@@ -1681,11 +1777,10 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
1681
1777
|
/**
|
|
1682
1778
|
* @param {!shaka.Player} player
|
|
1683
1779
|
* @param {shaka.extern.Manifest} manifest
|
|
1684
|
-
* @param {boolean} useMediaCapabilities
|
|
1685
1780
|
* @param {function(!shaka.media.DrmEngine):Promise} action
|
|
1686
1781
|
* @return {!Promise}
|
|
1687
1782
|
*/
|
|
1688
|
-
async function withDrm(player, manifest,
|
|
1783
|
+
async function withDrm(player, manifest, action) {
|
|
1689
1784
|
const net = player.getNetworkingEngine();
|
|
1690
1785
|
goog.asserts.assert(net, 'Player should have a net engine right now');
|
|
1691
1786
|
|
|
@@ -1703,8 +1798,7 @@ filterDescribe('Storage', storageSupport, () => {
|
|
|
1703
1798
|
try {
|
|
1704
1799
|
drm.configure(player.getConfiguration().drm);
|
|
1705
1800
|
const variants = manifest.variants;
|
|
1706
|
-
await drm.initForStorage(variants, /* usePersistentLicenses= */ true
|
|
1707
|
-
useMediaCapabilities);
|
|
1801
|
+
await drm.initForStorage(variants, /* usePersistentLicenses= */ true);
|
|
1708
1802
|
await action(drm);
|
|
1709
1803
|
} finally {
|
|
1710
1804
|
await drm.destroy();
|