shaka-player 4.2.3 → 4.2.5
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/AUTHORS +2 -0
- package/CHANGELOG.md +39 -0
- package/CONTRIBUTORS +2 -0
- package/demo/index.html +1 -1
- package/dist/demo.compiled.debug.js +64 -64
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +64 -64
- package/dist/demo.compiled.map +2 -2
- package/dist/deps.js +5 -4
- package/dist/locales.js +32 -32
- package/dist/receiver.compiled.debug.js +12 -12
- package/dist/receiver.compiled.debug.map +2 -2
- package/dist/receiver.compiled.js +12 -12
- package/dist/receiver.compiled.map +2 -2
- package/dist/shaka-player.compiled.d.ts +15 -1
- package/dist/shaka-player.compiled.debug.d.ts +15 -1
- package/dist/shaka-player.compiled.debug.externs.js +95 -80
- package/dist/shaka-player.compiled.debug.js +583 -573
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +95 -80
- package/dist/shaka-player.compiled.js +823 -820
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +15 -1
- package/dist/shaka-player.ui.debug.d.ts +15 -1
- package/dist/shaka-player.ui.debug.externs.js +95 -80
- package/dist/shaka-player.ui.debug.js +612 -602
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +95 -80
- package/dist/shaka-player.ui.js +963 -960
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/ui.md +7 -7
- package/docs/tutorials/welcome.md +2 -2
- package/externs/mux.js +3 -0
- package/externs/shaka/player.js +2 -1
- package/lib/cast/cast_proxy.js +2 -1
- package/lib/cast/cast_receiver.js +19 -5
- package/lib/cast/cast_sender.js +2 -1
- package/lib/cast/cast_utils.js +16 -6
- package/lib/cea/cea708_window.js +2 -2
- package/lib/dash/segment_template.js +1 -1
- package/lib/hls/hls_parser.js +21 -4
- package/lib/media/content_workarounds.js +12 -0
- package/lib/media/media_source_engine.js +6 -0
- package/lib/media/playhead.js +23 -1
- package/lib/media/streaming_engine.js +3 -12
- package/lib/media/transmuxer.js +6 -0
- package/lib/player.js +24 -11
- package/lib/polyfill/abort_controller.js +143 -0
- package/lib/polyfill/media_capabilities.js +59 -9
- package/lib/text/ttml_text_parser.js +32 -7
- package/lib/text/ui_text_displayer.js +22 -5
- package/lib/util/manifest_parser_utils.js +4 -0
- package/lib/util/platform.js +9 -1
- package/lib/util/player_configuration.js +10 -3
- package/lib/util/stream_utils.js +30 -10
- package/package.json +1 -1
- package/roadmap.md +24 -6
- package/shaka-player.uncompiled.js +1 -0
- package/test/cast/cast_receiver_integration.js +97 -16
- package/test/cast/cast_receiver_unit.js +17 -12
- package/test/cast/cast_utils_unit.js +1 -0
- package/test/dash/dash_parser_manifest_unit.js +1 -0
- package/test/hls/hls_parser_unit.js +1 -0
- package/test/media/drm_engine_unit.js +11 -1
- package/test/media/media_source_engine_integration.js +108 -1
- package/test/media/playhead_unit.js +41 -0
- package/test/media/streaming_engine_integration.js +13 -0
- package/test/media/streaming_engine_unit.js +36 -23
- package/test/player_unit.js +87 -0
- package/test/polyfill/media_capabilities_unit.js +261 -0
- package/test/test/util/simple_fakes.js +3 -0
- package/test/test/util/stream_generator.js +212 -8
- package/test/test/util/test_scheme.js +3 -2
- package/test/test/util/util.js +3 -2
- package/test/text/mp4_ttml_parser_unit.js +6 -4
- package/test/text/ttml_text_parser_unit.js +119 -86
- package/test/text/ui_text_displayer_unit.js +76 -0
- package/test/ui/text_displayer_layout_unit.js +14 -0
- package/test/util/stream_utils_unit.js +18 -0
- package/test/util/xml_utils_unit.js +6 -1
- package/ui/controls.js +49 -37
- package/ui/settings_menu.js +11 -2
|
@@ -878,7 +878,7 @@ describe('StreamingEngine', () => {
|
|
|
878
878
|
|
|
879
879
|
const config = shaka.util.PlayerConfiguration.createDefault().streaming;
|
|
880
880
|
config.bufferingGoal = 60;
|
|
881
|
-
config.failureCallback = () => streamingEngine.retry();
|
|
881
|
+
config.failureCallback = () => streamingEngine.retry(0.1);
|
|
882
882
|
createStreamingEngine(config);
|
|
883
883
|
|
|
884
884
|
// Make requests for different types take different amounts of time.
|
|
@@ -1737,8 +1737,23 @@ describe('StreamingEngine', () => {
|
|
|
1737
1737
|
beforeEach(() => {
|
|
1738
1738
|
setupLive();
|
|
1739
1739
|
mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData, 0);
|
|
1740
|
-
|
|
1740
|
+
|
|
1741
|
+
// Retry on failure for live streams.
|
|
1742
|
+
const config = shaka.util.PlayerConfiguration.createDefault().streaming;
|
|
1743
|
+
config.failureCallback = () => streamingEngine.retry(0.1);
|
|
1744
|
+
|
|
1745
|
+
createStreamingEngine(config);
|
|
1741
1746
|
presentationTimeInSeconds = 100;
|
|
1747
|
+
|
|
1748
|
+
// Ignore 404 errors in live stream tests.
|
|
1749
|
+
onError.and.callFake((error) => {
|
|
1750
|
+
if (error.code == shaka.util.Error.Code.BAD_HTTP_STATUS &&
|
|
1751
|
+
error.data[1] == 404) {
|
|
1752
|
+
// 404 error
|
|
1753
|
+
} else {
|
|
1754
|
+
fail(error);
|
|
1755
|
+
}
|
|
1756
|
+
});
|
|
1742
1757
|
});
|
|
1743
1758
|
|
|
1744
1759
|
it('outside segment availability window', async () => {
|
|
@@ -1768,24 +1783,22 @@ describe('StreamingEngine', () => {
|
|
|
1768
1783
|
const originalAppendBuffer =
|
|
1769
1784
|
// eslint-disable-next-line no-restricted-syntax
|
|
1770
1785
|
shaka.test.FakeMediaSourceEngine.prototype.appendBufferImpl;
|
|
1771
|
-
mediaSourceEngine.appendBuffer.and.callFake(
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
originalAppendBuffer);
|
|
1783
|
-
}
|
|
1786
|
+
mediaSourceEngine.appendBuffer.and.callFake((type, data, reference) => {
|
|
1787
|
+
expect(presentationTimeInSeconds).toBe(125);
|
|
1788
|
+
// Ignore a possible call for the first Period.
|
|
1789
|
+
if (reference && reference.startTime >= 100) {
|
|
1790
|
+
expect(Util.invokeSpy(timeline.getSegmentAvailabilityStart))
|
|
1791
|
+
.not.toBeLessThan(100);
|
|
1792
|
+
expect(Util.invokeSpy(timeline.getSegmentAvailabilityEnd))
|
|
1793
|
+
.not.toBeLessThan(120);
|
|
1794
|
+
playing = true;
|
|
1795
|
+
mediaSourceEngine.appendBuffer.and.callFake(originalAppendBuffer);
|
|
1796
|
+
}
|
|
1784
1797
|
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1798
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
1799
|
+
return originalAppendBuffer.call(
|
|
1800
|
+
mediaSourceEngine, type, data, reference);
|
|
1801
|
+
});
|
|
1789
1802
|
|
|
1790
1803
|
await runTest(slideSegmentAvailabilityWindow);
|
|
1791
1804
|
// Verify buffers.
|
|
@@ -2001,7 +2014,7 @@ describe('StreamingEngine', () => {
|
|
|
2001
2014
|
mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData);
|
|
2002
2015
|
|
|
2003
2016
|
const config = shaka.util.PlayerConfiguration.createDefault().streaming;
|
|
2004
|
-
config.failureCallback = () => streamingEngine.retry();
|
|
2017
|
+
config.failureCallback = () => streamingEngine.retry(0.1);
|
|
2005
2018
|
createStreamingEngine(config);
|
|
2006
2019
|
|
|
2007
2020
|
presentationTimeInSeconds = 100;
|
|
@@ -2162,7 +2175,7 @@ describe('StreamingEngine', () => {
|
|
|
2162
2175
|
netEngine.request.calls.reset();
|
|
2163
2176
|
|
|
2164
2177
|
// Retry streaming.
|
|
2165
|
-
expect(streamingEngine.retry()).toBe(true);
|
|
2178
|
+
expect(streamingEngine.retry(0.1)).toBe(true);
|
|
2166
2179
|
});
|
|
2167
2180
|
|
|
2168
2181
|
// Here we go!
|
|
@@ -2192,7 +2205,7 @@ describe('StreamingEngine', () => {
|
|
|
2192
2205
|
|
|
2193
2206
|
// Retry streaming, which should fail and return false.
|
|
2194
2207
|
netEngine.request.calls.reset();
|
|
2195
|
-
expect(streamingEngine.retry()).toBe(false);
|
|
2208
|
+
expect(streamingEngine.retry(0.1)).toBe(false);
|
|
2196
2209
|
});
|
|
2197
2210
|
|
|
2198
2211
|
// Here we go!
|
|
@@ -2244,7 +2257,7 @@ describe('StreamingEngine', () => {
|
|
|
2244
2257
|
|
|
2245
2258
|
// Retry streaming, which should fail and return false.
|
|
2246
2259
|
netEngine.request.calls.reset();
|
|
2247
|
-
expect(streamingEngine.retry()).toBe(false);
|
|
2260
|
+
expect(streamingEngine.retry(0.1)).toBe(false);
|
|
2248
2261
|
}
|
|
2249
2262
|
});
|
|
2250
2263
|
|
package/test/player_unit.js
CHANGED
|
@@ -3940,6 +3940,93 @@ describe('Player', () => {
|
|
|
3940
3940
|
});
|
|
3941
3941
|
});
|
|
3942
3942
|
|
|
3943
|
+
describe('config streaming.failureCallback default', () => {
|
|
3944
|
+
/** @type {jasmine.Spy} */
|
|
3945
|
+
let retryStreaming;
|
|
3946
|
+
/** @type {jasmine.Spy} */
|
|
3947
|
+
let isLive;
|
|
3948
|
+
|
|
3949
|
+
/**
|
|
3950
|
+
* @suppress {accessControls}
|
|
3951
|
+
* @param {!shaka.util.Error} error
|
|
3952
|
+
*/
|
|
3953
|
+
function defaultStreamingFailureCallback(error) {
|
|
3954
|
+
player.defaultStreamingFailureCallback_(error);
|
|
3955
|
+
}
|
|
3956
|
+
|
|
3957
|
+
beforeEach(() => {
|
|
3958
|
+
retryStreaming = jasmine.createSpy('retryStreaming');
|
|
3959
|
+
isLive = jasmine.createSpy('isLive');
|
|
3960
|
+
|
|
3961
|
+
player.retryStreaming = Util.spyFunc(retryStreaming);
|
|
3962
|
+
player.isLive = Util.spyFunc(isLive);
|
|
3963
|
+
});
|
|
3964
|
+
|
|
3965
|
+
it('ignores VOD failures', () => {
|
|
3966
|
+
isLive.and.returnValue(false);
|
|
3967
|
+
|
|
3968
|
+
const error = new shaka.util.Error(
|
|
3969
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
3970
|
+
shaka.util.Error.Category.NETWORK,
|
|
3971
|
+
shaka.util.Error.Code.BAD_HTTP_STATUS,
|
|
3972
|
+
/* url= */ '',
|
|
3973
|
+
/* http_status= */ 404);
|
|
3974
|
+
|
|
3975
|
+
defaultStreamingFailureCallback(error);
|
|
3976
|
+
expect(retryStreaming).not.toHaveBeenCalled();
|
|
3977
|
+
});
|
|
3978
|
+
|
|
3979
|
+
it('retries live on HTTP 404', () => {
|
|
3980
|
+
isLive.and.returnValue(true);
|
|
3981
|
+
|
|
3982
|
+
const error = new shaka.util.Error(
|
|
3983
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
3984
|
+
shaka.util.Error.Category.NETWORK,
|
|
3985
|
+
shaka.util.Error.Code.BAD_HTTP_STATUS,
|
|
3986
|
+
/* url= */ '',
|
|
3987
|
+
/* http_status= */ 404);
|
|
3988
|
+
|
|
3989
|
+
defaultStreamingFailureCallback(error);
|
|
3990
|
+
expect(retryStreaming).toHaveBeenCalled();
|
|
3991
|
+
});
|
|
3992
|
+
|
|
3993
|
+
it('retries live on generic HTTP error', () => {
|
|
3994
|
+
isLive.and.returnValue(true);
|
|
3995
|
+
|
|
3996
|
+
const error = new shaka.util.Error(
|
|
3997
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
3998
|
+
shaka.util.Error.Category.NETWORK,
|
|
3999
|
+
shaka.util.Error.Code.HTTP_ERROR);
|
|
4000
|
+
|
|
4001
|
+
defaultStreamingFailureCallback(error);
|
|
4002
|
+
expect(retryStreaming).toHaveBeenCalled();
|
|
4003
|
+
});
|
|
4004
|
+
|
|
4005
|
+
it('retries live on HTTP timeout', () => {
|
|
4006
|
+
isLive.and.returnValue(true);
|
|
4007
|
+
|
|
4008
|
+
const error = new shaka.util.Error(
|
|
4009
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
4010
|
+
shaka.util.Error.Category.NETWORK,
|
|
4011
|
+
shaka.util.Error.Code.TIMEOUT);
|
|
4012
|
+
|
|
4013
|
+
defaultStreamingFailureCallback(error);
|
|
4014
|
+
expect(retryStreaming).toHaveBeenCalled();
|
|
4015
|
+
});
|
|
4016
|
+
|
|
4017
|
+
it('ignores other live failures', () => {
|
|
4018
|
+
isLive.and.returnValue(true);
|
|
4019
|
+
|
|
4020
|
+
const error = new shaka.util.Error(
|
|
4021
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
4022
|
+
shaka.util.Error.Category.MEDIA,
|
|
4023
|
+
shaka.util.Error.Code.VIDEO_ERROR);
|
|
4024
|
+
|
|
4025
|
+
defaultStreamingFailureCallback(error);
|
|
4026
|
+
expect(retryStreaming).not.toHaveBeenCalled();
|
|
4027
|
+
});
|
|
4028
|
+
});
|
|
4029
|
+
|
|
3943
4030
|
/**
|
|
3944
4031
|
* Gets the currently active variant track.
|
|
3945
4032
|
* @return {shaka.extern.Track}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
describe('MediaCapabilities', () => {
|
|
8
|
+
const Util = shaka.test.Util;
|
|
9
|
+
const originalCast = window['cast'];
|
|
10
|
+
const originalVendor = navigator.vendor;
|
|
11
|
+
const originalUserAgent = navigator.userAgent;
|
|
12
|
+
const originalRequestMediaKeySystemAccess =
|
|
13
|
+
navigator.requestMediaKeySystemAccess;
|
|
14
|
+
const originalMediaCapabilities = navigator.mediaCapabilities;
|
|
15
|
+
|
|
16
|
+
/** @type {MediaDecodingConfiguration} */
|
|
17
|
+
let mockDecodingConfig;
|
|
18
|
+
/** @type {!jasmine.Spy} */
|
|
19
|
+
let mockCanDisplayType;
|
|
20
|
+
|
|
21
|
+
beforeAll(() => {
|
|
22
|
+
Object.defineProperty(window['navigator'],
|
|
23
|
+
'userAgent', {
|
|
24
|
+
value: 'unknown', configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(window['navigator'],
|
|
28
|
+
'vendor', {
|
|
29
|
+
value: 'unknown', configurable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(window['navigator'],
|
|
33
|
+
'requestMediaKeySystemAccess', {
|
|
34
|
+
value: 'unknown', configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
});
|
|
37
|
+
Object.defineProperty(window['navigator'],
|
|
38
|
+
'mediaCapabilities', {
|
|
39
|
+
value: undefined, configurable: true,
|
|
40
|
+
writable: true,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
mockDecodingConfig = {
|
|
46
|
+
audio: {
|
|
47
|
+
bitrate: 100891,
|
|
48
|
+
channels: 2,
|
|
49
|
+
contentType: 'audio/mp4; codecs="mp4a.40.2"',
|
|
50
|
+
samplerate: 48000,
|
|
51
|
+
spatialRendering: false,
|
|
52
|
+
},
|
|
53
|
+
keySystemConfiguration: {
|
|
54
|
+
audio: {robustness: 'SW_SECURE_CRYPTO'},
|
|
55
|
+
distinctiveIdentifier: 'optional',
|
|
56
|
+
initDataType: 'cenc',
|
|
57
|
+
keySystem: 'com.widevine.alpha',
|
|
58
|
+
persistentState: 'optional',
|
|
59
|
+
sessionTypes: ['temporary'],
|
|
60
|
+
video: {robustness: 'SW_SECURE_CRYPTO'},
|
|
61
|
+
},
|
|
62
|
+
type: 'media-source',
|
|
63
|
+
video: {
|
|
64
|
+
bitrate: 349265,
|
|
65
|
+
contentType: 'video/mp4; codecs="avc1.4D4015"',
|
|
66
|
+
framerate: 23.976023976023978,
|
|
67
|
+
height: 288,
|
|
68
|
+
width: 512,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
shaka.polyfill.MediaCapabilities.memoizedMediaKeySystemAccessRequests_ = {};
|
|
72
|
+
|
|
73
|
+
mockCanDisplayType = jasmine.createSpy('canDisplayType');
|
|
74
|
+
mockCanDisplayType.and.returnValue(false);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
afterEach(() => {
|
|
78
|
+
window['cast'] = originalCast;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
afterAll(() => {
|
|
82
|
+
window['cast'] = originalCast;
|
|
83
|
+
Object.defineProperty(window['navigator'],
|
|
84
|
+
'userAgent', {value: originalUserAgent});
|
|
85
|
+
Object.defineProperty(window['navigator'],
|
|
86
|
+
'vendor', {value: originalVendor});
|
|
87
|
+
Object.defineProperty(window['navigator'],
|
|
88
|
+
'requestMediaKeySystemAccess',
|
|
89
|
+
{value: originalRequestMediaKeySystemAccess});
|
|
90
|
+
Object.defineProperty(window['navigator'],
|
|
91
|
+
'mediaCapabilities', {value: originalMediaCapabilities});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('install', () => {
|
|
95
|
+
it('should define decoding info method', () => {
|
|
96
|
+
shaka.polyfill.MediaCapabilities.install();
|
|
97
|
+
|
|
98
|
+
expect(navigator.mediaCapabilities.decodingInfo).toBeDefined();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('decodingInfo', () => {
|
|
103
|
+
it('should check codec support when MediaDecodingConfiguration.type ' +
|
|
104
|
+
'is "media-source"', () => {
|
|
105
|
+
const isTypeSupportedSpy =
|
|
106
|
+
spyOn(window['MediaSource'], 'isTypeSupported').and.returnValue(true);
|
|
107
|
+
shaka.polyfill.MediaCapabilities.install();
|
|
108
|
+
navigator.mediaCapabilities.decodingInfo(mockDecodingConfig);
|
|
109
|
+
|
|
110
|
+
expect(isTypeSupportedSpy).toHaveBeenCalledTimes(2);
|
|
111
|
+
expect(isTypeSupportedSpy).toHaveBeenCalledWith(
|
|
112
|
+
mockDecodingConfig.video.contentType,
|
|
113
|
+
);
|
|
114
|
+
expect(isTypeSupportedSpy).toHaveBeenCalledWith(
|
|
115
|
+
mockDecodingConfig.audio.contentType,
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should check codec support when MediaDecodingConfiguration.type ' +
|
|
120
|
+
'is "file"', () => {
|
|
121
|
+
const supportsMediaTypeSpy =
|
|
122
|
+
spyOn(shaka['util']['Platform'],
|
|
123
|
+
'supportsMediaType').and.returnValue(true);
|
|
124
|
+
mockDecodingConfig.type = 'file';
|
|
125
|
+
shaka.polyfill.MediaCapabilities.install();
|
|
126
|
+
navigator.mediaCapabilities.decodingInfo(mockDecodingConfig);
|
|
127
|
+
|
|
128
|
+
expect(supportsMediaTypeSpy).toHaveBeenCalledTimes(2);
|
|
129
|
+
expect(supportsMediaTypeSpy).toHaveBeenCalledWith(
|
|
130
|
+
mockDecodingConfig.video.contentType,
|
|
131
|
+
);
|
|
132
|
+
expect(supportsMediaTypeSpy).toHaveBeenCalledWith(
|
|
133
|
+
mockDecodingConfig.audio.contentType,
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should check MediaKeySystem when keySystemConfiguration is present',
|
|
138
|
+
async () => {
|
|
139
|
+
const mockResult = {mockKeySystemAccess: 'mockKeySystemAccess'};
|
|
140
|
+
spyOn(window['MediaSource'], 'isTypeSupported').and.returnValue(true);
|
|
141
|
+
const requestKeySystemAccessSpy =
|
|
142
|
+
spyOn(window['navigator'],
|
|
143
|
+
'requestMediaKeySystemAccess').and.returnValue(mockResult);
|
|
144
|
+
|
|
145
|
+
shaka.polyfill.MediaCapabilities.install();
|
|
146
|
+
const result = await navigator.mediaCapabilities
|
|
147
|
+
.decodingInfo(mockDecodingConfig);
|
|
148
|
+
|
|
149
|
+
expect(requestKeySystemAccessSpy).toHaveBeenCalledWith(
|
|
150
|
+
'com.widevine.alpha',
|
|
151
|
+
[{
|
|
152
|
+
audioCapabilities: [
|
|
153
|
+
{
|
|
154
|
+
robustness: 'SW_SECURE_CRYPTO',
|
|
155
|
+
contentType: 'audio/mp4; codecs="mp4a.40.2"',
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
distinctiveIdentifier: 'optional',
|
|
159
|
+
initDataTypes: ['cenc'],
|
|
160
|
+
persistentState: 'optional',
|
|
161
|
+
sessionTypes: ['temporary'],
|
|
162
|
+
videoCapabilities: [{
|
|
163
|
+
robustness: 'SW_SECURE_CRYPTO',
|
|
164
|
+
contentType: 'video/mp4; codecs="avc1.4D4015"',
|
|
165
|
+
}],
|
|
166
|
+
}],
|
|
167
|
+
);
|
|
168
|
+
expect(result.keySystemAccess).toEqual(mockResult);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('throws when the cast namespace is not available', async () => {
|
|
172
|
+
// Temporarily remove window.cast to trigger error. It's restored after
|
|
173
|
+
// every test.
|
|
174
|
+
delete window['cast'];
|
|
175
|
+
|
|
176
|
+
const isChromecastSpy =
|
|
177
|
+
spyOn(shaka['util']['Platform'],
|
|
178
|
+
'isChromecast').and.returnValue(true);
|
|
179
|
+
const expected = Util.jasmineError(new shaka.util.Error(
|
|
180
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
181
|
+
shaka.util.Error.Category.CAST,
|
|
182
|
+
shaka.util.Error.Code.CAST_API_UNAVAILABLE));
|
|
183
|
+
const isTypeSupportedSpy =
|
|
184
|
+
spyOn(window['MediaSource'], 'isTypeSupported').and.returnValue(true);
|
|
185
|
+
|
|
186
|
+
shaka.polyfill.MediaCapabilities.install();
|
|
187
|
+
await expectAsync(
|
|
188
|
+
navigator.mediaCapabilities.decodingInfo(mockDecodingConfig))
|
|
189
|
+
.toBeRejectedWith(expected);
|
|
190
|
+
|
|
191
|
+
expect(isTypeSupportedSpy).not.toHaveBeenCalled();
|
|
192
|
+
// 1 (during install()) + 1 (for video config check).
|
|
193
|
+
expect(isChromecastSpy).toHaveBeenCalledTimes(2);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('falls back to isTypeSupported() when canDisplayType() missing',
|
|
197
|
+
async () => {
|
|
198
|
+
// We only set the cast namespace, but not the canDisplayType() API.
|
|
199
|
+
window['cast'] = {};
|
|
200
|
+
const isChromecastSpy =
|
|
201
|
+
spyOn(shaka['util']['Platform'],
|
|
202
|
+
'isChromecast').and.returnValue(true);
|
|
203
|
+
const isTypeSupportedSpy =
|
|
204
|
+
spyOn(window['MediaSource'], 'isTypeSupported')
|
|
205
|
+
.and.returnValue(true);
|
|
206
|
+
|
|
207
|
+
shaka.polyfill.MediaCapabilities.install();
|
|
208
|
+
await navigator.mediaCapabilities.decodingInfo(mockDecodingConfig);
|
|
209
|
+
|
|
210
|
+
expect(mockCanDisplayType).not.toHaveBeenCalled();
|
|
211
|
+
// 1 (during install()) + 1 (for video config check).
|
|
212
|
+
expect(isChromecastSpy).toHaveBeenCalledTimes(2);
|
|
213
|
+
// 1 (fallback in canCastDisplayType()) +
|
|
214
|
+
// 1 (mockDecodingConfig.audio).
|
|
215
|
+
expect(isTypeSupportedSpy).toHaveBeenCalledTimes(2);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('should use cast.__platform__.canDisplayType for "supported" field ' +
|
|
219
|
+
'when platform is Cast', async () => {
|
|
220
|
+
// We're using quotes to access window.cast because the compiler
|
|
221
|
+
// knows about lots of Cast-specific APIs we aren't mocking. We
|
|
222
|
+
// don't need this mock strictly type-checked.
|
|
223
|
+
window['cast'] = {
|
|
224
|
+
__platform__: {canDisplayType: mockCanDisplayType},
|
|
225
|
+
};
|
|
226
|
+
const isChromecastSpy =
|
|
227
|
+
spyOn(shaka['util']['Platform'],
|
|
228
|
+
'isChromecast').and.returnValue(true);
|
|
229
|
+
const isTypeSupportedSpy =
|
|
230
|
+
spyOn(window['MediaSource'], 'isTypeSupported').and.returnValue(true);
|
|
231
|
+
|
|
232
|
+
// Tests an HDR stream's extended MIME type is correctly provided.
|
|
233
|
+
mockDecodingConfig.video.transferFunction = 'pq';
|
|
234
|
+
mockDecodingConfig.video.contentType =
|
|
235
|
+
'video/mp4; codecs="hev1.2.4.L153.B0"';
|
|
236
|
+
// Round to a whole number since we can't rely on number => string
|
|
237
|
+
// conversion precision on all devices.
|
|
238
|
+
mockDecodingConfig.video.framerate = 24;
|
|
239
|
+
mockCanDisplayType.and.callFake((type) => {
|
|
240
|
+
expect(type).toBe(
|
|
241
|
+
'video/mp4; ' +
|
|
242
|
+
'codecs="hev1.2.4.L153.B0"; ' +
|
|
243
|
+
'width=512; ' +
|
|
244
|
+
'height=288; ' +
|
|
245
|
+
'framerate=24; ' +
|
|
246
|
+
'eotf=smpte2084');
|
|
247
|
+
return true;
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
shaka.polyfill.MediaCapabilities.install();
|
|
251
|
+
await navigator.mediaCapabilities.decodingInfo(mockDecodingConfig);
|
|
252
|
+
|
|
253
|
+
// 1 (during install()) + 1 (for video config check).
|
|
254
|
+
expect(isChromecastSpy).toHaveBeenCalledTimes(2);
|
|
255
|
+
// 1 (mockDecodingConfig.audio).
|
|
256
|
+
expect(isTypeSupportedSpy).toHaveBeenCalledTimes(1);
|
|
257
|
+
// Called once in canCastDisplayType.
|
|
258
|
+
expect(mockCanDisplayType).toHaveBeenCalledTimes(1);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
});
|
|
@@ -339,6 +339,9 @@ shaka.test.FakePlayhead = class {
|
|
|
339
339
|
/** @private {number} */
|
|
340
340
|
this.stallsDetected_ = 0;
|
|
341
341
|
|
|
342
|
+
/** @type {!jasmine.Spy} */
|
|
343
|
+
this.ready = jasmine.createSpy('ready');
|
|
344
|
+
|
|
342
345
|
/** @type {!jasmine.Spy} */
|
|
343
346
|
this.setStartTime = jasmine.createSpy('setStartTime')
|
|
344
347
|
.and.callFake((value) => {
|