shaka-player 4.8.8 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +5 -5
- package/dist/locales.js +33 -33
- package/dist/shaka-player.compiled.d.ts +39 -17
- package/dist/shaka-player.compiled.debug.d.ts +39 -17
- package/dist/shaka-player.compiled.debug.externs.js +32 -11
- package/dist/shaka-player.compiled.debug.js +574 -516
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +32 -11
- package/dist/shaka-player.compiled.js +1270 -1236
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +39 -17
- package/dist/shaka-player.ui.debug.d.ts +39 -17
- package/dist/shaka-player.ui.debug.externs.js +43 -22
- package/dist/shaka-player.ui.debug.js +601 -543
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +43 -22
- package/dist/shaka-player.ui.js +1483 -1448
- package/dist/shaka-player.ui.map +4 -4
- package/externs/shaka/manifest.js +11 -1
- package/externs/shaka/offline.js +3 -0
- package/externs/shaka/player.js +105 -12
- package/externs/tizen.js +1 -1
- package/lib/abr/simple_abr_manager.js +5 -0
- package/lib/ads/media_tailor_ad.js +11 -0
- package/lib/ads/media_tailor_ad_manager.js +37 -3
- package/lib/cea/cea608_data_channel.js +9 -0
- package/lib/cea/cea_decoder.js +6 -2
- package/lib/dash/dash_parser.js +655 -46
- package/lib/dash/mpd_utils.js +7 -8
- package/lib/dash/segment_template.js +65 -10
- package/lib/hls/hls_parser.js +92 -34
- package/lib/media/drm_engine.js +274 -40
- package/lib/media/manifest_filterer.js +10 -14
- package/lib/media/preload_manager.js +3 -10
- package/lib/media/segment_utils.js +14 -3
- package/lib/mss/mss_parser.js +2 -0
- package/lib/net/http_plugin_utils.js +2 -1
- package/lib/net/networking_engine.js +27 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +2 -0
- package/lib/offline/storage.js +1 -0
- package/lib/player.js +221 -14
- package/lib/polyfill/media_capabilities.js +10 -35
- package/lib/util/config_utils.js +74 -6
- package/lib/util/error.js +7 -0
- package/lib/util/mp4_box_parsers.js +23 -2
- package/lib/util/periods.js +51 -28
- package/lib/util/platform.js +3 -1
- package/lib/util/player_configuration.js +20 -8
- package/lib/util/stream_utils.js +62 -30
- package/lib/util/tXml.js +74 -6
- package/package.json +2 -2
- package/support.html +1 -0
- package/ui/controls.js +4 -0
- package/ui/less/ad_controls.less +2 -1
- package/ui/resolution_selection.js +12 -3
package/lib/player.js
CHANGED
|
@@ -582,6 +582,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
582
582
|
*/
|
|
583
583
|
this.trickPlayEventManager_ = new shaka.util.EventManager();
|
|
584
584
|
|
|
585
|
+
/**
|
|
586
|
+
* For listeners scoped to the lifetime of the ad manager.
|
|
587
|
+
* @private {shaka.util.EventManager}
|
|
588
|
+
*/
|
|
589
|
+
this.adManagerEventManager_ = new shaka.util.EventManager();
|
|
590
|
+
|
|
585
591
|
/** @private {shaka.net.NetworkingEngine} */
|
|
586
592
|
this.networkingEngine_ = null;
|
|
587
593
|
|
|
@@ -708,7 +714,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
708
714
|
*/
|
|
709
715
|
this.lastTextFactory_;
|
|
710
716
|
|
|
711
|
-
/** @private {
|
|
717
|
+
/** @private {shaka.extern.Resolution} */
|
|
712
718
|
this.maxHwRes_ = {width: Infinity, height: Infinity};
|
|
713
719
|
|
|
714
720
|
/** @private {!shaka.media.ManifestFilterer} */
|
|
@@ -758,14 +764,78 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
758
764
|
this.cmsdManager_ = this.createCmsd_();
|
|
759
765
|
|
|
760
766
|
this.networkingEngine_ = this.createNetworkingEngine();
|
|
767
|
+
this.networkingEngine_.setForceHTTP(this.config_.streaming.forceHTTP);
|
|
761
768
|
this.networkingEngine_.setForceHTTPS(this.config_.streaming.forceHTTPS);
|
|
762
769
|
|
|
763
770
|
/** @private {shaka.extern.IAdManager} */
|
|
764
771
|
this.adManager_ = null;
|
|
765
772
|
|
|
773
|
+
/** @private {?shaka.media.PreloadManager} */
|
|
774
|
+
this.preloadDueAdManager_ = null;
|
|
775
|
+
|
|
776
|
+
/** @private {HTMLMediaElement} */
|
|
777
|
+
this.preloadDueAdManagerVideo_ = null;
|
|
778
|
+
|
|
779
|
+
/** @private {shaka.util.Timer} */
|
|
780
|
+
this.preloadDueAdManagerTimer_ = new shaka.util.Timer(async () => {
|
|
781
|
+
if (this.preloadDueAdManager_) {
|
|
782
|
+
goog.asserts.assert(this.preloadDueAdManagerVideo_, 'Must have video');
|
|
783
|
+
await this.attach(
|
|
784
|
+
this.preloadDueAdManagerVideo_, /* initializeMediaSource= */ true);
|
|
785
|
+
await this.load(this.preloadDueAdManager_);
|
|
786
|
+
this.preloadDueAdManagerVideo_.play();
|
|
787
|
+
this.preloadDueAdManager_ = null;
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
|
|
766
791
|
if (shaka.Player.adManagerFactory_) {
|
|
767
792
|
this.adManager_ = shaka.Player.adManagerFactory_();
|
|
768
793
|
this.adManager_.configure(this.config_.ads);
|
|
794
|
+
|
|
795
|
+
// Note: we don't use shaka.ads.AdManager.AD_STARTED to avoid add a
|
|
796
|
+
// optional module in the player.
|
|
797
|
+
this.adManagerEventManager_.listen(
|
|
798
|
+
this.adManager_, 'ad-started', async (e) => {
|
|
799
|
+
if (this.config_.ads.supportsMultipleMediaElements) {
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
const event = /** @type {?google.ima.AdEvent} */
|
|
803
|
+
(e['originalEvent']);
|
|
804
|
+
if (!event) {
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
const contentPauseRequested =
|
|
808
|
+
google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED;
|
|
809
|
+
if (event.type != contentPauseRequested) {
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
this.preloadDueAdManagerTimer_.stop();
|
|
813
|
+
if (!this.preloadDueAdManager_) {
|
|
814
|
+
this.preloadDueAdManagerVideo_ = this.video_;
|
|
815
|
+
this.preloadDueAdManager_ =
|
|
816
|
+
await this.detachAndSavePreload(true);
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
// Note: we don't use shaka.ads.AdManager.AD_STOPPED to avoid add a
|
|
821
|
+
// optional module in the player.
|
|
822
|
+
this.adManagerEventManager_.listen(
|
|
823
|
+
this.adManager_, 'ad-stopped', (e) => {
|
|
824
|
+
if (this.config_.ads.supportsMultipleMediaElements) {
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
const event = /** @type {?google.ima.AdEvent} */
|
|
828
|
+
(e['originalEvent']);
|
|
829
|
+
if (!event) {
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
const contentResumeRequested =
|
|
833
|
+
google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED;
|
|
834
|
+
if (event.type != contentResumeRequested) {
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
this.preloadDueAdManagerTimer_.tickAfter(0.1);
|
|
838
|
+
});
|
|
769
839
|
}
|
|
770
840
|
|
|
771
841
|
// If the browser comes back online after being offline, then try to play
|
|
@@ -779,6 +849,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
779
849
|
this.checkVariantsTimer_ =
|
|
780
850
|
new shaka.util.Timer(() => this.checkVariants_());
|
|
781
851
|
|
|
852
|
+
/** @private {?shaka.media.PreloadManager} */
|
|
853
|
+
this.preloadNextUrl_ = null;
|
|
854
|
+
|
|
782
855
|
// Even though |attach| will start in later interpreter cycles, it should be
|
|
783
856
|
// the LAST thing we do in the constructor because conceptually it relies on
|
|
784
857
|
// player having been initialized.
|
|
@@ -913,6 +986,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
913
986
|
this.trickPlayEventManager_.release();
|
|
914
987
|
this.trickPlayEventManager_ = null;
|
|
915
988
|
}
|
|
989
|
+
if (this.adManagerEventManager_) {
|
|
990
|
+
this.adManagerEventManager_.release();
|
|
991
|
+
this.adManagerEventManager_ = null;
|
|
992
|
+
}
|
|
916
993
|
|
|
917
994
|
this.abrManagerFactory_ = null;
|
|
918
995
|
this.config_ = null;
|
|
@@ -1030,10 +1107,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1030
1107
|
}
|
|
1031
1108
|
const manifest = shaka.media.ManifestParser.probeSupport();
|
|
1032
1109
|
const media = shaka.media.MediaSourceEngine.probeSupport();
|
|
1110
|
+
const hardwareResolution =
|
|
1111
|
+
await shaka.util.Platform.detectMaxHardwareResolution();
|
|
1112
|
+
|
|
1113
|
+
/** @type {shaka.extern.SupportType} */
|
|
1033
1114
|
const ret = {
|
|
1034
|
-
manifest
|
|
1035
|
-
media
|
|
1036
|
-
drm
|
|
1115
|
+
manifest,
|
|
1116
|
+
media,
|
|
1117
|
+
drm,
|
|
1118
|
+
hardwareResolution,
|
|
1037
1119
|
};
|
|
1038
1120
|
|
|
1039
1121
|
const plugins = shaka.Player.supportPlugins_;
|
|
@@ -1301,6 +1383,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1301
1383
|
this.adManager_.onAssetUnload();
|
|
1302
1384
|
}
|
|
1303
1385
|
|
|
1386
|
+
if (this.preloadDueAdManager_ && !keepAdManager) {
|
|
1387
|
+
this.preloadDueAdManager_.destroy();
|
|
1388
|
+
this.preloadDueAdManager_ = null;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
if (!keepAdManager) {
|
|
1392
|
+
this.preloadDueAdManagerTimer_.stop();
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1304
1395
|
if (this.cmsdManager_) {
|
|
1305
1396
|
this.cmsdManager_.reset();
|
|
1306
1397
|
}
|
|
@@ -1332,6 +1423,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1332
1423
|
this.drmEngine_ = null;
|
|
1333
1424
|
}
|
|
1334
1425
|
|
|
1426
|
+
if (this.preloadNextUrl_ &&
|
|
1427
|
+
this.assetUri_ != this.preloadNextUrl_.getAssetUri()) {
|
|
1428
|
+
if (!this.preloadNextUrl_.isDestroyed()) {
|
|
1429
|
+
this.preloadNextUrl_.destroy();
|
|
1430
|
+
}
|
|
1431
|
+
this.preloadNextUrl_ = null;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1335
1434
|
this.assetUri_ = null;
|
|
1336
1435
|
this.mimeType_ = null;
|
|
1337
1436
|
this.bufferObserver_ = null;
|
|
@@ -1351,6 +1450,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1351
1450
|
}
|
|
1352
1451
|
}
|
|
1353
1452
|
|
|
1453
|
+
// On some devices, cached MediaKeySystemAccess objects may corrupt
|
|
1454
|
+
// after several playbacks, and they are not able anymore to properly
|
|
1455
|
+
// create MediaKeys objects. To prevent it, clear the cache after
|
|
1456
|
+
// each playback.
|
|
1457
|
+
if (this.config_.streaming.clearDecodingCache) {
|
|
1458
|
+
shaka.util.StreamUtils.clearDecodingConfigCache();
|
|
1459
|
+
shaka.media.DrmEngine.clearMediaKeySystemAccessMap();
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1354
1462
|
this.manifest_ = null;
|
|
1355
1463
|
this.stats_ = new shaka.util.Stats(); // Replace with a clean object.
|
|
1356
1464
|
this.lastTextFactory_ = null;
|
|
@@ -1426,6 +1534,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1426
1534
|
}
|
|
1427
1535
|
|
|
1428
1536
|
if (this.assetUri_) {
|
|
1537
|
+
// Note: This is used to avoid the destruction of the nextUrl
|
|
1538
|
+
// preloadManager that can be the current one.
|
|
1539
|
+
this.assetUri_ = assetUri;
|
|
1429
1540
|
await this.unload(/* initializeMediaSource= */ false);
|
|
1430
1541
|
}
|
|
1431
1542
|
|
|
@@ -1627,6 +1738,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1627
1738
|
// properly destroyed or released.
|
|
1628
1739
|
await preloadManager.destroy();
|
|
1629
1740
|
}
|
|
1741
|
+
this.preloadNextUrl_ = null;
|
|
1630
1742
|
}
|
|
1631
1743
|
}
|
|
1632
1744
|
|
|
@@ -1664,6 +1776,34 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1664
1776
|
*/
|
|
1665
1777
|
async unloadAndSavePreload(
|
|
1666
1778
|
initializeMediaSource = true, keepAdManager = false) {
|
|
1779
|
+
const preloadManager = await this.savePreload_();
|
|
1780
|
+
await this.unload(initializeMediaSource, keepAdManager);
|
|
1781
|
+
return preloadManager;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
/**
|
|
1785
|
+
* Detach the player from the current media element, if any, and returns a
|
|
1786
|
+
* PreloadManager that contains the loaded manifest of that asset, if any.
|
|
1787
|
+
* Allows for the asset to be re-loaded by this player faster, in the future.
|
|
1788
|
+
* When in src= mode, this detach but does not make a PreloadManager.
|
|
1789
|
+
* Leaves the player in a state where it cannot play media, until it has been
|
|
1790
|
+
* attached to something else.
|
|
1791
|
+
*
|
|
1792
|
+
* @param {boolean=} keepAdManager
|
|
1793
|
+
* @return {!Promise.<?shaka.media.PreloadManager>}
|
|
1794
|
+
* @export
|
|
1795
|
+
*/
|
|
1796
|
+
async detachAndSavePreload(keepAdManager = false) {
|
|
1797
|
+
const preloadManager = await this.savePreload_();
|
|
1798
|
+
await this.detach(keepAdManager);
|
|
1799
|
+
return preloadManager;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
/**
|
|
1803
|
+
* @return {!Promise.<?shaka.media.PreloadManager>}
|
|
1804
|
+
* @private
|
|
1805
|
+
*/
|
|
1806
|
+
async savePreload_() {
|
|
1667
1807
|
let preloadManager = null;
|
|
1668
1808
|
if (this.manifest_ && this.parser_ && this.parserFactory_ &&
|
|
1669
1809
|
this.assetUri_) {
|
|
@@ -1698,7 +1838,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1698
1838
|
this.abrManager_ = null;
|
|
1699
1839
|
this.abrManagerFactory_ = null;
|
|
1700
1840
|
}
|
|
1701
|
-
await this.unload(initializeMediaSource, keepAdManager);
|
|
1702
1841
|
return preloadManager;
|
|
1703
1842
|
}
|
|
1704
1843
|
|
|
@@ -1968,6 +2107,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1968
2107
|
// Sadly, as the network engine creation code must be replaceable by tests,
|
|
1969
2108
|
// it cannot be made and use the utilities defined in this function.
|
|
1970
2109
|
const networkingEngine = this.createNetworkingEngine(getPreloadManager);
|
|
2110
|
+
this.networkingEngine_.copyFiltersInto(networkingEngine);
|
|
1971
2111
|
|
|
1972
2112
|
/** @return {!shaka.media.DrmEngine} */
|
|
1973
2113
|
const createDrmEngine = () => {
|
|
@@ -2375,6 +2515,28 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2375
2515
|
this.loadEventManager_.listen(
|
|
2376
2516
|
mediaElement, 'timeupdate', onVideoProgress);
|
|
2377
2517
|
this.onVideoProgress_();
|
|
2518
|
+
if (this.manifest_.nextUrl) {
|
|
2519
|
+
if (this.config_.streaming.preloadNextUrlWindow > 0) {
|
|
2520
|
+
const onTimeUpdate = async () => {
|
|
2521
|
+
const timeToEnd = this.video_.duration - this.video_.currentTime;
|
|
2522
|
+
if (!isNaN(timeToEnd)) {
|
|
2523
|
+
if (timeToEnd <= this.config_.streaming.preloadNextUrlWindow) {
|
|
2524
|
+
this.loadEventManager_.unlisten(
|
|
2525
|
+
mediaElement, 'timeupdate', onTimeUpdate);
|
|
2526
|
+
goog.asserts.assert(this.manifest_.nextUrl,
|
|
2527
|
+
'this.manifest_.nextUrl should be valid.');
|
|
2528
|
+
this.preloadNextUrl_ =
|
|
2529
|
+
await this.preload(this.manifest_.nextUrl);
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
};
|
|
2533
|
+
this.loadEventManager_.listen(
|
|
2534
|
+
mediaElement, 'timeupdate', onTimeUpdate);
|
|
2535
|
+
}
|
|
2536
|
+
this.loadEventManager_.listen(mediaElement, 'ended', () => {
|
|
2537
|
+
this.load(this.preloadNextUrl_ || this.manifest_.nextUrl);
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2378
2540
|
}
|
|
2379
2541
|
|
|
2380
2542
|
if (this.adManager_) {
|
|
@@ -3412,10 +3574,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3412
3574
|
}
|
|
3413
3575
|
|
|
3414
3576
|
// If lowLatencyMode is enabled, and inaccurateManifestTolerance and
|
|
3415
|
-
// rebufferingGoal and segmentPrefetchLimit and baseDelay
|
|
3416
|
-
//
|
|
3417
|
-
// to 0
|
|
3418
|
-
//
|
|
3577
|
+
// rebufferingGoal and segmentPrefetchLimit and baseDelay and
|
|
3578
|
+
// autoCorrectDrift and maxDisabledTime are not specified, set
|
|
3579
|
+
// inaccurateManifestTolerance to 0 and rebufferingGoal to 0.01 and
|
|
3580
|
+
// segmentPrefetchLimit to 2 and updateIntervalSeconds to 0.1 and and
|
|
3581
|
+
// baseDelay to 100 and autoCorrectDrift to false and maxDisabledTime
|
|
3582
|
+
// to 1 by default for low latency streaming.
|
|
3419
3583
|
if (config['streaming'] && config['streaming']['lowLatencyMode']) {
|
|
3420
3584
|
if (config['streaming']['inaccurateManifestTolerance'] == undefined) {
|
|
3421
3585
|
config['streaming']['inaccurateManifestTolerance'] = 0;
|
|
@@ -3429,6 +3593,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3429
3593
|
if (config['streaming']['updateIntervalSeconds'] == undefined) {
|
|
3430
3594
|
config['streaming']['updateIntervalSeconds'] = 0.1;
|
|
3431
3595
|
}
|
|
3596
|
+
if (config['streaming']['maxDisabledTime'] == undefined) {
|
|
3597
|
+
config['streaming']['maxDisabledTime'] = 1;
|
|
3598
|
+
}
|
|
3432
3599
|
if (config['streaming']['retryParameters'] == undefined) {
|
|
3433
3600
|
config['streaming']['retryParameters'] = {};
|
|
3434
3601
|
}
|
|
@@ -3438,6 +3605,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3438
3605
|
if (config['manifest'] == undefined) {
|
|
3439
3606
|
config['manifest'] = {};
|
|
3440
3607
|
}
|
|
3608
|
+
if (config['manifest']['dash'] == undefined) {
|
|
3609
|
+
config['manifest']['dash'] = {};
|
|
3610
|
+
}
|
|
3611
|
+
if (config['manifest']['dash']['autoCorrectDrift'] == undefined) {
|
|
3612
|
+
config['manifest']['dash']['autoCorrectDrift'] = false;
|
|
3613
|
+
}
|
|
3441
3614
|
if (config['manifest']['retryParameters'] == undefined) {
|
|
3442
3615
|
config['manifest']['retryParameters'] = {};
|
|
3443
3616
|
}
|
|
@@ -3512,6 +3685,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3512
3685
|
}
|
|
3513
3686
|
}
|
|
3514
3687
|
if (this.networkingEngine_) {
|
|
3688
|
+
this.networkingEngine_.setForceHTTP(this.config_.streaming.forceHTTP);
|
|
3515
3689
|
this.networkingEngine_.setForceHTTPS(this.config_.streaming.forceHTTPS);
|
|
3516
3690
|
}
|
|
3517
3691
|
|
|
@@ -3599,6 +3773,24 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
3599
3773
|
return ret;
|
|
3600
3774
|
}
|
|
3601
3775
|
|
|
3776
|
+
/**
|
|
3777
|
+
* Return a copy of the current non default configuration. Modifications of
|
|
3778
|
+
* the returned value will not affect the Player's active configuration.
|
|
3779
|
+
* You must call <code>player.configure()</code> to make changes.
|
|
3780
|
+
*
|
|
3781
|
+
* @return {!Object}
|
|
3782
|
+
* @export
|
|
3783
|
+
*/
|
|
3784
|
+
getNonDefaultConfiguration() {
|
|
3785
|
+
goog.asserts.assert(this.config_, 'Config must not be null!');
|
|
3786
|
+
|
|
3787
|
+
const ret = this.defaultConfig_();
|
|
3788
|
+
shaka.util.PlayerConfiguration.mergeConfigObjects(
|
|
3789
|
+
ret, this.config_, this.defaultConfig_());
|
|
3790
|
+
return shaka.util.ConfigUtils.getDifferenceFromConfigObjects(
|
|
3791
|
+
this.config_, this.defaultConfig_());
|
|
3792
|
+
}
|
|
3793
|
+
|
|
3602
3794
|
/**
|
|
3603
3795
|
* Return a reference to the current configuration. Modifications to the
|
|
3604
3796
|
* returned value will affect the Player's active configuration. This method
|
|
@@ -5733,6 +5925,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5733
5925
|
error.code == shaka.util.Error.Code.HTTP_ERROR) {
|
|
5734
5926
|
// These errors can be near-instant, so delay a bit before retrying.
|
|
5735
5927
|
retryDelaySeconds = 1;
|
|
5928
|
+
if (this.config_.streaming.lowLatencyMode) {
|
|
5929
|
+
retryDelaySeconds = 0.1;
|
|
5930
|
+
}
|
|
5736
5931
|
} else if (error.code == shaka.util.Error.Code.TIMEOUT) {
|
|
5737
5932
|
// We already waited for a timeout, so retry quickly.
|
|
5738
5933
|
retryDelaySeconds = 0.1;
|
|
@@ -6026,8 +6221,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6026
6221
|
// serviceDescription must override if it is defined in the MPD and
|
|
6027
6222
|
// liveSync configuration is not set.
|
|
6028
6223
|
if (this.manifest_ && this.manifest_.serviceDescription) {
|
|
6029
|
-
liveSyncMaxLatency = this.
|
|
6030
|
-
|
|
6224
|
+
liveSyncMaxLatency = this.config_.streaming.liveSyncMaxLatency;
|
|
6225
|
+
if (this.manifest_.serviceDescription.targetLatency != null) {
|
|
6226
|
+
liveSyncMaxLatency =
|
|
6227
|
+
this.manifest_.serviceDescription.targetLatency +
|
|
6228
|
+
this.config_.streaming.liveSyncTargetLatencyTolerance;
|
|
6229
|
+
} else if (this.manifest_.serviceDescription.maxLatency != null) {
|
|
6230
|
+
liveSyncMaxLatency = this.manifest_.serviceDescription.maxLatency;
|
|
6231
|
+
}
|
|
6031
6232
|
liveSyncPlaybackRate =
|
|
6032
6233
|
this.manifest_.serviceDescription.maxPlaybackRate ||
|
|
6033
6234
|
this.config_.streaming.liveSyncPlaybackRate;
|
|
@@ -6043,8 +6244,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6043
6244
|
// serviceDescription must override if it is defined in the MPD and
|
|
6044
6245
|
// liveSync configuration is not set.
|
|
6045
6246
|
if (this.manifest_ && this.manifest_.serviceDescription) {
|
|
6046
|
-
liveSyncMinLatency = this.
|
|
6047
|
-
|
|
6247
|
+
liveSyncMinLatency = this.config_.streaming.liveSyncMinLatency;
|
|
6248
|
+
if (this.manifest_.serviceDescription.targetLatency != null) {
|
|
6249
|
+
liveSyncMinLatency =
|
|
6250
|
+
this.manifest_.serviceDescription.targetLatency -
|
|
6251
|
+
this.config_.streaming.liveSyncTargetLatencyTolerance;
|
|
6252
|
+
} else if (this.manifest_.serviceDescription.minLatency != null) {
|
|
6253
|
+
liveSyncMinLatency = this.manifest_.serviceDescription.minLatency;
|
|
6254
|
+
}
|
|
6048
6255
|
liveSyncMinPlaybackRate =
|
|
6049
6256
|
this.manifest_.serviceDescription.minPlaybackRate ||
|
|
6050
6257
|
this.config_.streaming.liveSyncMinPlaybackRate;
|
|
@@ -7239,7 +7446,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7239
7446
|
* @export
|
|
7240
7447
|
*/
|
|
7241
7448
|
// eslint-disable-next-line no-useless-concat
|
|
7242
|
-
shaka.Player.version = 'v4.
|
|
7449
|
+
shaka.Player.version = 'v4.9.0' + '-uncompiled'; // x-release-please-version
|
|
7243
7450
|
|
|
7244
7451
|
// Initialize the deprecation system using the version string we just set
|
|
7245
7452
|
// on the player.
|
|
@@ -8,6 +8,7 @@ goog.provide('shaka.polyfill.MediaCapabilities');
|
|
|
8
8
|
|
|
9
9
|
goog.require('shaka.log');
|
|
10
10
|
goog.require('shaka.media.Capabilities');
|
|
11
|
+
goog.require('shaka.media.DrmEngine');
|
|
11
12
|
goog.require('shaka.polyfill');
|
|
12
13
|
goog.require('shaka.util.Platform');
|
|
13
14
|
|
|
@@ -276,25 +277,22 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
276
277
|
mediaKeySystemConfig.videoCapabilities = videoCapabilities;
|
|
277
278
|
}
|
|
278
279
|
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
audioConfig ? audioConfig.contentType : '',
|
|
283
|
-
mcapKeySystemConfig.keySystem);
|
|
280
|
+
const videoCodec = videoConfig ? videoConfig.contentType : '';
|
|
281
|
+
const audioCodec = audioConfig ? audioConfig.contentType : '';
|
|
282
|
+
const keySystem = mcapKeySystemConfig.keySystem;
|
|
284
283
|
|
|
285
284
|
/** @type {MediaKeySystemAccess} */
|
|
286
285
|
let keySystemAccess = null;
|
|
287
286
|
try {
|
|
288
|
-
if (
|
|
289
|
-
|
|
290
|
-
keySystemAccess = shaka.
|
|
291
|
-
|
|
287
|
+
if (shaka.media.DrmEngine.hasMediaKeySystemAccess(
|
|
288
|
+
videoCodec, audioCodec, keySystem)) {
|
|
289
|
+
keySystemAccess = shaka.media.DrmEngine.getMediaKeySystemAccess(
|
|
290
|
+
videoCodec, audioCodec, keySystem);
|
|
292
291
|
} else {
|
|
293
292
|
keySystemAccess = await navigator.requestMediaKeySystemAccess(
|
|
294
293
|
mcapKeySystemConfig.keySystem, [mediaKeySystemConfig]);
|
|
295
|
-
shaka.
|
|
296
|
-
|
|
297
|
-
keySystemAccess;
|
|
294
|
+
shaka.media.DrmEngine.setMediaKeySystemAccess(
|
|
295
|
+
videoCodec, audioCodec, keySystem, keySystemAccess);
|
|
298
296
|
}
|
|
299
297
|
} catch (e) {
|
|
300
298
|
shaka.log.info('navigator.requestMediaKeySystemAccess failed.');
|
|
@@ -346,19 +344,6 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
346
344
|
}
|
|
347
345
|
return result;
|
|
348
346
|
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* A method for generating a key for the MediaKeySystemAccessRequests cache.
|
|
352
|
-
*
|
|
353
|
-
* @param {!string} videoCodec
|
|
354
|
-
* @param {!string} audioCodec
|
|
355
|
-
* @param {!string} keySystem
|
|
356
|
-
* @return {!string}
|
|
357
|
-
* @private
|
|
358
|
-
*/
|
|
359
|
-
static generateKeySystemCacheKey_(videoCodec, audioCodec, keySystem) {
|
|
360
|
-
return `${videoCodec}#${audioCodec}#${keySystem}`;
|
|
361
|
-
}
|
|
362
347
|
};
|
|
363
348
|
|
|
364
349
|
/**
|
|
@@ -371,16 +356,6 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
371
356
|
*/
|
|
372
357
|
shaka.polyfill.MediaCapabilities.originalMcap = null;
|
|
373
358
|
|
|
374
|
-
/**
|
|
375
|
-
* A cache that stores the MediaKeySystemAccess result of calling
|
|
376
|
-
* `navigator.requestMediaKeySystemAccess` by a key combination of
|
|
377
|
-
* video/audio codec and key system string.
|
|
378
|
-
*
|
|
379
|
-
* @type {(Object<(!string), (!MediaKeySystemAccess)>)}
|
|
380
|
-
* @export
|
|
381
|
-
*/
|
|
382
|
-
shaka.polyfill.MediaCapabilities.memoizedMediaKeySystemAccessRequests_ = {};
|
|
383
|
-
|
|
384
359
|
/**
|
|
385
360
|
* A cache that stores the canDisplayType result of calling
|
|
386
361
|
* `cast.__platform__.canDisplayType`.
|
package/lib/util/config_utils.js
CHANGED
|
@@ -28,17 +28,28 @@ shaka.util.ConfigUtils = class {
|
|
|
28
28
|
static mergeConfigObjects(destination, source, template, overrides, path) {
|
|
29
29
|
goog.asserts.assert(destination, 'Destination config must not be null!');
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
// If true, override the template.
|
|
32
|
+
const overrideTemplate = path in overrides;
|
|
33
|
+
|
|
34
|
+
// If true, treat the source as a generic object to be copied without
|
|
35
|
+
// descending more deeply.
|
|
36
|
+
let genericObject = false;
|
|
37
|
+
if (overrideTemplate) {
|
|
38
|
+
genericObject = template.constructor == Object &&
|
|
39
|
+
Object.keys(overrides).length == 0;
|
|
40
|
+
} else {
|
|
41
|
+
genericObject = template.constructor == Object &&
|
|
42
|
+
Object.keys(template).length == 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// If true, don't validate the keys in the next level.
|
|
46
|
+
const ignoreKeys = overrideTemplate || genericObject;
|
|
36
47
|
|
|
37
48
|
let isValid = true;
|
|
38
49
|
|
|
39
50
|
for (const k in source) {
|
|
40
51
|
const subPath = path + '.' + k;
|
|
41
|
-
const subTemplate =
|
|
52
|
+
const subTemplate = overrideTemplate ? overrides[path] : template[k];
|
|
42
53
|
|
|
43
54
|
// The order of these checks is important.
|
|
44
55
|
if (!ignoreKeys && !(k in template)) {
|
|
@@ -55,6 +66,10 @@ shaka.util.ConfigUtils = class {
|
|
|
55
66
|
// There is something in the template, so go back to that.
|
|
56
67
|
destination[k] = shaka.util.ObjectUtils.cloneObject(subTemplate);
|
|
57
68
|
}
|
|
69
|
+
} else if (genericObject) {
|
|
70
|
+
// Copy the fields of a generic object directly without a template and
|
|
71
|
+
// without descending any deeper.
|
|
72
|
+
destination[k] = source[k];
|
|
58
73
|
} else if (subTemplate.constructor == Object &&
|
|
59
74
|
source[k] &&
|
|
60
75
|
source[k].constructor == Object) {
|
|
@@ -152,4 +167,57 @@ shaka.util.ConfigUtils = class {
|
|
|
152
167
|
static referenceParametersAndReturn(parameters, returnValue) {
|
|
153
168
|
return parameters && returnValue;
|
|
154
169
|
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @param {!Object} object
|
|
173
|
+
* @param {!Object} base
|
|
174
|
+
* @return {!Object}
|
|
175
|
+
* @export
|
|
176
|
+
*/
|
|
177
|
+
static getDifferenceFromConfigObjects(object, base) {
|
|
178
|
+
const isObject = (obj) => {
|
|
179
|
+
return obj && typeof obj === 'object' && !Array.isArray(obj);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const isArrayEmpty = (array) => {
|
|
183
|
+
return Array.isArray(array) && array.length === 0;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const changes = (object, base) => {
|
|
187
|
+
return Object.keys(object).reduce((acc, key) => {
|
|
188
|
+
const value = object[key];
|
|
189
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
190
|
+
if (!base.hasOwnProperty(key)) {
|
|
191
|
+
acc[key] = value;
|
|
192
|
+
} else if (isObject(value) && isObject(base[key])) {
|
|
193
|
+
const diff = changes(value, base[key]);
|
|
194
|
+
if (Object.keys(diff).length > 0 || !isObject(diff)) {
|
|
195
|
+
acc[key] = diff;
|
|
196
|
+
}
|
|
197
|
+
} else if (isArrayEmpty(value) && isArrayEmpty(base[key])) {
|
|
198
|
+
// Do nothing if both are empty arrays
|
|
199
|
+
} else if (value !== base[key]) {
|
|
200
|
+
acc[key] = value;
|
|
201
|
+
}
|
|
202
|
+
return acc;
|
|
203
|
+
}, {});
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const diff = changes(object, base);
|
|
207
|
+
|
|
208
|
+
const removeEmpty = (obj) => {
|
|
209
|
+
for (const key of Object.keys(obj)) {
|
|
210
|
+
if (isObject(obj[key]) && Object.keys(obj[key]).length === 0) {
|
|
211
|
+
delete obj[key];
|
|
212
|
+
} else if (isArrayEmpty(obj[key])) {
|
|
213
|
+
delete obj[key];
|
|
214
|
+
} else if (isObject(obj[key])) {
|
|
215
|
+
removeEmpty(obj[key]);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
removeEmpty(diff);
|
|
221
|
+
return diff;
|
|
222
|
+
}
|
|
155
223
|
};
|
package/lib/util/error.js
CHANGED
|
@@ -212,6 +212,8 @@ shaka.util.Error.Code = {
|
|
|
212
212
|
* <br> error.data[3] is the map of response headers.
|
|
213
213
|
* <br> error.data[4] is the NetworkingEngine.RequestType of the request,
|
|
214
214
|
* if one was provided.
|
|
215
|
+
* <br> error.data[5] is the final URI. This may be different if the initial
|
|
216
|
+
* URI (error.data[0]) issued a redirect.
|
|
215
217
|
*/
|
|
216
218
|
'BAD_HTTP_STATUS': 1001,
|
|
217
219
|
|
|
@@ -770,6 +772,11 @@ shaka.util.Error.Code = {
|
|
|
770
772
|
*/
|
|
771
773
|
'DASH_UNSUPPORTED_AES_128': 4051,
|
|
772
774
|
|
|
775
|
+
/**
|
|
776
|
+
* Patch requested during an update did not match original manifest.
|
|
777
|
+
*/
|
|
778
|
+
'DASH_INVALID_PATCH': 4052,
|
|
779
|
+
|
|
773
780
|
|
|
774
781
|
// RETIRED: 'INCONSISTENT_BUFFER_STATE': 5000,
|
|
775
782
|
// RETIRED: 'INVALID_SEGMENT_INDEX': 5001,
|
|
@@ -555,6 +555,7 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
555
555
|
* @return {!shaka.util.ParsedCOLRBox}
|
|
556
556
|
*/
|
|
557
557
|
static parseCOLR(reader) {
|
|
558
|
+
let colorGamut = null;
|
|
558
559
|
let videoRange = null;
|
|
559
560
|
const data = reader.readBytes(4);
|
|
560
561
|
let colorType = '';
|
|
@@ -563,7 +564,22 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
563
564
|
colorType += String.fromCharCode(data[2]);
|
|
564
565
|
colorType += String.fromCharCode(data[3]);
|
|
565
566
|
if (colorType === 'nclx') {
|
|
566
|
-
reader.readUint16();
|
|
567
|
+
const colorPrimaries = reader.readUint16();
|
|
568
|
+
switch (colorPrimaries) {
|
|
569
|
+
case 1:
|
|
570
|
+
case 5:
|
|
571
|
+
case 6:
|
|
572
|
+
case 7:
|
|
573
|
+
colorGamut = 'srgb';
|
|
574
|
+
break;
|
|
575
|
+
case 9:
|
|
576
|
+
colorGamut = 'rec2020';
|
|
577
|
+
break;
|
|
578
|
+
case 11:
|
|
579
|
+
case 12:
|
|
580
|
+
colorGamut = 'p3';
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
567
583
|
const transferCharacteristics = reader.readUint16();
|
|
568
584
|
reader.readUint16(); // matrix_coefficients
|
|
569
585
|
switch (transferCharacteristics) {
|
|
@@ -582,7 +598,10 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
582
598
|
break;
|
|
583
599
|
}
|
|
584
600
|
}
|
|
585
|
-
return {
|
|
601
|
+
return {
|
|
602
|
+
colorGamut,
|
|
603
|
+
videoRange,
|
|
604
|
+
};
|
|
586
605
|
}
|
|
587
606
|
|
|
588
607
|
/**
|
|
@@ -913,9 +932,11 @@ shaka.util.ParsedHFOVBox;
|
|
|
913
932
|
|
|
914
933
|
/**
|
|
915
934
|
* @typedef {{
|
|
935
|
+
* colorGamut: ?string,
|
|
916
936
|
* videoRange: ?string
|
|
917
937
|
* }}
|
|
918
938
|
*
|
|
939
|
+
* @property {?string} colorGamut
|
|
919
940
|
* @property {?string} videoRange
|
|
920
941
|
*
|
|
921
942
|
* @exportDoc
|