shaka-player 3.3.14 → 3.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/build-and-test.yaml +13 -0
- package/AUTHORS +1 -0
- package/CHANGELOG.md +20 -0
- package/CONTRIBUTORS +1 -0
- package/dist/locales.js +32 -32
- package/dist/shaka-player.compiled.debug.js +79 -77
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +247 -247
- package/dist/shaka-player.compiled.map +2 -2
- package/dist/shaka-player.ui.debug.js +93 -91
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +262 -261
- package/dist/shaka-player.ui.map +3 -3
- package/lib/ads/ad_manager.js +2 -2
- package/lib/media/streaming_engine.js +20 -8
- package/lib/player.js +17 -2
- package/lib/text/ui_text_displayer.js +24 -4
- package/lib/text/web_vtt_generator.js +21 -9
- package/lib/util/dom_utils.js +3 -1
- package/lib/util/stream_utils.js +6 -0
- package/lib/util/timer.js +17 -0
- package/package.json +1 -1
- package/test/player_integration.js +37 -3
- package/test/player_unit.js +4 -2
- package/test/test/boot.js +29 -11
- package/test/test/util/test_scheme.js +2 -2
- package/test/text/ui_text_displayer_unit.js +70 -0
package/lib/ads/ad_manager.js
CHANGED
|
@@ -19,8 +19,8 @@ goog.require('shaka.util.IReleasable');
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* @event shaka.ads.AdManager.
|
|
23
|
-
* @description Fired when
|
|
22
|
+
* @event shaka.ads.AdManager.AdsLoadedEvent
|
|
23
|
+
* @description Fired when a sequence of ads has been loaded.
|
|
24
24
|
* @property {string} type
|
|
25
25
|
* 'ads-loaded'
|
|
26
26
|
* @property {number} loadTime
|
|
@@ -603,6 +603,11 @@ shaka.media.StreamingEngine = class {
|
|
|
603
603
|
* within the presentation timeline.
|
|
604
604
|
*/
|
|
605
605
|
seeked() {
|
|
606
|
+
if (!this.playerInterface_) {
|
|
607
|
+
// Already destroyed.
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
|
|
606
611
|
const presentationTime = this.playerInterface_.getPresentationTime();
|
|
607
612
|
const smallGapLimit = this.config_.smallGapLimit;
|
|
608
613
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
@@ -657,7 +662,7 @@ shaka.media.StreamingEngine = class {
|
|
|
657
662
|
|
|
658
663
|
/**
|
|
659
664
|
* Clear the buffer for a given stream. Unlike clearBuffer_, this will handle
|
|
660
|
-
* cases where a MediaState is performing an update. After this runs,
|
|
665
|
+
* cases where a MediaState is performing an update. After this runs, the
|
|
661
666
|
* MediaState will have a pending update.
|
|
662
667
|
* @param {!shaka.media.StreamingEngine.MediaState_} mediaState
|
|
663
668
|
* @private
|
|
@@ -772,9 +777,9 @@ shaka.media.StreamingEngine = class {
|
|
|
772
777
|
for (const type of streamsByType.keys()) {
|
|
773
778
|
const stream = streamsByType.get(type);
|
|
774
779
|
if (!this.mediaStates_.has(type)) {
|
|
775
|
-
const
|
|
776
|
-
this.mediaStates_.set(type,
|
|
777
|
-
this.scheduleUpdate_(
|
|
780
|
+
const mediaState = this.createMediaState_(stream);
|
|
781
|
+
this.mediaStates_.set(type, mediaState);
|
|
782
|
+
this.scheduleUpdate_(mediaState, 0);
|
|
778
783
|
}
|
|
779
784
|
}
|
|
780
785
|
}
|
|
@@ -884,7 +889,7 @@ shaka.media.StreamingEngine = class {
|
|
|
884
889
|
'mediastate.stream should not have segmentIndex yet.');
|
|
885
890
|
thisStream.closeSegmentIndex();
|
|
886
891
|
}
|
|
887
|
-
if (mediaState.
|
|
892
|
+
if (!mediaState.performingUpdate && !mediaState.updateTimer) {
|
|
888
893
|
this.scheduleUpdate_(mediaState, 0);
|
|
889
894
|
}
|
|
890
895
|
return;
|
|
@@ -1352,7 +1357,7 @@ shaka.media.StreamingEngine = class {
|
|
|
1352
1357
|
// If the network slows down, abort the current fetch request and start
|
|
1353
1358
|
// a new one, and ignore the error message.
|
|
1354
1359
|
mediaState.performingUpdate = false;
|
|
1355
|
-
mediaState
|
|
1360
|
+
this.cancelUpdate_(mediaState);
|
|
1356
1361
|
this.scheduleUpdate_(mediaState, 0);
|
|
1357
1362
|
} else if (mediaState.type == ContentType.TEXT &&
|
|
1358
1363
|
this.config_.ignoreTextStreamFailures) {
|
|
@@ -1397,7 +1402,10 @@ shaka.media.StreamingEngine = class {
|
|
|
1397
1402
|
|
|
1398
1403
|
for (const mediaState of this.mediaStates_.values()) {
|
|
1399
1404
|
const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState);
|
|
1400
|
-
if
|
|
1405
|
+
// Only schedule an update if it has an error, but it's not mid-update
|
|
1406
|
+
// and there is not already an update scheduled.
|
|
1407
|
+
if (mediaState.hasError && !mediaState.performingUpdate &&
|
|
1408
|
+
!mediaState.updateTimer) {
|
|
1401
1409
|
shaka.log.info(logPrefix, 'Retrying after failure...');
|
|
1402
1410
|
mediaState.hasError = false;
|
|
1403
1411
|
this.scheduleUpdate_(mediaState, delaySeconds);
|
|
@@ -1880,7 +1888,11 @@ shaka.media.StreamingEngine = class {
|
|
|
1880
1888
|
shaka.log.debug(logPrefix, 'cleared buffer');
|
|
1881
1889
|
mediaState.clearingBuffer = false;
|
|
1882
1890
|
mediaState.endOfStream = false;
|
|
1883
|
-
|
|
1891
|
+
// Since the clear operation was async, check to make sure we're not doing
|
|
1892
|
+
// another update and we don't have one scheduled yet.
|
|
1893
|
+
if (!mediaState.performingUpdate && !mediaState.updateTimer) {
|
|
1894
|
+
this.scheduleUpdate_(mediaState, 0);
|
|
1895
|
+
}
|
|
1884
1896
|
}
|
|
1885
1897
|
|
|
1886
1898
|
|
package/lib/player.js
CHANGED
|
@@ -1419,6 +1419,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1419
1419
|
has.startTime = null;
|
|
1420
1420
|
has.uri = null;
|
|
1421
1421
|
|
|
1422
|
+
// Release the region timeline, which is created when parsing the manifest.
|
|
1423
|
+
if (this.regionTimeline_) {
|
|
1424
|
+
this.regionTimeline_.release();
|
|
1425
|
+
this.regionTimeline_ = null;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1422
1428
|
// In most cases we should have a media element. The one exception would
|
|
1423
1429
|
// be if there was an error and we, by chance, did not have a media element.
|
|
1424
1430
|
if (has.mediaElement) {
|
|
@@ -4116,16 +4122,25 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4116
4122
|
return [];
|
|
4117
4123
|
}
|
|
4118
4124
|
const chapters = [];
|
|
4125
|
+
const uniqueChapters = new Set();
|
|
4119
4126
|
for (const chaptersTrack of chaptersTracksWithLanguage) {
|
|
4120
4127
|
if (chaptersTrack && chaptersTrack.cues) {
|
|
4121
4128
|
for (const cue of chaptersTrack.cues) {
|
|
4129
|
+
let id = cue.id;
|
|
4130
|
+
if (!id || id == '') {
|
|
4131
|
+
id = cue.startTime + '-' + cue.endTime + '-' + cue.text;
|
|
4132
|
+
}
|
|
4122
4133
|
/** @type {shaka.extern.Chapter} */
|
|
4123
4134
|
const chapter = {
|
|
4135
|
+
id: id,
|
|
4124
4136
|
title: cue.text,
|
|
4125
4137
|
startTime: cue.startTime,
|
|
4126
4138
|
endTime: cue.endTime,
|
|
4127
4139
|
};
|
|
4128
|
-
|
|
4140
|
+
if (!uniqueChapters.has(id)) {
|
|
4141
|
+
chapters.push(chapter);
|
|
4142
|
+
uniqueChapters.add(id);
|
|
4143
|
+
}
|
|
4129
4144
|
}
|
|
4130
4145
|
}
|
|
4131
4146
|
}
|
|
@@ -6648,7 +6663,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6648
6663
|
* @define {string} A version number taken from git at compile time.
|
|
6649
6664
|
* @export
|
|
6650
6665
|
*/
|
|
6651
|
-
shaka.Player.version = 'v3.3.
|
|
6666
|
+
shaka.Player.version = 'v3.3.16-uncompiled';
|
|
6652
6667
|
|
|
6653
6668
|
// Initialize the deprecation system using the version string we just set
|
|
6654
6669
|
// on the player.
|
|
@@ -372,6 +372,25 @@ shaka.text.UITextDisplayer = class {
|
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Compute a unique internal id:
|
|
377
|
+
* Regions can reuse the id but have different dimensions, we need to
|
|
378
|
+
* consider those differences
|
|
379
|
+
* @param {shaka.extern.CueRegion} region
|
|
380
|
+
* @private
|
|
381
|
+
*/
|
|
382
|
+
generateRegionId_(region) {
|
|
383
|
+
const percentageUnit = shaka.text.CueRegion.units.PERCENTAGE;
|
|
384
|
+
const heightUnit = region.heightUnits == percentageUnit ? '%' : 'px';
|
|
385
|
+
const viewportAnchorUnit =
|
|
386
|
+
region.viewportAnchorUnits == percentageUnit ? '%' : 'px';
|
|
387
|
+
const uniqueRegionId = `${region.id}_${
|
|
388
|
+
region.width}x${region.height}${heightUnit}-${
|
|
389
|
+
region.viewportAnchorX}x${region.viewportAnchorY}${viewportAnchorUnit}`;
|
|
390
|
+
|
|
391
|
+
return uniqueRegionId;
|
|
392
|
+
}
|
|
393
|
+
|
|
375
394
|
/**
|
|
376
395
|
* Get or create a region element corresponding to the cue region. These are
|
|
377
396
|
* cached by ID.
|
|
@@ -383,8 +402,9 @@ shaka.text.UITextDisplayer = class {
|
|
|
383
402
|
getRegionElement_(cue) {
|
|
384
403
|
const region = cue.region;
|
|
385
404
|
|
|
386
|
-
|
|
387
|
-
|
|
405
|
+
const regionId = this.generateRegionId_(region);
|
|
406
|
+
if (this.regionElements_.has(regionId)) {
|
|
407
|
+
return this.regionElements_.get(regionId);
|
|
388
408
|
}
|
|
389
409
|
|
|
390
410
|
const regionElement = shaka.util.Dom.createHTMLElement('span');
|
|
@@ -395,7 +415,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
395
415
|
const viewportAnchorUnit =
|
|
396
416
|
region.viewportAnchorUnits == percentageUnit ? '%' : 'px';
|
|
397
417
|
|
|
398
|
-
regionElement.id = 'shaka-text-region---' +
|
|
418
|
+
regionElement.id = 'shaka-text-region---' + regionId;
|
|
399
419
|
regionElement.classList.add('shaka-text-region');
|
|
400
420
|
|
|
401
421
|
regionElement.style.height = region.height + heightUnit;
|
|
@@ -416,7 +436,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
416
436
|
regionElement.style.justifyContent = 'flex-end';
|
|
417
437
|
}
|
|
418
438
|
|
|
419
|
-
this.regionElements_.set(
|
|
439
|
+
this.regionElements_.set(regionId, regionElement);
|
|
420
440
|
return regionElement;
|
|
421
441
|
}
|
|
422
442
|
|
|
@@ -87,16 +87,28 @@ shaka.text.WebVttGenerator = class {
|
|
|
87
87
|
// We don't want to modify the array or objects passed in, since we don't
|
|
88
88
|
// technically own them. So we build a new array and replace certain items
|
|
89
89
|
// in it if they need to be flattened.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
90
|
+
// We also don't want to flatten the text payloads starting at a container
|
|
91
|
+
// element; otherwise, for containers encapsulating multiple caption lines,
|
|
92
|
+
// the lines would merge into a single cue. This is undesirable when a
|
|
93
|
+
// subset of the captions are outside of the append time window. To fix
|
|
94
|
+
// this, we only call flattenPayload() starting at elements marked as
|
|
95
|
+
// isContainer = false.
|
|
96
|
+
const getCuesToFlatten = (cues, result) => {
|
|
97
|
+
for (const cue of cues) {
|
|
98
|
+
if (cue.isContainer) {
|
|
99
|
+
// Recurse to find the actual text payload cues.
|
|
100
|
+
getCuesToFlatten(cue.nestedCues, result);
|
|
101
|
+
} else {
|
|
102
|
+
// Flatten the payload.
|
|
103
|
+
const flatCue = cue.clone();
|
|
104
|
+
flatCue.nestedCues = [];
|
|
105
|
+
flatCue.payload = flattenPayload(cue);
|
|
106
|
+
result.push(flatCue);
|
|
107
|
+
}
|
|
98
108
|
}
|
|
99
|
-
|
|
109
|
+
return result;
|
|
110
|
+
};
|
|
111
|
+
const flattenedCues = getCuesToFlatten(cues, []);
|
|
100
112
|
|
|
101
113
|
let webvttString = 'WEBVTT\n\n';
|
|
102
114
|
for (const cue of flattenedCues) {
|
package/lib/util/dom_utils.js
CHANGED
|
@@ -36,7 +36,9 @@ shaka.util.Dom = class {
|
|
|
36
36
|
* @return {!HTMLButtonElement}
|
|
37
37
|
*/
|
|
38
38
|
static createButton() {
|
|
39
|
-
|
|
39
|
+
const button = document.createElement('button');
|
|
40
|
+
button.setAttribute('type', 'button');
|
|
41
|
+
return /** @type {!HTMLButtonElement} */ (button);
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -450,12 +450,16 @@ shaka.util.StreamUtils = class {
|
|
|
450
450
|
if (!MediaSource.isTypeSupported(audioFullType)) {
|
|
451
451
|
return false;
|
|
452
452
|
}
|
|
453
|
+
// Update the codec string with the (possibly) converted codecs.
|
|
454
|
+
videoCodecs = [videoCodecs, audioCodecs].join(',');
|
|
453
455
|
}
|
|
454
456
|
const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
|
|
455
457
|
video.mimeType, videoCodecs, ContentType.VIDEO);
|
|
456
458
|
if (!MediaSource.isTypeSupported(fullType)) {
|
|
457
459
|
return false;
|
|
458
460
|
}
|
|
461
|
+
// Update the codec string with the (possibly) converted codecs.
|
|
462
|
+
video.codecs = videoCodecs;
|
|
459
463
|
}
|
|
460
464
|
const audio = variant.audio;
|
|
461
465
|
if (audio) {
|
|
@@ -466,6 +470,8 @@ shaka.util.StreamUtils = class {
|
|
|
466
470
|
if (!MediaSource.isTypeSupported(fullType)) {
|
|
467
471
|
return false;
|
|
468
472
|
}
|
|
473
|
+
// Update the codec string with the (possibly) converted codecs.
|
|
474
|
+
audio.codecs = codecs;
|
|
469
475
|
}
|
|
470
476
|
|
|
471
477
|
// See: https://github.com/shaka-project/shaka-player/issues/3380
|
package/lib/util/timer.js
CHANGED
|
@@ -78,6 +78,11 @@ shaka.util.Timer = class {
|
|
|
78
78
|
tickEvery(seconds) {
|
|
79
79
|
this.stop();
|
|
80
80
|
|
|
81
|
+
if (goog.DEBUG) {
|
|
82
|
+
// Capture the stack trace by making a fake error.
|
|
83
|
+
const stackTrace = Error('Timer created').stack;
|
|
84
|
+
shaka.util.Timer.activeTimers.set(this, stackTrace);
|
|
85
|
+
}
|
|
81
86
|
this.ticker_ = new shaka.util.DelayedTick(() => {
|
|
82
87
|
// Schedule the timer again first. |onTick_| could cancel the timer and
|
|
83
88
|
// rescheduling first simplifies the implementation.
|
|
@@ -99,5 +104,17 @@ shaka.util.Timer = class {
|
|
|
99
104
|
this.ticker_.stop();
|
|
100
105
|
this.ticker_ = null;
|
|
101
106
|
}
|
|
107
|
+
if (goog.DEBUG) {
|
|
108
|
+
shaka.util.Timer.activeTimers.delete(this);
|
|
109
|
+
}
|
|
102
110
|
}
|
|
103
111
|
};
|
|
112
|
+
|
|
113
|
+
if (goog.DEBUG) {
|
|
114
|
+
/**
|
|
115
|
+
* Tracks all active timer instances, along with the stack trace that created
|
|
116
|
+
* that timer.
|
|
117
|
+
* @type {!Map.<!shaka.util.Timer, string>}
|
|
118
|
+
*/
|
|
119
|
+
shaka.util.Timer.activeTimers = new Map();
|
|
120
|
+
}
|
package/package.json
CHANGED
|
@@ -72,6 +72,33 @@ describe('Player', () => {
|
|
|
72
72
|
});
|
|
73
73
|
}); // describe('attach')
|
|
74
74
|
|
|
75
|
+
describe('destroy', () => {
|
|
76
|
+
// Regression test for:
|
|
77
|
+
// https://github.com/shaka-project/shaka-player/issues/4850
|
|
78
|
+
it('does not leave any lingering timers', async () => {
|
|
79
|
+
shaka.util.Timer.activeTimers.clear();
|
|
80
|
+
|
|
81
|
+
// Unlike the other tests in this file, this uses an uncompiled build of
|
|
82
|
+
// Shaka, so that we don't need to expose shaka.util.Timer.activeTimers.
|
|
83
|
+
player = new shaka.Player(video);
|
|
84
|
+
waiter.setPlayer(player);
|
|
85
|
+
|
|
86
|
+
// Play the video for a little while.
|
|
87
|
+
await player.load('test:sintel');
|
|
88
|
+
video.play();
|
|
89
|
+
await waiter.waitUntilPlayheadReachesOrFailOnTimeout(video, 1, 10);
|
|
90
|
+
|
|
91
|
+
// Destroy the player.
|
|
92
|
+
await player.destroy();
|
|
93
|
+
|
|
94
|
+
// Are there any timers left?
|
|
95
|
+
for (const timer of shaka.util.Timer.activeTimers.keys()) {
|
|
96
|
+
const stackTrace = shaka.util.Timer.activeTimers.get(timer);
|
|
97
|
+
fail('Lingering timer exists! Stack trace of creation: ' + stackTrace);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
75
102
|
describe('updateStartTime() in manifestparsed event handler', () => {
|
|
76
103
|
it('does not get segments prior to startTime', async () => {
|
|
77
104
|
player.addEventListener('manifestparsed', () => {
|
|
@@ -879,7 +906,7 @@ describe('Player', () => {
|
|
|
879
906
|
expect(getBufferedBehind()).toBe(20); // Buffered to start still.
|
|
880
907
|
video.currentTime = 50;
|
|
881
908
|
await waitUntilBuffered(30);
|
|
882
|
-
expect(getBufferedBehind()).toBeLessThan(
|
|
909
|
+
expect(getBufferedBehind()).toBeLessThan(40); // 30 + segment_size
|
|
883
910
|
|
|
884
911
|
player.configure('streaming.bufferBehind', 10);
|
|
885
912
|
// We only evict content when we append a segment, so increase the
|
|
@@ -906,7 +933,7 @@ describe('Player', () => {
|
|
|
906
933
|
}
|
|
907
934
|
|
|
908
935
|
async function waitUntilBuffered(amount) {
|
|
909
|
-
for (let i = 0; i <
|
|
936
|
+
for (let i = 0; i < 50; i++) {
|
|
910
937
|
// We buffer from an internal segment, so this shouldn't take long to
|
|
911
938
|
// buffer.
|
|
912
939
|
await Util.delay(0.1); // eslint-disable-line no-await-in-loop
|
|
@@ -914,7 +941,14 @@ describe('Player', () => {
|
|
|
914
941
|
return;
|
|
915
942
|
}
|
|
916
943
|
}
|
|
917
|
-
|
|
944
|
+
|
|
945
|
+
const ranges =
|
|
946
|
+
shaka.media.TimeRangesUtils.getBufferedInfo(video.buffered);
|
|
947
|
+
const currentTime = video.currentTime;
|
|
948
|
+
const target = currentTime + amount;
|
|
949
|
+
|
|
950
|
+
throw new Error('Timeout waiting to buffer! ' +
|
|
951
|
+
JSON.stringify({ranges, currentTime, target}));
|
|
918
952
|
}
|
|
919
953
|
}); // describe('buffering')
|
|
920
954
|
|
package/test/player_unit.js
CHANGED
|
@@ -3185,7 +3185,9 @@ describe('Player', () => {
|
|
|
3185
3185
|
variant.addAudio(0, (stream) => {
|
|
3186
3186
|
stream.channelsCount = 6;
|
|
3187
3187
|
stream.audioSamplingRate = 48000;
|
|
3188
|
-
|
|
3188
|
+
// ac-3 is rewritten as ec-3 on Tizen, so for the stability of this
|
|
3189
|
+
// test case, use ec-3.
|
|
3190
|
+
stream.codecs = 'ec-3';
|
|
3189
3191
|
});
|
|
3190
3192
|
});
|
|
3191
3193
|
|
|
@@ -3210,7 +3212,7 @@ describe('Player', () => {
|
|
|
3210
3212
|
expect(abrManager.variants.length).toBe(1);
|
|
3211
3213
|
// It should be the 6-channel variant, based on our preference.
|
|
3212
3214
|
expect(abrManager.variants[0].audio.channelsCount).toBe(6);
|
|
3213
|
-
expect(abrManager.variants[0].audio.codecs).toBe('
|
|
3215
|
+
expect(abrManager.variants[0].audio.codecs).toBe('ec-3');
|
|
3214
3216
|
});
|
|
3215
3217
|
});
|
|
3216
3218
|
|
package/test/test/boot.js
CHANGED
|
@@ -66,22 +66,40 @@ function failTestsOnNamespacedElementOrAttributeNames() {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
69
|
+
* Fail the current test on a given error, constructed with a given header and
|
|
70
|
+
* the full stack trace of the error.
|
|
71
|
+
*
|
|
72
|
+
* @param {string} messageHeader
|
|
73
|
+
* @param {!Error} error
|
|
71
74
|
*/
|
|
72
|
-
function
|
|
75
|
+
function failOnError(messageHeader, error) {
|
|
76
|
+
let message = `${messageHeader}: ${error}`;
|
|
77
|
+
// Shaka errors have the stack trace in their toString() already, so don't
|
|
78
|
+
// add it again. For native errors, we need to see where it came from.
|
|
79
|
+
if (error && error.stack && !(error instanceof shaka.util.Error)) {
|
|
80
|
+
message += '\n' + error.stack;
|
|
81
|
+
}
|
|
82
|
+
fail(message);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Listen for unhandled errors and Promise rejections (which may occur after a
|
|
87
|
+
* test) and convert them into test failures.
|
|
88
|
+
*/
|
|
89
|
+
function failTestsOnUnhandledErrors() {
|
|
73
90
|
// https://developer.mozilla.org/en-US/docs/Web/Events/unhandledrejection
|
|
74
91
|
window.addEventListener('unhandledrejection', (event) => {
|
|
75
92
|
/** @type {?} */
|
|
76
93
|
const error = event.reason;
|
|
77
|
-
|
|
94
|
+
failOnError('Unhandled rejection in Promise', error);
|
|
95
|
+
});
|
|
78
96
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
97
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Window/error_event
|
|
98
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent
|
|
99
|
+
window.addEventListener('error', (event) => {
|
|
100
|
+
/** @type {?} */
|
|
101
|
+
const error = event['error'];
|
|
102
|
+
failOnError('Unhandled error', error);
|
|
85
103
|
});
|
|
86
104
|
}
|
|
87
105
|
|
|
@@ -387,7 +405,7 @@ function configureJasmineEnvironment() {
|
|
|
387
405
|
function setupTestEnvironment() {
|
|
388
406
|
failTestsOnFailedAssertions();
|
|
389
407
|
failTestsOnNamespacedElementOrAttributeNames();
|
|
390
|
-
|
|
408
|
+
failTestsOnUnhandledErrors();
|
|
391
409
|
disableScrollbars();
|
|
392
410
|
workAroundLegacyEdgePromiseIssues();
|
|
393
411
|
|
|
@@ -402,7 +402,7 @@ const sintelAudioSegment = {
|
|
|
402
402
|
mdhdOffset: 0x1b6,
|
|
403
403
|
segmentUri: '/base/test/test/assets/sintel-audio-segment.mp4',
|
|
404
404
|
tfdtOffset: 0x3c,
|
|
405
|
-
segmentDuration: 10
|
|
405
|
+
segmentDuration: 10,
|
|
406
406
|
mimeType: 'audio/mp4',
|
|
407
407
|
codecs: 'mp4a.40.2',
|
|
408
408
|
};
|
|
@@ -428,7 +428,7 @@ const sintelEncryptedAudio = {
|
|
|
428
428
|
mdhdOffset: 0x1b6,
|
|
429
429
|
segmentUri: '/base/test/test/assets/encrypted-sintel-audio-segment.mp4',
|
|
430
430
|
tfdtOffset: 0x3c,
|
|
431
|
-
segmentDuration: 10
|
|
431
|
+
segmentDuration: 10,
|
|
432
432
|
mimeType: 'audio/mp4',
|
|
433
433
|
codecs: 'mp4a.40.2',
|
|
434
434
|
initData:
|
|
@@ -537,4 +537,74 @@ describe('UITextDisplayer', () => {
|
|
|
537
537
|
'.shaka-text-region');
|
|
538
538
|
expect(allRegionElements.length).toBe(1);
|
|
539
539
|
});
|
|
540
|
+
|
|
541
|
+
it('creates separate regions when dimensions differ but id same', () => {
|
|
542
|
+
const identicalRegionId = 'regionId';
|
|
543
|
+
|
|
544
|
+
const cueRegion1 = new shaka.text.CueRegion();
|
|
545
|
+
const cueRegion2 = new shaka.text.CueRegion();
|
|
546
|
+
cueRegion1.id = identicalRegionId;
|
|
547
|
+
cueRegion2.id = identicalRegionId;
|
|
548
|
+
|
|
549
|
+
cueRegion1.height = 80;
|
|
550
|
+
cueRegion1.heightUnits = shaka.text.CueRegion.units.PERCENTAGE;
|
|
551
|
+
cueRegion1.width = 80;
|
|
552
|
+
cueRegion1.widthUnits = shaka.text.CueRegion.units.PERCENTAGE;
|
|
553
|
+
|
|
554
|
+
cueRegion2.height = 160; // the only difference!
|
|
555
|
+
cueRegion2.heightUnits = shaka.text.CueRegion.units.PERCENTAGE;
|
|
556
|
+
cueRegion2.width = 80;
|
|
557
|
+
cueRegion2.widthUnits = shaka.text.CueRegion.units.PERCENTAGE;
|
|
558
|
+
|
|
559
|
+
cueRegion1.viewportAnchorX = 10;
|
|
560
|
+
cueRegion1.viewportAnchorY = 10;
|
|
561
|
+
cueRegion1.viewportAnchorUnits = shaka.text.CueRegion.units.PERCENTAGE;
|
|
562
|
+
|
|
563
|
+
cueRegion2.viewportAnchorX = 10;
|
|
564
|
+
cueRegion2.viewportAnchorY = 10;
|
|
565
|
+
cueRegion2.viewportAnchorUnits = shaka.text.CueRegion.units.PERCENTAGE;
|
|
566
|
+
|
|
567
|
+
// These all attach to the same region, but only one region element should
|
|
568
|
+
// be created.
|
|
569
|
+
const firstBatchOfCues = [
|
|
570
|
+
new shaka.text.Cue(0, 100, ''),
|
|
571
|
+
new shaka.text.Cue(0, 100, ''),
|
|
572
|
+
new shaka.text.Cue(0, 100, ''),
|
|
573
|
+
];
|
|
574
|
+
for (const cue of firstBatchOfCues) {
|
|
575
|
+
cue.displayAlign = shaka.text.Cue.displayAlign.CENTER;
|
|
576
|
+
cue.region = cueRegion1;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Another batch for the other region
|
|
580
|
+
const secondBatchOfCues = [
|
|
581
|
+
new shaka.text.Cue(0, 100, ''),
|
|
582
|
+
new shaka.text.Cue(0, 100, ''),
|
|
583
|
+
new shaka.text.Cue(0, 100, ''),
|
|
584
|
+
];
|
|
585
|
+
for (const cue of secondBatchOfCues) {
|
|
586
|
+
cue.displayAlign = shaka.text.Cue.displayAlign.CENTER;
|
|
587
|
+
cue.region = cueRegion2;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
textDisplayer.setTextVisibility(true);
|
|
591
|
+
textDisplayer.append(firstBatchOfCues);
|
|
592
|
+
textDisplayer.append(secondBatchOfCues);
|
|
593
|
+
updateCaptions();
|
|
594
|
+
|
|
595
|
+
const textContainer = videoContainer.querySelector('.shaka-text-container');
|
|
596
|
+
const allRegionElements = textContainer.querySelectorAll(
|
|
597
|
+
'.shaka-text-region');
|
|
598
|
+
|
|
599
|
+
// Verify that the nested cues are attached to respective region element.
|
|
600
|
+
expect(allRegionElements.length).toBe(2);
|
|
601
|
+
|
|
602
|
+
const childrenOfOne = Array.from(allRegionElements[0].childNodes).filter(
|
|
603
|
+
(e) => e.nodeType == Node.ELEMENT_NODE);
|
|
604
|
+
expect(childrenOfOne.length).toBe(3);
|
|
605
|
+
|
|
606
|
+
const childrenOfTwo = Array.from(allRegionElements[1].childNodes).filter(
|
|
607
|
+
(e) => e.nodeType == Node.ELEMENT_NODE);
|
|
608
|
+
expect(childrenOfTwo.length).toBe(3);
|
|
609
|
+
});
|
|
540
610
|
});
|