shaka-player 4.2.0 → 4.2.1
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/selenium-lab-tests.yaml +158 -53
- package/CHANGELOG.md +11 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/locales.js +32 -32
- package/dist/shaka-player.compiled.d.ts +0 -2
- package/dist/shaka-player.compiled.debug.d.ts +0 -2
- package/dist/shaka-player.compiled.debug.externs.js +0 -2
- package/dist/shaka-player.compiled.debug.js +55 -56
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +0 -2
- package/dist/shaka-player.compiled.js +372 -373
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +0 -2
- package/dist/shaka-player.ui.debug.d.ts +0 -2
- package/dist/shaka-player.ui.debug.externs.js +0 -2
- package/dist/shaka-player.ui.debug.js +57 -58
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +0 -2
- package/dist/shaka-player.ui.js +698 -700
- package/dist/shaka-player.ui.map +3 -3
- package/lib/hls/hls_parser.js +24 -74
- package/lib/player.js +13 -1
- package/lib/text/ui_text_displayer.js +8 -0
- package/lib/util/error.js +2 -10
- package/lib/util/player_configuration.js +1 -0
- package/package.json +1 -1
- package/test/hls/hls_parser_unit.js +52 -1
- package/test/media/drm_engine_unit.js +29 -0
- package/test/player_src_equals_integration.js +2 -0
- package/test/player_unit.js +39 -1
- package/test/test/assets/small.mp4 +0 -0
- package/ui/less/ad_controls.less +4 -0
package/lib/hls/hls_parser.js
CHANGED
|
@@ -180,10 +180,6 @@ shaka.hls.HlsParser = class {
|
|
|
180
180
|
*/
|
|
181
181
|
this.groupIdToClosedCaptionsMap_ = new Map();
|
|
182
182
|
|
|
183
|
-
/** True if some of the variants in the playlist is encrypted with AES-128.
|
|
184
|
-
* @private {boolean} */
|
|
185
|
-
this.aesEncrypted_ = false;
|
|
186
|
-
|
|
187
183
|
/** @private {Map.<string, string>} */
|
|
188
184
|
this.groupIdToCodecsMap_ = new Map();
|
|
189
185
|
|
|
@@ -576,7 +572,6 @@ shaka.hls.HlsParser = class {
|
|
|
576
572
|
playlist, uri, uri, codecs, type, language, primary, name,
|
|
577
573
|
channelsCount, closedCaptions, characteristics, forced, spatialAudio,
|
|
578
574
|
mimeType);
|
|
579
|
-
goog.asserts.assert(streamInfo != null, 'StreamInfo is null!');
|
|
580
575
|
this.uriToStreamInfosMap_.set(uri, streamInfo);
|
|
581
576
|
|
|
582
577
|
// Wrap the stream from that stream info with a variant.
|
|
@@ -654,17 +649,6 @@ shaka.hls.HlsParser = class {
|
|
|
654
649
|
this.syncStreamsWithProgramDateTime_();
|
|
655
650
|
}
|
|
656
651
|
|
|
657
|
-
if (this.aesEncrypted_ && variants.length == 0) {
|
|
658
|
-
// We do not support AES-128 encryption with HLS yet. Variants is null
|
|
659
|
-
// when the playlist is encrypted with AES-128.
|
|
660
|
-
shaka.log.info('No stream is created, because we don\'t support AES-128',
|
|
661
|
-
'encryption yet');
|
|
662
|
-
throw new shaka.util.Error(
|
|
663
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
664
|
-
shaka.util.Error.Category.MANIFEST,
|
|
665
|
-
shaka.util.Error.Code.HLS_AES_128_ENCRYPTION_NOT_SUPPORTED);
|
|
666
|
-
}
|
|
667
|
-
|
|
668
652
|
// Find the min and max timestamp of the earliest segment in all streams.
|
|
669
653
|
// Find the minimum duration of all streams as well.
|
|
670
654
|
let minDuration = Infinity;
|
|
@@ -863,8 +847,6 @@ shaka.hls.HlsParser = class {
|
|
|
863
847
|
}
|
|
864
848
|
try {
|
|
865
849
|
const streamInfo = await this.createStreamInfoFromMediaTag_(tag);
|
|
866
|
-
goog.asserts.assert(
|
|
867
|
-
streamInfo, 'Should always have a streamInfo for text');
|
|
868
850
|
return streamInfo.stream;
|
|
869
851
|
} catch (e) {
|
|
870
852
|
if (this.config_.hls.ignoreTextStreamFailures) {
|
|
@@ -907,8 +889,6 @@ shaka.hls.HlsParser = class {
|
|
|
907
889
|
}
|
|
908
890
|
try {
|
|
909
891
|
const streamInfo = await this.createStreamInfoFromImageTag_(tag);
|
|
910
|
-
goog.asserts.assert(
|
|
911
|
-
streamInfo, 'Should always have a streamInfo for image');
|
|
912
892
|
return streamInfo.stream;
|
|
913
893
|
} catch (e) {
|
|
914
894
|
if (this.config_.hls.ignoreImageStreamFailures) {
|
|
@@ -960,22 +940,17 @@ shaka.hls.HlsParser = class {
|
|
|
960
940
|
const streamInfos = await this.createStreamInfosForVariantTag_(tag,
|
|
961
941
|
resolution, frameRate);
|
|
962
942
|
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
videoRange);
|
|
975
|
-
}
|
|
976
|
-
// We do not support AES-128 encryption with HLS yet. If the streamInfos
|
|
977
|
-
// is null because of AES-128 encryption, do not create variants for that.
|
|
978
|
-
return [];
|
|
943
|
+
goog.asserts.assert(streamInfos.audio.length ||
|
|
944
|
+
streamInfos.video.length, 'We should have created a stream!');
|
|
945
|
+
|
|
946
|
+
return this.createVariants_(
|
|
947
|
+
streamInfos.audio,
|
|
948
|
+
streamInfos.video,
|
|
949
|
+
bandwidth,
|
|
950
|
+
width,
|
|
951
|
+
height,
|
|
952
|
+
frameRate,
|
|
953
|
+
videoRange);
|
|
979
954
|
});
|
|
980
955
|
|
|
981
956
|
const allVariants = await Promise.all(variantsPromises);
|
|
@@ -992,7 +967,7 @@ shaka.hls.HlsParser = class {
|
|
|
992
967
|
* @param {!shaka.hls.Tag} tag
|
|
993
968
|
* @param {?string} resolution
|
|
994
969
|
* @param {?string} frameRate
|
|
995
|
-
* @return {!Promise
|
|
970
|
+
* @return {!Promise.<!shaka.hls.HlsParser.StreamInfos>}
|
|
996
971
|
* @private
|
|
997
972
|
*/
|
|
998
973
|
async createStreamInfosForVariantTag_(tag, resolution, frameRate) {
|
|
@@ -1062,17 +1037,10 @@ shaka.hls.HlsParser = class {
|
|
|
1062
1037
|
type = ContentType.VIDEO;
|
|
1063
1038
|
}
|
|
1064
1039
|
|
|
1065
|
-
let streamInfo;
|
|
1066
1040
|
if (!ignoreStream) {
|
|
1067
|
-
streamInfo =
|
|
1041
|
+
const streamInfo =
|
|
1068
1042
|
await this.createStreamInfoFromVariantTag_(tag, allCodecs, type);
|
|
1069
|
-
}
|
|
1070
|
-
if (streamInfo) {
|
|
1071
1043
|
res[streamInfo.stream.type] = [streamInfo];
|
|
1072
|
-
} else if (streamInfo === null) {
|
|
1073
|
-
// Triple-equals for undefined.
|
|
1074
|
-
shaka.log.debug('streamInfo is null');
|
|
1075
|
-
return null;
|
|
1076
1044
|
}
|
|
1077
1045
|
this.filterLegacyCodecs_(res);
|
|
1078
1046
|
return res;
|
|
@@ -1364,7 +1332,7 @@ shaka.hls.HlsParser = class {
|
|
|
1364
1332
|
* Parse EXT-X-MEDIA media tag into a Stream object.
|
|
1365
1333
|
*
|
|
1366
1334
|
* @param {shaka.hls.Tag} tag
|
|
1367
|
-
* @return {!Promise
|
|
1335
|
+
* @return {!Promise.<!shaka.hls.HlsParser.StreamInfo>}
|
|
1368
1336
|
* @private
|
|
1369
1337
|
*/
|
|
1370
1338
|
async createStreamInfoFromMediaTag_(tag) {
|
|
@@ -1418,9 +1386,6 @@ shaka.hls.HlsParser = class {
|
|
|
1418
1386
|
} else {
|
|
1419
1387
|
this.groupIdToStreamInfosMap_.set(groupId, [streamInfo]);
|
|
1420
1388
|
}
|
|
1421
|
-
if (streamInfo == null) {
|
|
1422
|
-
return null;
|
|
1423
|
-
}
|
|
1424
1389
|
|
|
1425
1390
|
// TODO: This check is necessary because of the possibility of multiple
|
|
1426
1391
|
// calls to createStreamInfoFromMediaTag_ before either has resolved.
|
|
@@ -1435,7 +1400,7 @@ shaka.hls.HlsParser = class {
|
|
|
1435
1400
|
* Parse EXT-X-MEDIA media tag into a Stream object.
|
|
1436
1401
|
*
|
|
1437
1402
|
* @param {shaka.hls.Tag} tag
|
|
1438
|
-
* @return {!Promise
|
|
1403
|
+
* @return {!Promise.<!shaka.hls.HlsParser.StreamInfo>}
|
|
1439
1404
|
* @private
|
|
1440
1405
|
*/
|
|
1441
1406
|
async createStreamInfoFromImageTag_(tag) {
|
|
@@ -1463,9 +1428,6 @@ shaka.hls.HlsParser = class {
|
|
|
1463
1428
|
verbatimImagePlaylistUri, codecs, type, language, /* primary= */ false,
|
|
1464
1429
|
name, /* channelsCount= */ null, /* closedCaptions= */ null,
|
|
1465
1430
|
characteristics, /* forced= */ false, /* spatialAudio= */ false);
|
|
1466
|
-
if (streamInfo == null) {
|
|
1467
|
-
return null;
|
|
1468
|
-
}
|
|
1469
1431
|
|
|
1470
1432
|
// TODO: This check is necessary because of the possibility of multiple
|
|
1471
1433
|
// calls to createStreamInfoFromImageTag_ before either has resolved.
|
|
@@ -1506,7 +1468,7 @@ shaka.hls.HlsParser = class {
|
|
|
1506
1468
|
* @param {!shaka.hls.Tag} tag
|
|
1507
1469
|
* @param {!Array.<string>} allCodecs
|
|
1508
1470
|
* @param {string} type
|
|
1509
|
-
* @return {!Promise
|
|
1471
|
+
* @return {!Promise.<!shaka.hls.HlsParser.StreamInfo>}
|
|
1510
1472
|
* @private
|
|
1511
1473
|
*/
|
|
1512
1474
|
async createStreamInfoFromVariantTag_(tag, allCodecs, type) {
|
|
@@ -1526,9 +1488,6 @@ shaka.hls.HlsParser = class {
|
|
|
1526
1488
|
/* name= */ null, /* channelcount= */ null, closedCaptions,
|
|
1527
1489
|
/* characteristics= */ null, /* forced= */ false,
|
|
1528
1490
|
/* spatialAudio= */ false);
|
|
1529
|
-
if (streamInfo == null) {
|
|
1530
|
-
return null;
|
|
1531
|
-
}
|
|
1532
1491
|
// TODO: This check is necessary because of the possibility of multiple
|
|
1533
1492
|
// calls to createStreamInfoFromVariantTag_ before either has resolved.
|
|
1534
1493
|
if (this.uriToStreamInfosMap_.has(verbatimMediaPlaylistUri)) {
|
|
@@ -1552,7 +1511,7 @@ shaka.hls.HlsParser = class {
|
|
|
1552
1511
|
* @param {?string} characteristics
|
|
1553
1512
|
* @param {boolean} forced
|
|
1554
1513
|
* @param {boolean} spatialAudio
|
|
1555
|
-
* @return {!Promise
|
|
1514
|
+
* @return {!Promise.<!shaka.hls.HlsParser.StreamInfo>}
|
|
1556
1515
|
* @private
|
|
1557
1516
|
*/
|
|
1558
1517
|
async createStreamInfo_(verbatimMediaPlaylistUri, codecs, type, language,
|
|
@@ -1592,7 +1551,7 @@ shaka.hls.HlsParser = class {
|
|
|
1592
1551
|
* @param {boolean} forced
|
|
1593
1552
|
* @param {boolean} spatialAudio
|
|
1594
1553
|
* @param {(string|undefined)} mimeType
|
|
1595
|
-
* @return {!Promise
|
|
1554
|
+
* @return {!Promise.<!shaka.hls.HlsParser.StreamInfo>}
|
|
1596
1555
|
* @private
|
|
1597
1556
|
*/
|
|
1598
1557
|
async convertParsedPlaylistIntoStreamInfo_(playlist, verbatimMediaPlaylistUri,
|
|
@@ -1635,6 +1594,8 @@ shaka.hls.HlsParser = class {
|
|
|
1635
1594
|
}
|
|
1636
1595
|
|
|
1637
1596
|
let encrypted = false;
|
|
1597
|
+
let aesEncrypted = false;
|
|
1598
|
+
|
|
1638
1599
|
/** @type {!Array.<shaka.extern.DrmInfo>}*/
|
|
1639
1600
|
const drmInfos = [];
|
|
1640
1601
|
const keyIds = new Set();
|
|
@@ -1647,7 +1608,7 @@ shaka.hls.HlsParser = class {
|
|
|
1647
1608
|
|
|
1648
1609
|
if (method == 'AES-128') {
|
|
1649
1610
|
// These keys are handled separately.
|
|
1650
|
-
|
|
1611
|
+
aesEncrypted = true;
|
|
1651
1612
|
} else {
|
|
1652
1613
|
const keyFormat = drmTag.getRequiredAttrValue('KEYFORMAT');
|
|
1653
1614
|
const drmParser =
|
|
@@ -1668,7 +1629,7 @@ shaka.hls.HlsParser = class {
|
|
|
1668
1629
|
}
|
|
1669
1630
|
}
|
|
1670
1631
|
|
|
1671
|
-
if (encrypted && !drmInfos.length && !
|
|
1632
|
+
if (encrypted && !drmInfos.length && !aesEncrypted) {
|
|
1672
1633
|
throw new shaka.util.Error(
|
|
1673
1634
|
shaka.util.Error.Severity.CRITICAL,
|
|
1674
1635
|
shaka.util.Error.Category.MANIFEST,
|
|
@@ -1683,19 +1644,8 @@ shaka.hls.HlsParser = class {
|
|
|
1683
1644
|
/** @type {!Map.<number, number>} */
|
|
1684
1645
|
const mediaSequenceToStartTime = new Map();
|
|
1685
1646
|
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
segments = this.createSegments_(verbatimMediaPlaylistUri, playlist, type,
|
|
1689
|
-
mimeType, mediaSequenceToStartTime, mediaVariables, codecs);
|
|
1690
|
-
} catch (error) {
|
|
1691
|
-
if (error.code == shaka.util.Error.Code.HLS_INTERNAL_SKIP_STREAM) {
|
|
1692
|
-
shaka.log.alwaysWarn('Skipping unsupported HLS stream',
|
|
1693
|
-
mimeType, verbatimMediaPlaylistUri);
|
|
1694
|
-
return null;
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
throw error;
|
|
1698
|
-
}
|
|
1647
|
+
const segments = this.createSegments_(verbatimMediaPlaylistUri, playlist,
|
|
1648
|
+
type, mimeType, mediaSequenceToStartTime, mediaVariables, codecs);
|
|
1699
1649
|
|
|
1700
1650
|
const lastEndTime = segments[segments.length - 1].endTime;
|
|
1701
1651
|
/** @type {!shaka.media.SegmentIndex} */
|
package/lib/player.js
CHANGED
|
@@ -4459,6 +4459,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4459
4459
|
this.stats_.setBandwidthEstimate(estimate);
|
|
4460
4460
|
}
|
|
4461
4461
|
|
|
4462
|
+
if (this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS) {
|
|
4463
|
+
this.stats_.setResolution(
|
|
4464
|
+
/* width= */ element.videoWidth || NaN,
|
|
4465
|
+
/* height= */ element.videoHeight || NaN);
|
|
4466
|
+
}
|
|
4467
|
+
|
|
4462
4468
|
return this.stats_.getBlob();
|
|
4463
4469
|
}
|
|
4464
4470
|
|
|
@@ -5625,6 +5631,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5625
5631
|
return false;
|
|
5626
5632
|
}
|
|
5627
5633
|
|
|
5634
|
+
if (!navigator.onLine) {
|
|
5635
|
+
// Don't restrict variants if we're completely offline, or else we end up
|
|
5636
|
+
// rapidly restricting all of them.
|
|
5637
|
+
return false;
|
|
5638
|
+
}
|
|
5639
|
+
|
|
5628
5640
|
let maxDisabledTime = this.config_.streaming.maxDisabledTime;
|
|
5629
5641
|
if (maxDisabledTime == 0) {
|
|
5630
5642
|
if (error.code == shaka.util.Error.Code.SEGMENT_MISSING) {
|
|
@@ -6558,7 +6570,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6558
6570
|
* @define {string} A version number taken from git at compile time.
|
|
6559
6571
|
* @export
|
|
6560
6572
|
*/
|
|
6561
|
-
shaka.Player.version = 'v4.2.
|
|
6573
|
+
shaka.Player.version = 'v4.2.1-uncompiled';
|
|
6562
6574
|
|
|
6563
6575
|
// Initialize the deprecation system using the version string we just set
|
|
6564
6576
|
// on the player.
|
|
@@ -493,6 +493,14 @@ shaka.text.UITextDisplayer = class {
|
|
|
493
493
|
style.backgroundRepeat = 'no-repeat';
|
|
494
494
|
style.backgroundSize = 'contain';
|
|
495
495
|
style.backgroundPosition = 'center';
|
|
496
|
+
|
|
497
|
+
// Quoting https://www.w3.org/TR/ttml-imsc1.2/:
|
|
498
|
+
// "The width and height (in pixels) of the image resource referenced by
|
|
499
|
+
// smpte:backgroundImage SHALL be equal to the width and height expressed
|
|
500
|
+
// by the tts:extent attribute of the region in which the div element is
|
|
501
|
+
// presented".
|
|
502
|
+
style.width = '100%';
|
|
503
|
+
style.height = '100%';
|
|
496
504
|
} else {
|
|
497
505
|
// If we have both text and nested cues, then style everything; otherwise
|
|
498
506
|
// place the text in its own <span> so the background doesn't fill the
|
package/lib/util/error.js
CHANGED
|
@@ -656,16 +656,8 @@ shaka.util.Error.Code = {
|
|
|
656
656
|
*/
|
|
657
657
|
'CANNOT_ADD_EXTERNAL_TEXT_TO_LIVE_STREAM': 4033,
|
|
658
658
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
*/
|
|
662
|
-
'HLS_AES_128_ENCRYPTION_NOT_SUPPORTED': 4034,
|
|
663
|
-
|
|
664
|
-
/**
|
|
665
|
-
* An internal error code that should never be seen by applications, thrown
|
|
666
|
-
* to force the HLS parser to skip an unsupported stream.
|
|
667
|
-
*/
|
|
668
|
-
'HLS_INTERNAL_SKIP_STREAM': 4035,
|
|
659
|
+
// RETIRED: 'HLS_AES_128_ENCRYPTION_NOT_SUPPORTED': 4034,
|
|
660
|
+
// RETIRED: 'HLS_INTERNAL_SKIP_STREAM': 4035,
|
|
669
661
|
|
|
670
662
|
/** The Manifest contained no Variants. */
|
|
671
663
|
'NO_VARIANTS': 4036,
|
package/package.json
CHANGED
|
@@ -2537,9 +2537,60 @@ describe('HlsParser', () => {
|
|
|
2537
2537
|
|
|
2538
2538
|
const actual = await parser.start('test:/master', playerInterface);
|
|
2539
2539
|
expect(actual).toEqual(manifest);
|
|
2540
|
-
return actual;
|
|
2541
2540
|
});
|
|
2542
2541
|
|
|
2542
|
+
it('fails on AES-128 if WebCrypto APIs are not available', async () => {
|
|
2543
|
+
const master = [
|
|
2544
|
+
'#EXTM3U\n',
|
|
2545
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
2546
|
+
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1"\n',
|
|
2547
|
+
'video\n',
|
|
2548
|
+
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
|
|
2549
|
+
'URI="audio"\n',
|
|
2550
|
+
].join('');
|
|
2551
|
+
|
|
2552
|
+
const mediaWithMp4AesEncryption = [
|
|
2553
|
+
'#EXTM3U\n',
|
|
2554
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2555
|
+
'#EXT-X-KEY:METHOD=AES-128,',
|
|
2556
|
+
'URI="800k.key"\n',
|
|
2557
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
2558
|
+
'#EXTINF:5,\n',
|
|
2559
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
2560
|
+
'main.mp4',
|
|
2561
|
+
].join('');
|
|
2562
|
+
|
|
2563
|
+
fakeNetEngine
|
|
2564
|
+
.setResponseText('test:/master', master)
|
|
2565
|
+
.setResponseText('test:/audio', mediaWithMp4AesEncryption)
|
|
2566
|
+
.setResponseText('test:/video', mediaWithMp4AesEncryption)
|
|
2567
|
+
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
2568
|
+
.setResponseValue('test:/main.mp4', segmentData)
|
|
2569
|
+
.setResponseValue('test:/800k.key', aes128Key);
|
|
2570
|
+
|
|
2571
|
+
let originalWebCrypto = null;
|
|
2572
|
+
try {
|
|
2573
|
+
originalWebCrypto = window.crypto;
|
|
2574
|
+
Object.defineProperty(window, 'crypto', {
|
|
2575
|
+
configurable: true,
|
|
2576
|
+
value: null,
|
|
2577
|
+
});
|
|
2578
|
+
|
|
2579
|
+
const expectedError = shaka.test.Util.jasmineError(new shaka.util.Error(
|
|
2580
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
2581
|
+
shaka.util.Error.Category.MANIFEST,
|
|
2582
|
+
shaka.util.Error.Code.NO_WEB_CRYPTO_API));
|
|
2583
|
+
await expectAsync(parser.start('test:/master', playerInterface))
|
|
2584
|
+
.toBeRejectedWith(expectedError);
|
|
2585
|
+
} finally {
|
|
2586
|
+
Object.defineProperty(window, 'crypto', {
|
|
2587
|
+
configurable: true,
|
|
2588
|
+
value: originalWebCrypto,
|
|
2589
|
+
});
|
|
2590
|
+
}
|
|
2591
|
+
});
|
|
2592
|
+
|
|
2593
|
+
|
|
2543
2594
|
it('constructs DrmInfo for Widevine', async () => {
|
|
2544
2595
|
const master = [
|
|
2545
2596
|
'#EXTM3U\n',
|
|
@@ -677,6 +677,35 @@ describe('DrmEngine', () => {
|
|
|
677
677
|
.toBeRejectedWith(expected);
|
|
678
678
|
});
|
|
679
679
|
|
|
680
|
+
it('uses key system IDs from keySystemsMapping config', async () => {
|
|
681
|
+
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
682
|
+
manifest.addVariant(0, (variant) => {
|
|
683
|
+
variant.addVideo(1, (stream) => {
|
|
684
|
+
stream.encrypted = true;
|
|
685
|
+
stream.addDrmInfo('drm.abc');
|
|
686
|
+
});
|
|
687
|
+
});
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
setDecodingInfoSpy([]);
|
|
691
|
+
|
|
692
|
+
config.keySystemsMapping['drm.abc'] = 'drm.def';
|
|
693
|
+
drmEngine.configure(config);
|
|
694
|
+
|
|
695
|
+
const variants = manifest.variants;
|
|
696
|
+
await expectAsync(
|
|
697
|
+
drmEngine.initForPlayback(variants, manifest.offlineSessionIds))
|
|
698
|
+
.toBeRejected();
|
|
699
|
+
|
|
700
|
+
expect(drmEngine.initialized()).toBe(false);
|
|
701
|
+
expect(decodingInfoSpy).toHaveBeenCalledTimes(1);
|
|
702
|
+
expect(decodingInfoSpy).toHaveBeenCalledWith(containing({
|
|
703
|
+
keySystemConfiguration: containing({
|
|
704
|
+
keySystem: 'drm.def',
|
|
705
|
+
}),
|
|
706
|
+
}));
|
|
707
|
+
});
|
|
708
|
+
|
|
680
709
|
it('maps TS MIME types through the transmuxer', async () => {
|
|
681
710
|
const originalIsSupported = shaka.media.Transmuxer.isSupported;
|
|
682
711
|
|
|
@@ -305,6 +305,8 @@ describe('Player Src Equals', () => {
|
|
|
305
305
|
expect(stats.loadLatency).toBeGreaterThan(0);
|
|
306
306
|
expect(stats.manifestTimeSeconds).toBeNaN(); // There's no manifest.
|
|
307
307
|
expect(stats.drmTimeSeconds).toBeNaN(); // There's no DRM.
|
|
308
|
+
expect(stats.height).toBe(110);
|
|
309
|
+
expect(stats.width).toBe(256);
|
|
308
310
|
});
|
|
309
311
|
|
|
310
312
|
it('plays with external text tracks', async () => {
|
package/test/player_unit.js
CHANGED
|
@@ -422,7 +422,6 @@ describe('Player', () => {
|
|
|
422
422
|
dispatchEventSpy.calls.reset();
|
|
423
423
|
player.configure({streaming: {maxDisabledTime}});
|
|
424
424
|
player.setMaxHardwareResolution(123, 456);
|
|
425
|
-
onErrorCallback(httpError);
|
|
426
425
|
});
|
|
427
426
|
|
|
428
427
|
afterEach(() => {
|
|
@@ -434,14 +433,18 @@ describe('Player', () => {
|
|
|
434
433
|
});
|
|
435
434
|
|
|
436
435
|
it('handles HTTP_ERROR', () => {
|
|
436
|
+
onErrorCallback(httpError);
|
|
437
437
|
expect(httpError.handled).toBeTruthy();
|
|
438
438
|
});
|
|
439
439
|
|
|
440
440
|
it('does not dispatch any error', () => {
|
|
441
|
+
onErrorCallback(httpError);
|
|
441
442
|
expect(dispatchEventSpy).not.toHaveBeenCalled();
|
|
442
443
|
});
|
|
443
444
|
|
|
444
445
|
it('disables the current variant and applies restrictions', () => {
|
|
446
|
+
onErrorCallback(httpError);
|
|
447
|
+
|
|
445
448
|
const foundDisabledVariant =
|
|
446
449
|
manifest.variants.some(({disabledUntilTime}) =>
|
|
447
450
|
disabledUntilTime == currentTime + maxDisabledTime);
|
|
@@ -453,11 +456,46 @@ describe('Player', () => {
|
|
|
453
456
|
});
|
|
454
457
|
|
|
455
458
|
it('switches the variant', () => {
|
|
459
|
+
onErrorCallback(httpError);
|
|
460
|
+
|
|
456
461
|
expect(chooseVariantSpy).toHaveBeenCalled();
|
|
457
462
|
expect(getBufferedInfoSpy).toHaveBeenCalled();
|
|
458
463
|
expect(switchVariantSpy)
|
|
459
464
|
.toHaveBeenCalledWith(chosenVariant, false, true, 14);
|
|
460
465
|
});
|
|
466
|
+
|
|
467
|
+
describe('but browser is truly offline', () => {
|
|
468
|
+
/** @type {!Object} */
|
|
469
|
+
let navigatorOnLineDescriptor;
|
|
470
|
+
|
|
471
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
472
|
+
const navigatorPrototype = Navigator.prototype;
|
|
473
|
+
|
|
474
|
+
beforeAll(() => {
|
|
475
|
+
navigatorOnLineDescriptor =
|
|
476
|
+
/** @type {!Object} */(Object.getOwnPropertyDescriptor(
|
|
477
|
+
navigatorPrototype, 'onLine'));
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
beforeEach(() => {
|
|
481
|
+
// Redefine the property, replacing only the getter.
|
|
482
|
+
Object.defineProperty(navigatorPrototype, 'onLine',
|
|
483
|
+
Object.assign(navigatorOnLineDescriptor, {
|
|
484
|
+
get: () => false,
|
|
485
|
+
}));
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
afterEach(() => {
|
|
489
|
+
// Restore the original property definition.
|
|
490
|
+
Object.defineProperty(
|
|
491
|
+
navigatorPrototype, 'onLine', navigatorOnLineDescriptor);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
it('does not handle HTTP_ERROR', () => {
|
|
495
|
+
onErrorCallback(httpError);
|
|
496
|
+
expect(httpError.handled).toBe(false);
|
|
497
|
+
});
|
|
498
|
+
});
|
|
461
499
|
});
|
|
462
500
|
});
|
|
463
501
|
});
|
|
Binary file
|
package/ui/less/ad_controls.less
CHANGED
|
@@ -71,6 +71,10 @@
|
|
|
71
71
|
.ad-text-shadow();
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
.shaka-ad-controls .shaka-ad-position:not(.shaka-hidden) + .shaka-ad-counter {
|
|
75
|
+
margin-left: 0.75em;
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
.shaka-skip-ad-container {
|
|
75
79
|
/* Skip button is positioned at the very right edge of the
|
|
76
80
|
* video container unlike the rest of the bottom controls. */
|