shaka-player 3.2.3 → 3.2.4
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 +73 -0
- package/.github/workflows/release.yaml +53 -0
- package/CHANGELOG.md +13 -1
- package/build/checkversion.py +1 -1
- package/build/test.py +6 -0
- package/dist/controls.css +1 -1
- package/dist/deps.js +3 -3
- package/dist/locales.js +30 -30
- package/dist/shaka-player.compiled.d.ts +2 -1
- package/dist/shaka-player.compiled.debug.d.ts +2 -1
- package/dist/shaka-player.compiled.debug.externs.js +17 -12
- package/dist/shaka-player.compiled.debug.js +95 -93
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +17 -12
- package/dist/shaka-player.compiled.js +610 -608
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +4 -12
- package/dist/shaka-player.ui.debug.d.ts +4 -12
- package/dist/shaka-player.ui.debug.externs.js +19 -23
- package/dist/shaka-player.ui.debug.js +109 -108
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +19 -23
- package/dist/shaka-player.ui.js +774 -773
- package/dist/shaka-player.ui.map +3 -3
- package/karma.conf.js +19 -15
- package/lib/ads/ad_manager.js +1 -0
- package/lib/cast/cast_proxy.js +3 -0
- package/lib/cast/cast_receiver.js +3 -0
- package/lib/dash/dash_parser.js +31 -19
- package/lib/hls/manifest_text_parser.js +1 -0
- package/lib/media/region_observer.js +39 -33
- package/lib/media/region_timeline.js +17 -19
- package/lib/media/streaming_engine.js +1 -1
- package/lib/net/networking_engine.js +4 -0
- package/lib/offline/storage.js +8 -9
- package/lib/player.js +25 -9
- package/lib/util/fake_event_target.js +21 -1
- package/package.json +3 -6
- package/test/dash/dash_parser_live_unit.js +43 -0
- package/test/dash/dash_parser_manifest_unit.js +2 -1
- package/test/hls/hls_parser_unit.js +74 -0
- package/test/media/region_observer_unit.js +40 -5
- package/test/media/region_timeline_unit.js +40 -22
- package/test/test/util/util.js +10 -7
- package/test/ui/text_displayer_layout_unit.js +8 -7
- package/ui/controls.js +3 -0
- package/ui/localization.js +12 -36
package/karma.conf.js
CHANGED
|
@@ -11,6 +11,7 @@ const Jimp = require('jimp');
|
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const rimraf = require('rimraf');
|
|
14
|
+
const {ssim} = require('ssim.js');
|
|
14
15
|
const util = require('karma/common/util');
|
|
15
16
|
const which = require('which');
|
|
16
17
|
|
|
@@ -336,6 +337,10 @@ module.exports = (config) => {
|
|
|
336
337
|
|
|
337
338
|
config.set({reporters: reporters});
|
|
338
339
|
|
|
340
|
+
if (reporters.includes('spec') && settings.spec_hide_passed) {
|
|
341
|
+
config.set({specReporter: {suppressPassed: true}});
|
|
342
|
+
}
|
|
343
|
+
|
|
339
344
|
if (settings.random) {
|
|
340
345
|
// If --seed was specified use that value, else generate a seed so that the
|
|
341
346
|
// exact order can be reproduced if it catches an issue.
|
|
@@ -518,8 +523,7 @@ function WebDriverScreenshotMiddlewareFactory(launcher) {
|
|
|
518
523
|
*
|
|
519
524
|
* @param {karma.Launcher.Browser} browser
|
|
520
525
|
* @param {!Object.<string, string>} params
|
|
521
|
-
* @return {!Promise.<number>}
|
|
522
|
-
* and new screenshots, after cropping and scaling.
|
|
526
|
+
* @return {!Promise.<number>} A similarity score between 0 and 1.
|
|
523
527
|
*/
|
|
524
528
|
async function diffScreenshot(browser, params) {
|
|
525
529
|
const webDriverClient = getWebDriverClient(browser);
|
|
@@ -604,22 +608,22 @@ function WebDriverScreenshotMiddlewareFactory(launcher) {
|
|
|
604
608
|
// Compare the new screenshot to the old one and produce a diff image.
|
|
605
609
|
// Initially, the image data will be raw pixels, 4 bytes per pixel.
|
|
606
610
|
// The threshold parameter affects the sensitivity of individual pixel
|
|
607
|
-
// comparisons.
|
|
608
|
-
//
|
|
609
|
-
//
|
|
610
|
-
|
|
611
|
-
const diff = Jimp.diff(oldScreenshot, newScreenshot,
|
|
611
|
+
// comparisons. This diff is only used for visual review, not for
|
|
612
|
+
// automated similarity checks, so the threshold setting is not so critical
|
|
613
|
+
// as it used to be.
|
|
614
|
+
const threshold = 0.10;
|
|
615
|
+
const diff = Jimp.diff(oldScreenshot, newScreenshot, threshold);
|
|
612
616
|
|
|
613
617
|
// Write the diff to disk. This is used to review when there are changes.
|
|
618
|
+
const fullSizeDiff =
|
|
619
|
+
diff.image.clone().resize(width, height, Jimp.RESIZE_BICUBIC);
|
|
614
620
|
fs.writeFileSync(
|
|
615
|
-
diffScreenshotPath, await
|
|
616
|
-
|
|
617
|
-
//
|
|
618
|
-
//
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
diff.percent * diff.image.bitmap.width * diff.image.bitmap.height;
|
|
622
|
-
return pixelsChanged;
|
|
621
|
+
diffScreenshotPath, await fullSizeDiff.getBufferAsync('image/png'));
|
|
622
|
+
|
|
623
|
+
// Compare with a structural similarity algorithm. This produces a
|
|
624
|
+
// similarity score that we will use to pass or fail the test.
|
|
625
|
+
const ssimResult = ssim(oldScreenshot.bitmap, newScreenshot.bitmap);
|
|
626
|
+
return ssimResult.mssim; // A score between 0 and 1.
|
|
623
627
|
}
|
|
624
628
|
|
|
625
629
|
/**
|
package/lib/ads/ad_manager.js
CHANGED
package/lib/cast/cast_proxy.js
CHANGED
|
@@ -238,6 +238,9 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget {
|
|
|
238
238
|
this.shakaBus_ = null;
|
|
239
239
|
this.genericBus_ = null;
|
|
240
240
|
|
|
241
|
+
// FakeEventTarget implements IReleasable
|
|
242
|
+
super.release();
|
|
243
|
+
|
|
241
244
|
await Promise.all(waitFor);
|
|
242
245
|
|
|
243
246
|
const manager = cast.receiver.CastReceiverManager.getInstance();
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -401,6 +401,24 @@ shaka.dash.DashParser = class {
|
|
|
401
401
|
this.config_.dash.autoCorrectDrift);
|
|
402
402
|
}
|
|
403
403
|
|
|
404
|
+
presentationTimeline.setStatic(mpdType == 'static');
|
|
405
|
+
|
|
406
|
+
const isLive = presentationTimeline.isLive();
|
|
407
|
+
|
|
408
|
+
// If it's live, we check for an override.
|
|
409
|
+
if (isLive && !isNaN(this.config_.availabilityWindowOverride)) {
|
|
410
|
+
segmentAvailabilityDuration = this.config_.availabilityWindowOverride;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// If it's null, that means segments are always available. This is always
|
|
414
|
+
// the case for VOD, and sometimes the case for live.
|
|
415
|
+
if (segmentAvailabilityDuration == null) {
|
|
416
|
+
segmentAvailabilityDuration = Infinity;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
presentationTimeline.setSegmentAvailabilityDuration(
|
|
420
|
+
segmentAvailabilityDuration);
|
|
421
|
+
|
|
404
422
|
const profiles = mpd.getAttribute('profiles') || '';
|
|
405
423
|
|
|
406
424
|
/** @type {shaka.dash.DashParser.Context} */
|
|
@@ -423,7 +441,6 @@ shaka.dash.DashParser = class {
|
|
|
423
441
|
const duration = periodsAndDuration.duration;
|
|
424
442
|
const periods = periodsAndDuration.periods;
|
|
425
443
|
|
|
426
|
-
presentationTimeline.setStatic(mpdType == 'static');
|
|
427
444
|
if (mpdType == 'static' ||
|
|
428
445
|
!periodsAndDuration.durationDerivedFromPeriods) {
|
|
429
446
|
// Ignore duration calculated from Period lengths if this is dynamic.
|
|
@@ -442,6 +459,7 @@ shaka.dash.DashParser = class {
|
|
|
442
459
|
this.lowLatencyMode_ = this.playerInterface_.isLowLatencyMode();
|
|
443
460
|
}
|
|
444
461
|
}
|
|
462
|
+
|
|
445
463
|
if (this.lowLatencyMode_) {
|
|
446
464
|
presentationTimeline.setAvailabilityTimeOffset(
|
|
447
465
|
this.minTotalAvailabilityTimeOffset_);
|
|
@@ -455,22 +473,6 @@ shaka.dash.DashParser = class {
|
|
|
455
473
|
'https://bit.ly/3clctcj for details.');
|
|
456
474
|
}
|
|
457
475
|
|
|
458
|
-
const isLive = presentationTimeline.isLive();
|
|
459
|
-
|
|
460
|
-
// If it's live, we check for an override.
|
|
461
|
-
if (isLive && !isNaN(this.config_.availabilityWindowOverride)) {
|
|
462
|
-
segmentAvailabilityDuration = this.config_.availabilityWindowOverride;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// If it's null, that means segments are always available. This is always
|
|
466
|
-
// the case for VOD, and sometimes the case for live.
|
|
467
|
-
if (segmentAvailabilityDuration == null) {
|
|
468
|
-
segmentAvailabilityDuration = Infinity;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
presentationTimeline.setSegmentAvailabilityDuration(
|
|
472
|
-
segmentAvailabilityDuration);
|
|
473
|
-
|
|
474
476
|
// Use @maxSegmentDuration to override smaller, derived values.
|
|
475
477
|
presentationTimeline.notifyMaxSegmentDuration(maxSegmentDuration || 1);
|
|
476
478
|
if (goog.DEBUG) {
|
|
@@ -705,8 +707,12 @@ shaka.dash.DashParser = class {
|
|
|
705
707
|
|
|
706
708
|
const eventStreamNodes =
|
|
707
709
|
XmlUtils.findChildren(periodInfo.node, 'EventStream');
|
|
710
|
+
const availabilityStart =
|
|
711
|
+
context.presentationTimeline.getSegmentAvailabilityStart();
|
|
712
|
+
|
|
708
713
|
for (const node of eventStreamNodes) {
|
|
709
|
-
this.parseEventStream_(
|
|
714
|
+
this.parseEventStream_(
|
|
715
|
+
periodInfo.start, periodInfo.duration, node, availabilityStart);
|
|
710
716
|
}
|
|
711
717
|
|
|
712
718
|
const adaptationSetNodes =
|
|
@@ -1737,9 +1743,10 @@ shaka.dash.DashParser = class {
|
|
|
1737
1743
|
* @param {number} periodStart
|
|
1738
1744
|
* @param {?number} periodDuration
|
|
1739
1745
|
* @param {!Element} elem
|
|
1746
|
+
* @param {number} availabilityStart
|
|
1740
1747
|
* @private
|
|
1741
1748
|
*/
|
|
1742
|
-
parseEventStream_(periodStart, periodDuration, elem) {
|
|
1749
|
+
parseEventStream_(periodStart, periodDuration, elem, availabilityStart) {
|
|
1743
1750
|
const XmlUtils = shaka.util.XmlUtils;
|
|
1744
1751
|
const parseNumber = XmlUtils.parseNonNegativeInt;
|
|
1745
1752
|
|
|
@@ -1762,6 +1769,11 @@ shaka.dash.DashParser = class {
|
|
|
1762
1769
|
endTime = Math.min(endTime, periodStart + periodDuration);
|
|
1763
1770
|
}
|
|
1764
1771
|
|
|
1772
|
+
// Don't add unavailable regions to the timeline.
|
|
1773
|
+
if (endTime < availabilityStart) {
|
|
1774
|
+
continue;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1765
1777
|
/** @type {shaka.extern.TimelineRegionInfo} */
|
|
1766
1778
|
const region = {
|
|
1767
1779
|
schemeIdUri: schemeIdUri,
|
|
@@ -8,16 +8,19 @@ goog.provide('shaka.media.RegionObserver');
|
|
|
8
8
|
|
|
9
9
|
goog.require('shaka.media.IPlayheadObserver');
|
|
10
10
|
goog.require('shaka.media.RegionTimeline');
|
|
11
|
+
goog.require('shaka.util.EventManager');
|
|
12
|
+
goog.require('shaka.util.FakeEvent');
|
|
13
|
+
goog.require('shaka.util.FakeEventTarget');
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
/**
|
|
14
17
|
* The region observer watches a region timeline and playhead, and fires events
|
|
15
|
-
* (
|
|
18
|
+
* ('enter', 'exit', 'skip') as the playhead moves.
|
|
16
19
|
*
|
|
17
20
|
* @implements {shaka.media.IPlayheadObserver}
|
|
18
21
|
* @final
|
|
19
22
|
*/
|
|
20
|
-
shaka.media.RegionObserver = class {
|
|
23
|
+
shaka.media.RegionObserver = class extends shaka.util.FakeEventTarget {
|
|
21
24
|
/**
|
|
22
25
|
* Create a region observer for the given timeline. The observer does not
|
|
23
26
|
* own the timeline, only uses it. This means that the observer should NOT
|
|
@@ -26,6 +29,8 @@ shaka.media.RegionObserver = class {
|
|
|
26
29
|
* @param {!shaka.media.RegionTimeline} timeline
|
|
27
30
|
*/
|
|
28
31
|
constructor(timeline) {
|
|
32
|
+
super();
|
|
33
|
+
|
|
29
34
|
/** @private {shaka.media.RegionTimeline} */
|
|
30
35
|
this.timeline_ = timeline;
|
|
31
36
|
|
|
@@ -39,13 +44,6 @@ shaka.media.RegionObserver = class {
|
|
|
39
44
|
*/
|
|
40
45
|
this.oldPosition_ = new Map();
|
|
41
46
|
|
|
42
|
-
/** @private {shaka.media.RegionObserver.EventListener} */
|
|
43
|
-
this.onEnter_ = (region, seeking) => {};
|
|
44
|
-
/** @private {shaka.media.RegionObserver.EventListener} */
|
|
45
|
-
this.onExit_ = (region, seeking) => {};
|
|
46
|
-
/** @private {shaka.media.RegionObserver.EventListener} */
|
|
47
|
-
this.onSkip_ = (region, seeking) => {};
|
|
48
|
-
|
|
49
47
|
// To make the rules easier to read, alias all the relative positions.
|
|
50
48
|
const RelativePosition = shaka.media.RegionObserver.RelativePosition_;
|
|
51
49
|
const BEFORE_THE_REGION = RelativePosition.BEFORE_THE_REGION;
|
|
@@ -62,39 +60,48 @@ shaka.media.RegionObserver = class {
|
|
|
62
60
|
{
|
|
63
61
|
weWere: null,
|
|
64
62
|
weAre: IN_THE_REGION,
|
|
65
|
-
invoke: (region, seeking) => this.
|
|
63
|
+
invoke: (region, seeking) => this.onEvent_('enter', region, seeking),
|
|
66
64
|
},
|
|
67
65
|
{
|
|
68
66
|
weWere: BEFORE_THE_REGION,
|
|
69
67
|
weAre: IN_THE_REGION,
|
|
70
|
-
invoke: (region, seeking) => this.
|
|
68
|
+
invoke: (region, seeking) => this.onEvent_('enter', region, seeking),
|
|
71
69
|
},
|
|
72
70
|
{
|
|
73
71
|
weWere: AFTER_THE_REGION,
|
|
74
72
|
weAre: IN_THE_REGION,
|
|
75
|
-
invoke: (region, seeking) => this.
|
|
73
|
+
invoke: (region, seeking) => this.onEvent_('enter', region, seeking),
|
|
76
74
|
},
|
|
77
75
|
{
|
|
78
76
|
weWere: IN_THE_REGION,
|
|
79
77
|
weAre: BEFORE_THE_REGION,
|
|
80
|
-
invoke: (region, seeking) => this.
|
|
78
|
+
invoke: (region, seeking) => this.onEvent_('exit', region, seeking),
|
|
81
79
|
},
|
|
82
80
|
{
|
|
83
81
|
weWere: IN_THE_REGION,
|
|
84
82
|
weAre: AFTER_THE_REGION,
|
|
85
|
-
invoke: (region, seeking) => this.
|
|
83
|
+
invoke: (region, seeking) => this.onEvent_('exit', region, seeking),
|
|
86
84
|
},
|
|
87
85
|
{
|
|
88
86
|
weWere: BEFORE_THE_REGION,
|
|
89
87
|
weAre: AFTER_THE_REGION,
|
|
90
|
-
invoke: (region, seeking) => this.
|
|
88
|
+
invoke: (region, seeking) => this.onEvent_('skip', region, seeking),
|
|
91
89
|
},
|
|
92
90
|
{
|
|
93
91
|
weWere: AFTER_THE_REGION,
|
|
94
92
|
weAre: BEFORE_THE_REGION,
|
|
95
|
-
invoke: (region, seeking) => this.
|
|
93
|
+
invoke: (region, seeking) => this.onEvent_('skip', region, seeking),
|
|
96
94
|
},
|
|
97
95
|
];
|
|
96
|
+
|
|
97
|
+
/** @private {shaka.util.EventManager} */
|
|
98
|
+
this.eventManager_ = new shaka.util.EventManager();
|
|
99
|
+
|
|
100
|
+
this.eventManager_.listen(this.timeline_, 'regionremove', (event) => {
|
|
101
|
+
/** @type {shaka.extern.TimelineRegionInfo} */
|
|
102
|
+
const region = event['region'];
|
|
103
|
+
this.oldPosition_.delete(region);
|
|
104
|
+
});
|
|
98
105
|
}
|
|
99
106
|
|
|
100
107
|
/** @override */
|
|
@@ -105,11 +112,10 @@ shaka.media.RegionObserver = class {
|
|
|
105
112
|
// needed.
|
|
106
113
|
this.oldPosition_.clear();
|
|
107
114
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
this.onSkip_ = (region, seeking) => {};
|
|
115
|
+
this.eventManager_.release();
|
|
116
|
+
this.eventManager_ = null;
|
|
117
|
+
|
|
118
|
+
super.release();
|
|
113
119
|
}
|
|
114
120
|
|
|
115
121
|
/** @override */
|
|
@@ -134,20 +140,20 @@ shaka.media.RegionObserver = class {
|
|
|
134
140
|
}
|
|
135
141
|
|
|
136
142
|
/**
|
|
137
|
-
*
|
|
143
|
+
* Dispatch events of the given type. All event types in this class have the
|
|
144
|
+
* same parameters: region and seeking.
|
|
138
145
|
*
|
|
139
|
-
* @param {
|
|
140
|
-
*
|
|
141
|
-
* @param {
|
|
142
|
-
*
|
|
143
|
-
* @param {shaka.media.RegionObserver.EventListener} onSkip
|
|
144
|
-
* The callback for when we move from before to after a region or from
|
|
145
|
-
* after to before a region.
|
|
146
|
+
* @param {string} eventType
|
|
147
|
+
* @param {shaka.extern.TimelineRegionInfo} region
|
|
148
|
+
* @param {boolean} seeking
|
|
149
|
+
* @private
|
|
146
150
|
*/
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
onEvent_(eventType, region, seeking) {
|
|
152
|
+
const event = new shaka.util.FakeEvent(eventType, new Map([
|
|
153
|
+
['region', region],
|
|
154
|
+
['seeking', seeking],
|
|
155
|
+
]));
|
|
156
|
+
this.dispatchEvent(event);
|
|
151
157
|
}
|
|
152
158
|
|
|
153
159
|
/**
|
|
@@ -6,26 +6,30 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.media.RegionTimeline');
|
|
8
8
|
|
|
9
|
+
goog.require('shaka.util.FakeEvent');
|
|
10
|
+
goog.require('shaka.util.FakeEventTarget');
|
|
9
11
|
goog.require('shaka.util.IReleasable');
|
|
10
12
|
goog.require('shaka.util.Timer');
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* The region timeline is a set of unique timeline region info entries. When
|
|
15
|
-
* a new entry is added, the
|
|
17
|
+
* a new entry is added, the 'regionadd' event will be fired. When an entry is
|
|
18
|
+
* deleted, the 'regionremove' event will be fired.
|
|
16
19
|
*
|
|
17
20
|
* @implements {shaka.util.IReleasable}
|
|
18
21
|
* @final
|
|
19
22
|
*/
|
|
20
|
-
shaka.media.RegionTimeline = class {
|
|
23
|
+
shaka.media.RegionTimeline = class extends shaka.util.FakeEventTarget {
|
|
21
24
|
/**
|
|
22
25
|
* @param {!function():{start: number, end: number}} getSeekRange
|
|
23
26
|
*/
|
|
24
27
|
constructor(getSeekRange) {
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
super();
|
|
29
|
+
|
|
27
30
|
/** @private {!Set.<shaka.extern.TimelineRegionInfo>} */
|
|
28
31
|
this.regions_ = new Set();
|
|
32
|
+
|
|
29
33
|
/** @private {!function():{start: number, end: number}} */
|
|
30
34
|
this.getSeekRange_ = getSeekRange;
|
|
31
35
|
|
|
@@ -44,22 +48,9 @@ shaka.media.RegionTimeline = class {
|
|
|
44
48
|
|
|
45
49
|
/** @override */
|
|
46
50
|
release() {
|
|
47
|
-
// Prevent us from holding onto any external references via the callback.
|
|
48
|
-
this.onAddRegion_ = (region) => {};
|
|
49
51
|
this.regions_.clear();
|
|
50
52
|
this.filterTimer_.stop();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Set the callbacks for events. This will override any previous calls to
|
|
55
|
-
* |setListeners|.
|
|
56
|
-
*
|
|
57
|
-
* @param {function(shaka.extern.TimelineRegionInfo)} onAddRegion
|
|
58
|
-
* Set the callback for when we add a new region. This callback will only
|
|
59
|
-
* be called when a region is unique (we reject duplicate regions).
|
|
60
|
-
*/
|
|
61
|
-
setListeners(onAddRegion) {
|
|
62
|
-
this.onAddRegion_ = onAddRegion;
|
|
53
|
+
super.release();
|
|
63
54
|
}
|
|
64
55
|
|
|
65
56
|
/**
|
|
@@ -72,7 +63,10 @@ shaka.media.RegionTimeline = class {
|
|
|
72
63
|
// instead of making the parser track it.
|
|
73
64
|
if (similarRegion == null) {
|
|
74
65
|
this.regions_.add(region);
|
|
75
|
-
|
|
66
|
+
const event = new shaka.util.FakeEvent('regionadd', new Map([
|
|
67
|
+
['region', region],
|
|
68
|
+
]));
|
|
69
|
+
this.dispatchEvent(event);
|
|
76
70
|
}
|
|
77
71
|
}
|
|
78
72
|
|
|
@@ -89,6 +83,10 @@ shaka.media.RegionTimeline = class {
|
|
|
89
83
|
// reson to store or process them.
|
|
90
84
|
if (region.endTime < seekRange.start) {
|
|
91
85
|
this.regions_.delete(region);
|
|
86
|
+
const event = new shaka.util.FakeEvent('regionremove', new Map([
|
|
87
|
+
['region', region],
|
|
88
|
+
]));
|
|
89
|
+
this.dispatchEvent(event);
|
|
92
90
|
}
|
|
93
91
|
}
|
|
94
92
|
}
|
|
@@ -1644,7 +1644,7 @@ shaka.media.StreamingEngine = class {
|
|
|
1644
1644
|
// See DASH sec. 5.10.3.3.1
|
|
1645
1645
|
// If a DASH client detects an event message box with a scheme that is not
|
|
1646
1646
|
// defined in MPD, the client is expected to ignore it.
|
|
1647
|
-
if (emsgSchemeIdUris.includes(schemeId)) {
|
|
1647
|
+
if (emsgSchemeIdUris && emsgSchemeIdUris.includes(schemeId)) {
|
|
1648
1648
|
// See DASH sec. 5.10.4.1
|
|
1649
1649
|
// A special scheme in DASH used to signal manifest updates.
|
|
1650
1650
|
if (schemeId == 'urn:mpeg:dash:event:2012') {
|
|
@@ -222,6 +222,10 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
|
|
|
222
222
|
this.destroyed_ = true;
|
|
223
223
|
this.requestFilters_.clear();
|
|
224
224
|
this.responseFilters_.clear();
|
|
225
|
+
|
|
226
|
+
// FakeEventTarget implements IReleasable
|
|
227
|
+
super.release();
|
|
228
|
+
|
|
225
229
|
return this.operationManager_.destroy();
|
|
226
230
|
}
|
|
227
231
|
|
package/lib/offline/storage.js
CHANGED
|
@@ -477,16 +477,15 @@ shaka.offline.Storage = class {
|
|
|
477
477
|
* @private
|
|
478
478
|
*/
|
|
479
479
|
async filterManifest_(manifest, drmEngine, config) {
|
|
480
|
-
const StreamUtils = shaka.util.StreamUtils;
|
|
481
|
-
|
|
482
480
|
// Filter the manifest based on the restrictions given in the player
|
|
483
481
|
// configuration.
|
|
484
482
|
const maxHwRes = {width: Infinity, height: Infinity};
|
|
485
|
-
StreamUtils.filterByRestrictions(
|
|
483
|
+
shaka.util.StreamUtils.filterByRestrictions(
|
|
484
|
+
manifest, config.restrictions, maxHwRes);
|
|
486
485
|
|
|
487
486
|
// Filter the manifest based on what we know MediaCapabilities will be able
|
|
488
487
|
// to play later (no point storing something we can't play).
|
|
489
|
-
StreamUtils.filterManifestByMediaCapabilities(
|
|
488
|
+
await shaka.util.StreamUtils.filterManifestByMediaCapabilities(
|
|
490
489
|
manifest, config.offline.usePersistentLicense);
|
|
491
490
|
|
|
492
491
|
// Gather all tracks.
|
|
@@ -498,24 +497,24 @@ shaka.offline.Storage = class {
|
|
|
498
497
|
const preferredVideoCodecs = config.preferredVideoCodecs;
|
|
499
498
|
const preferredAudioCodecs = config.preferredAudioCodecs;
|
|
500
499
|
|
|
501
|
-
StreamUtils.chooseCodecsAndFilterManifest(
|
|
500
|
+
shaka.util.StreamUtils.chooseCodecsAndFilterManifest(
|
|
502
501
|
manifest, preferredVideoCodecs, preferredAudioCodecs,
|
|
503
502
|
preferredAudioChannelCount, preferredDecodingAttributes);
|
|
504
503
|
|
|
505
504
|
for (const variant of manifest.variants) {
|
|
506
505
|
goog.asserts.assert(
|
|
507
|
-
StreamUtils.isPlayable(variant),
|
|
506
|
+
shaka.util.StreamUtils.isPlayable(variant),
|
|
508
507
|
'We should have already filtered by "is playable"');
|
|
509
508
|
|
|
510
|
-
allTracks.push(StreamUtils.variantToTrack(variant));
|
|
509
|
+
allTracks.push(shaka.util.StreamUtils.variantToTrack(variant));
|
|
511
510
|
}
|
|
512
511
|
|
|
513
512
|
for (const text of manifest.textStreams) {
|
|
514
|
-
allTracks.push(StreamUtils.textStreamToTrack(text));
|
|
513
|
+
allTracks.push(shaka.util.StreamUtils.textStreamToTrack(text));
|
|
515
514
|
}
|
|
516
515
|
|
|
517
516
|
for (const image of manifest.imageStreams) {
|
|
518
|
-
allTracks.push(StreamUtils.imageStreamToTrack(image));
|
|
517
|
+
allTracks.push(shaka.util.StreamUtils.imageStreamToTrack(image));
|
|
519
518
|
}
|
|
520
519
|
|
|
521
520
|
// Let the application choose which tracks to store.
|
package/lib/player.js
CHANGED
|
@@ -728,6 +728,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
728
728
|
await this.networkingEngine_.destroy();
|
|
729
729
|
this.networkingEngine_ = null;
|
|
730
730
|
}
|
|
731
|
+
|
|
732
|
+
// FakeEventTarget implements IReleasable
|
|
733
|
+
super.release();
|
|
731
734
|
}
|
|
732
735
|
|
|
733
736
|
/**
|
|
@@ -1611,8 +1614,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1611
1614
|
// initialize it now even through it appears a little out-of-place.
|
|
1612
1615
|
this.regionTimeline_ =
|
|
1613
1616
|
new shaka.media.RegionTimeline(() => this.seekRange());
|
|
1614
|
-
this.regionTimeline_.
|
|
1617
|
+
this.regionTimeline_.addEventListener('regionadd', (event) => {
|
|
1618
|
+
/** @type {shaka.extern.TimelineRegionInfo} */
|
|
1619
|
+
const region = event['region'];
|
|
1615
1620
|
this.onRegionEvent_(shaka.Player.EventName.TimelineRegionAdded, region);
|
|
1621
|
+
|
|
1616
1622
|
if (this.adManager_) {
|
|
1617
1623
|
this.adManager_.onDashTimedMetadata(region);
|
|
1618
1624
|
}
|
|
@@ -2547,21 +2553,31 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2547
2553
|
// Create the region observer. This will allow us to notify the app when we
|
|
2548
2554
|
// move in and out of timeline regions.
|
|
2549
2555
|
const regionObserver = new shaka.media.RegionObserver(this.regionTimeline_);
|
|
2550
|
-
|
|
2556
|
+
|
|
2557
|
+
regionObserver.addEventListener('enter', (event) => {
|
|
2558
|
+
/** @type {shaka.extern.TimelineRegionInfo} */
|
|
2559
|
+
const region = event['region'];
|
|
2551
2560
|
this.onRegionEvent_(shaka.Player.EventName.TimelineRegionEnter, region);
|
|
2552
|
-
};
|
|
2553
|
-
|
|
2561
|
+
});
|
|
2562
|
+
|
|
2563
|
+
regionObserver.addEventListener('exit', (event) => {
|
|
2564
|
+
/** @type {shaka.extern.TimelineRegionInfo} */
|
|
2565
|
+
const region = event['region'];
|
|
2554
2566
|
this.onRegionEvent_(shaka.Player.EventName.TimelineRegionExit, region);
|
|
2555
|
-
};
|
|
2556
|
-
|
|
2567
|
+
});
|
|
2568
|
+
|
|
2569
|
+
regionObserver.addEventListener('skip', (event) => {
|
|
2570
|
+
/** @type {shaka.extern.TimelineRegionInfo} */
|
|
2571
|
+
const region = event['region'];
|
|
2572
|
+
/** @type {boolean} */
|
|
2573
|
+
const seeking = event['seeking'];
|
|
2557
2574
|
// If we are seeking, we don't want to surface the enter/exit events since
|
|
2558
2575
|
// they didn't play through them.
|
|
2559
2576
|
if (!seeking) {
|
|
2560
2577
|
this.onRegionEvent_(shaka.Player.EventName.TimelineRegionEnter, region);
|
|
2561
2578
|
this.onRegionEvent_(shaka.Player.EventName.TimelineRegionExit, region);
|
|
2562
2579
|
}
|
|
2563
|
-
};
|
|
2564
|
-
regionObserver.setListeners(onEnterRegion, onExitRegion, onSkipRegion);
|
|
2580
|
+
});
|
|
2565
2581
|
|
|
2566
2582
|
// Now that we have all our observers, create a manager for them.
|
|
2567
2583
|
const manager = new shaka.media.PlayheadObserverManager(this.video_);
|
|
@@ -6338,7 +6354,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6338
6354
|
* @define {string} A version number taken from git at compile time.
|
|
6339
6355
|
* @export
|
|
6340
6356
|
*/
|
|
6341
|
-
shaka.Player.version = 'v3.2.
|
|
6357
|
+
shaka.Player.version = 'v3.2.4-uncompiled'; // x-release-please-version
|
|
6342
6358
|
|
|
6343
6359
|
// Initialize the deprecation system using the version string we just set
|
|
6344
6360
|
// on the player.
|
|
@@ -9,6 +9,7 @@ goog.provide('shaka.util.FakeEventTarget');
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
10
|
goog.require('shaka.log');
|
|
11
11
|
goog.require('shaka.util.FakeEvent');
|
|
12
|
+
goog.require('shaka.util.IReleasable');
|
|
12
13
|
goog.require('shaka.util.MultiMap');
|
|
13
14
|
|
|
14
15
|
|
|
@@ -18,13 +19,14 @@ goog.require('shaka.util.MultiMap');
|
|
|
18
19
|
* to non-DOM classes. Only FakeEvents should be dispatched.
|
|
19
20
|
*
|
|
20
21
|
* @implements {EventTarget}
|
|
22
|
+
* @implements {shaka.util.IReleasable}
|
|
21
23
|
* @exportInterface
|
|
22
24
|
*/
|
|
23
25
|
shaka.util.FakeEventTarget = class {
|
|
24
26
|
/** */
|
|
25
27
|
constructor() {
|
|
26
28
|
/**
|
|
27
|
-
* @private {
|
|
29
|
+
* @private {shaka.util.MultiMap.<shaka.util.FakeEventTarget.ListenerType>}
|
|
28
30
|
*/
|
|
29
31
|
this.listeners_ = new shaka.util.MultiMap();
|
|
30
32
|
|
|
@@ -46,6 +48,9 @@ shaka.util.FakeEventTarget = class {
|
|
|
46
48
|
* @exportInterface
|
|
47
49
|
*/
|
|
48
50
|
addEventListener(type, listener, options) {
|
|
51
|
+
if (!this.listeners_) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
49
54
|
this.listeners_.push(type, listener);
|
|
50
55
|
}
|
|
51
56
|
|
|
@@ -73,6 +78,9 @@ shaka.util.FakeEventTarget = class {
|
|
|
73
78
|
* @exportInterface
|
|
74
79
|
*/
|
|
75
80
|
removeEventListener(type, listener, options) {
|
|
81
|
+
if (!this.listeners_) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
76
84
|
this.listeners_.remove(type, listener);
|
|
77
85
|
}
|
|
78
86
|
|
|
@@ -90,6 +98,10 @@ shaka.util.FakeEventTarget = class {
|
|
|
90
98
|
goog.asserts.assert(event instanceof shaka.util.FakeEvent,
|
|
91
99
|
'FakeEventTarget can only dispatch FakeEvents!');
|
|
92
100
|
|
|
101
|
+
if (!this.listeners_) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
93
105
|
let listeners = this.listeners_.get(event.type) || [];
|
|
94
106
|
const universalListeners =
|
|
95
107
|
this.listeners_.get(shaka.util.FakeEventTarget.ALL_EVENTS_);
|
|
@@ -129,6 +141,14 @@ shaka.util.FakeEventTarget = class {
|
|
|
129
141
|
|
|
130
142
|
return event.defaultPrevented;
|
|
131
143
|
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @override
|
|
147
|
+
* @exportInterface
|
|
148
|
+
*/
|
|
149
|
+
release() {
|
|
150
|
+
this.listeners_ = null;
|
|
151
|
+
}
|
|
132
152
|
};
|
|
133
153
|
|
|
134
154
|
/**
|