shaka-player 4.9.34 → 4.9.36

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.
Files changed (79) hide show
  1. package/AUTHORS +1 -0
  2. package/CONTRIBUTORS +1 -0
  3. package/README.md +9 -3
  4. package/dist/controls.css +1 -1
  5. package/dist/controls.css.map +1 -1
  6. package/dist/deps.js +6 -6
  7. package/dist/locales.js +31 -31
  8. package/dist/shaka-player.compiled.d.ts +1 -0
  9. package/dist/shaka-player.compiled.debug.d.ts +1 -0
  10. package/dist/shaka-player.compiled.debug.externs.js +4 -3
  11. package/dist/shaka-player.compiled.debug.js +445 -427
  12. package/dist/shaka-player.compiled.debug.map +3 -3
  13. package/dist/shaka-player.compiled.externs.js +4 -3
  14. package/dist/shaka-player.compiled.js +1254 -1240
  15. package/dist/shaka-player.compiled.map +3 -3
  16. package/dist/shaka-player.dash.d.ts +4099 -0
  17. package/dist/shaka-player.dash.debug.d.ts +4099 -0
  18. package/dist/shaka-player.dash.debug.externs.js +4188 -0
  19. package/dist/shaka-player.dash.debug.js +2161 -0
  20. package/dist/shaka-player.dash.debug.map +8 -0
  21. package/dist/shaka-player.dash.externs.js +4188 -0
  22. package/dist/shaka-player.dash.js +1007 -0
  23. package/dist/shaka-player.dash.map +8 -0
  24. package/dist/shaka-player.hls.d.ts +4196 -0
  25. package/dist/shaka-player.hls.debug.d.ts +4196 -0
  26. package/dist/shaka-player.hls.debug.externs.js +4403 -0
  27. package/dist/shaka-player.hls.debug.js +2243 -0
  28. package/dist/shaka-player.hls.debug.map +8 -0
  29. package/dist/shaka-player.hls.externs.js +4403 -0
  30. package/dist/shaka-player.hls.js +1076 -0
  31. package/dist/shaka-player.hls.map +8 -0
  32. package/dist/shaka-player.ui.d.ts +1 -0
  33. package/dist/shaka-player.ui.debug.d.ts +1 -0
  34. package/dist/shaka-player.ui.debug.externs.js +4 -3
  35. package/dist/shaka-player.ui.debug.js +472 -454
  36. package/dist/shaka-player.ui.debug.map +3 -3
  37. package/dist/shaka-player.ui.externs.js +4 -3
  38. package/dist/shaka-player.ui.js +1495 -1484
  39. package/dist/shaka-player.ui.map +3 -3
  40. package/externs/shaka/player.js +8 -4
  41. package/lib/cast/cast_proxy.js +48 -10
  42. package/lib/cea/cea708_service.js +20 -2
  43. package/lib/cea/dtvcc_packet_builder.js +15 -0
  44. package/lib/dash/dash_parser.js +24 -13
  45. package/lib/dash/mpd_utils.js +7 -4
  46. package/lib/dash/segment_template.js +74 -56
  47. package/lib/hls/hls_parser.js +5 -4
  48. package/lib/hls/manifest_text_parser.js +1 -0
  49. package/lib/media/content_workarounds.js +110 -72
  50. package/lib/media/drm_engine.js +72 -11
  51. package/lib/media/gap_jumping_controller.js +14 -1
  52. package/lib/media/media_source_engine.js +29 -11
  53. package/lib/media/region_timeline.js +4 -3
  54. package/lib/media/segment_utils.js +28 -16
  55. package/lib/media/streaming_engine.js +38 -12
  56. package/lib/net/http_fetch_plugin.js +1 -1
  57. package/lib/net/http_plugin_utils.js +4 -1
  58. package/lib/net/networking_engine.js +8 -0
  59. package/lib/net/networking_utils.js +1 -0
  60. package/lib/player.js +109 -37
  61. package/lib/polyfill/patchedmediakeys_apple.js +21 -0
  62. package/lib/text/cue.js +6 -2
  63. package/lib/text/mp4_ttml_parser.js +94 -6
  64. package/lib/text/ui_text_displayer.js +35 -4
  65. package/lib/transmuxer/ac3_transmuxer.js +6 -1
  66. package/lib/util/config_utils.js +13 -3
  67. package/lib/util/drm_utils.js +8 -0
  68. package/lib/util/error.js +6 -0
  69. package/lib/util/mp4_generator.js +19 -4
  70. package/lib/util/periods.js +4 -2
  71. package/lib/util/platform.js +60 -12
  72. package/lib/util/player_configuration.js +13 -2
  73. package/lib/util/stream_utils.js +18 -0
  74. package/lib/util/tXml.js +3 -2
  75. package/package.json +3 -3
  76. package/ui/controls.js +2 -6
  77. package/ui/less/thumbnails.less +1 -0
  78. package/ui/statistics_button.js +3 -1
  79. package/ui/ui.js +44 -35
@@ -8,6 +8,7 @@ goog.provide('shaka.util.Mp4Generator');
8
8
 
9
9
  goog.require('goog.asserts');
10
10
  goog.require('shaka.util.ManifestParserUtils');
11
+ goog.require('shaka.util.Platform');
11
12
  goog.require('shaka.util.Uint8ArrayUtils');
12
13
 
13
14
 
@@ -298,6 +299,20 @@ shaka.util.Mp4Generator = class {
298
299
  stsd_(streamInfo) {
299
300
  const Mp4Generator = shaka.util.Mp4Generator;
300
301
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
302
+ let audioCodec = 'aac';
303
+ if (streamInfo.codecs.includes('mp3')) {
304
+ audioCodec = 'mp3';
305
+ } else if (streamInfo.codecs.includes('ac-3')) {
306
+ if (shaka.util.Platform.requiresEC3InitSegments()) {
307
+ audioCodec = 'ec-3';
308
+ } else {
309
+ audioCodec = 'ac-3';
310
+ }
311
+ } else if (streamInfo.codecs.includes('ec-3')) {
312
+ audioCodec = 'ec-3';
313
+ } else if (streamInfo.codecs.includes('opus')) {
314
+ audioCodec = 'opus';
315
+ }
301
316
  let bytes = new Uint8Array([]);
302
317
  switch (streamInfo.type) {
303
318
  case ContentType.VIDEO:
@@ -308,13 +323,13 @@ shaka.util.Mp4Generator = class {
308
323
  }
309
324
  break;
310
325
  case ContentType.AUDIO:
311
- if (streamInfo.codecs.includes('mp3')) {
326
+ if (audioCodec == 'mp3') {
312
327
  bytes = this.mp3_(streamInfo);
313
- } else if (streamInfo.codecs.includes('ac-3')) {
328
+ } else if (audioCodec == 'ac-3') {
314
329
  bytes = this.ac3_(streamInfo);
315
- } else if (streamInfo.codecs.includes('ec-3')) {
330
+ } else if (audioCodec == 'ec-3') {
316
331
  bytes = this.ec3_(streamInfo);
317
- } else if (streamInfo.codecs.includes('opus')) {
332
+ } else if (audioCodec == 'opus') {
318
333
  bytes = this.opus_(streamInfo);
319
334
  } else {
320
335
  bytes = this.mp4a_(streamInfo);
@@ -836,7 +836,7 @@ shaka.util.PeriodCombiner = class {
836
836
  clone.roles = clone.roles.slice();
837
837
  clone.segmentIndex = null;
838
838
  clone.emsgSchemeIdUris = [];
839
- clone.keyIds = new Set();
839
+ clone.keyIds = new Set(stream.keyIds);
840
840
  clone.closedCaptions = stream.closedCaptions ?
841
841
  new Map(stream.closedCaptions) : null;
842
842
  clone.trickModeVideo = null;
@@ -860,7 +860,7 @@ shaka.util.PeriodCombiner = class {
860
860
  clone.roles = clone.roles.slice();
861
861
  // These are wiped out now and rebuilt later from the various per-period
862
862
  // streams that match this output.
863
- clone.keyIds = new Set();
863
+ clone.keyIds = new Set(streamDb.keyIds);
864
864
  clone.segments = [];
865
865
  clone.variantIds = [];
866
866
  clone.closedCaptions = streamDb.closedCaptions ?
@@ -1772,6 +1772,7 @@ shaka.util.PeriodCombiner = class {
1772
1772
  v.roles,
1773
1773
  v.closedCaptions ? Array.from(v.closedCaptions.entries()) : null,
1774
1774
  v.bandwidth,
1775
+ Array.from(v.keyIds),
1775
1776
  ]);
1776
1777
  }
1777
1778
 
@@ -1794,6 +1795,7 @@ shaka.util.PeriodCombiner = class {
1794
1795
  a.roles,
1795
1796
  a.audioSamplingRate,
1796
1797
  a.primary,
1798
+ Array.from(a.keyIds),
1797
1799
  ]);
1798
1800
  }
1799
1801
 
@@ -307,13 +307,15 @@ shaka.util.Platform = class {
307
307
  !shaka.util.Platform.isTizen() &&
308
308
  !shaka.util.Platform.isEOS() &&
309
309
  !shaka.util.Platform.isAPL() &&
310
+ !shaka.util.Platform.isAPP() &&
310
311
  !shaka.util.Platform.isVirginMedia() &&
311
312
  !shaka.util.Platform.isOrange() &&
312
313
  !shaka.util.Platform.isPS4() &&
313
314
  !shaka.util.Platform.isAmazonFireTV() &&
314
315
  !shaka.util.Platform.isComcastX1() &&
315
316
  !shaka.util.Platform.isZenterio() &&
316
- !shaka.util.Platform.isSkyQ();
317
+ !shaka.util.Platform.isSkyQ() &&
318
+ !shaka.util.Platform.isMultiChoice();
317
319
  }
318
320
 
319
321
  /**
@@ -391,6 +393,16 @@ shaka.util.Platform = class {
391
393
  return shaka.util.Platform.userAgentContains_('DT_STB_BCM');
392
394
  }
393
395
 
396
+ /**
397
+ * Check if the current platform is a MultiChoice STB.
398
+ * @return {boolean}
399
+ */
400
+ static isMultiChoice() {
401
+ // cspell: ignore MDMP
402
+ return shaka.util.Platform.userAgentContains_('MDMP1001S') ||
403
+ shaka.util.Platform.userAgentContains_('PS5525IMC');
404
+ }
405
+
394
406
  /**
395
407
  * Returns a major version number for Safari, or Safari-based iOS browsers.
396
408
  *
@@ -456,6 +468,14 @@ shaka.util.Platform = class {
456
468
  return shaka.util.Platform.userAgentContains_('PC=APL');
457
469
  }
458
470
 
471
+ /**
472
+ * Check if the current platform is an APPSTB set-top box.
473
+ * @return {boolean}
474
+ */
475
+ static isAPP() {
476
+ return shaka.util.Platform.userAgentContains_('PC=APPSTB');
477
+ }
478
+
459
479
  /**
460
480
  * Guesses if the platform is a mobile one (iOS or Android).
461
481
  *
@@ -523,6 +543,9 @@ shaka.util.Platform = class {
523
543
  * @return {boolean}
524
544
  */
525
545
  static isAndroid() {
546
+ if (navigator.userAgentData && navigator.userAgentData.platform) {
547
+ return navigator.userAgentData.platform.toLowerCase() == 'android';
548
+ }
526
549
  return shaka.util.Platform.userAgentContains_('Android');
527
550
  }
528
551
 
@@ -532,6 +555,9 @@ shaka.util.Platform = class {
532
555
  * @return {boolean}
533
556
  */
534
557
  static isFuchsia() {
558
+ if (navigator.userAgentData && navigator.userAgentData.platform) {
559
+ return navigator.userAgentData.platform.toLowerCase() == 'fuchsia';
560
+ }
535
561
  return shaka.util.Platform.userAgentContains_('Fuchsia');
536
562
  }
537
563
 
@@ -548,7 +574,8 @@ shaka.util.Platform = class {
548
574
  Platform.isEOS() || Platform.isAPL() ||
549
575
  Platform.isVirginMedia() || Platform.isOrange() ||
550
576
  Platform.isComcastX1() || Platform.isChromecast() ||
551
- Platform.isHisense() || Platform.isZenterio()) {
577
+ Platform.isHisense() || Platform.isZenterio() ||
578
+ Platform.isAPP() || Platform.isMultiChoice()) {
552
579
  return true;
553
580
  }
554
581
  return false;
@@ -621,6 +648,19 @@ shaka.util.Platform = class {
621
648
  (Platform.isEdge() && Platform.isWindows() && isPlayReady);
622
649
  }
623
650
 
651
+ /**
652
+ * Returns true if the platform requires AC-3 signalling in init
653
+ * segments to be replaced with EC-3 signalling.
654
+ * For such platforms, MediaSourceEngine will attempt to work
655
+ * around it by inserting fake EC-3 signalling into
656
+ * initialization segments.
657
+ *
658
+ * @return {boolean}
659
+ */
660
+ static requiresEC3InitSegments() {
661
+ return shaka.util.Platform.isTizen3();
662
+ }
663
+
624
664
  /**
625
665
  * Returns true if the platform supports SourceBuffer "sequence mode".
626
666
  *
@@ -629,7 +669,7 @@ shaka.util.Platform = class {
629
669
  static supportsSequenceMode() {
630
670
  const Platform = shaka.util.Platform;
631
671
  if (Platform.isTizen3() || Platform.isTizen2() ||
632
- Platform.isWebOS3() || Platform.isPS4()) {
672
+ Platform.isWebOS3() || Platform.isPS4() || Platform.isPS5()) {
633
673
  return false;
634
674
  }
635
675
  return true;
@@ -685,16 +725,13 @@ shaka.util.Platform = class {
685
725
  }
686
726
 
687
727
  /**
688
- * Returns true if MediaKeys is polyfilled
728
+ * Returns true if MediaKeys is polyfilled by the specified polyfill.
689
729
  *
690
- * @param {string=} polyfillType
730
+ * @param {string} polyfillType
691
731
  * @return {boolean}
692
732
  */
693
733
  static isMediaKeysPolyfilled(polyfillType) {
694
- if (polyfillType) {
695
- return polyfillType === window.shakaMediaKeysPolyfill;
696
- }
697
- return !!window.shakaMediaKeysPolyfill;
734
+ return polyfillType === window.shakaMediaKeysPolyfill;
698
735
  }
699
736
 
700
737
 
@@ -780,10 +817,21 @@ shaka.util.Platform = class {
780
817
  maxResolution.height = 1080;
781
818
  }
782
819
  } else if (Platform.isHisense()) {
783
- // eslint-disable-next-line new-cap
784
- if (window.Hisense_Get4KSupportState &&
820
+ let supports4k = null;
821
+ if (window.Hisense_Get4KSupportState) {
822
+ try {
785
823
  // eslint-disable-next-line new-cap
786
- window.Hisense_Get4KSupportState()) {
824
+ supports4k = window.Hisense_Get4KSupportState();
825
+ } catch (e) {
826
+ shaka.log.debug('Hisense: Failed to get 4K support state', e);
827
+ }
828
+ }
829
+ if (supports4k == null) {
830
+ // If API is not there or not working for whatever reason, fallback to
831
+ // user agent check, as it contains UHD or FHD info.
832
+ supports4k = Platform.userAgentContains_('UHD');
833
+ }
834
+ if (supports4k) {
787
835
  maxResolution.width = 3840;
788
836
  maxResolution.height = 2160;
789
837
  } else {
@@ -73,7 +73,7 @@ shaka.util.PlayerConfiguration = class {
73
73
  persistentSessionOnlinePlayback: false,
74
74
  persistentSessionsMetadata: [],
75
75
  initDataTransform: (initData, initDataType, drmInfo) => {
76
- if (shaka.util.Platform.isMediaKeysPolyfilled() &&
76
+ if (shaka.util.Platform.isMediaKeysPolyfilled('apple') &&
77
77
  initDataType == 'skd') {
78
78
  const cert = drmInfo.serverCertificate;
79
79
  const contentId =
@@ -261,6 +261,11 @@ shaka.util.PlayerConfiguration = class {
261
261
  shaka.util.Platform.isPS5(),
262
262
  };
263
263
 
264
+ const safariVersion = shaka.util.Platform.safariVersion();
265
+ if (safariVersion && safariVersion >= 17) {
266
+ streaming.infiniteLiveStreamDuration = true;
267
+ }
268
+
264
269
  // WebOS, Tizen, Chromecast and Hisense have long hardware pipelines
265
270
  // that respond slowly to seeking.
266
271
  // Therefore we should not seek when we detect a stall
@@ -517,7 +522,13 @@ shaka.util.PlayerConfiguration = class {
517
522
  if (hdrLevel == 'AUTO') {
518
523
  // Auto detect the ideal HDR level.
519
524
  if (window.matchMedia('(color-gamut: p3)').matches) {
520
- hdrLevel = 'PQ';
525
+ const someHLG = tracks.some((track) => {
526
+ if (track.hdr && track.hdr == 'HLG') {
527
+ return true;
528
+ }
529
+ return false;
530
+ });
531
+ hdrLevel = someHLG ? 'HLG' : 'PQ';
521
532
  } else {
522
533
  hdrLevel = 'SDR';
523
534
  }
@@ -996,6 +996,11 @@ shaka.util.StreamUtils = class {
996
996
  }
997
997
  }
998
998
 
999
+ if (codecs.toLowerCase() == 'ac-3' &&
1000
+ shaka.util.Platform.requiresEC3InitSegments()) {
1001
+ return 'ec-3';
1002
+ }
1003
+
999
1004
  return codecs;
1000
1005
  }
1001
1006
 
@@ -1191,6 +1196,9 @@ shaka.util.StreamUtils = class {
1191
1196
  * @return {shaka.extern.Track}
1192
1197
  */
1193
1198
  static variantToTrack(variant) {
1199
+ const ManifestParserUtils = shaka.util.ManifestParserUtils;
1200
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
1201
+
1194
1202
  /** @type {?shaka.extern.Stream} */
1195
1203
  const audio = variant.audio;
1196
1204
  /** @type {?shaka.extern.Stream} */
@@ -1309,6 +1317,16 @@ shaka.util.StreamUtils = class {
1309
1317
  track.audioSamplingRate = video.audioSamplingRate;
1310
1318
  track.spatialAudio = video.spatialAudio;
1311
1319
  track.originalLanguage = video.originalLanguage;
1320
+ track.audioMimeType = videoMimeType;
1321
+ const allCodecs = videoCodec.split(',');
1322
+ try {
1323
+ track.videoCodec = ManifestParserUtils.guessCodecs(
1324
+ ContentType.VIDEO, allCodecs);
1325
+ track.audioCodec = ManifestParserUtils.guessCodecs(
1326
+ ContentType.AUDIO, allCodecs);
1327
+ } catch (e) {
1328
+ // Ignore this error.
1329
+ }
1312
1330
  }
1313
1331
  }
1314
1332
 
package/lib/util/tXml.js CHANGED
@@ -555,8 +555,9 @@ shaka.util.TXml = class {
555
555
  const schemaNS = shaka.util.TXml.getKnownNameSpace(ns);
556
556
  const found = [];
557
557
  if (elem.children) {
558
+ const tagName = schemaNS ? `${schemaNS}:${name}` : name;
558
559
  for (const child of elem.children) {
559
- if (child && child.tagName === `${schemaNS}:${name}`) {
560
+ if (child && child.tagName === tagName) {
560
561
  found.push(child);
561
562
  }
562
563
  }
@@ -625,7 +626,7 @@ shaka.util.TXml = class {
625
626
 
626
627
  const re = '^P(?:([0-9]*)Y)?(?:([0-9]*)M)?(?:([0-9]*)D)?' +
627
628
  '(?:T(?:([0-9]*)H)?(?:([0-9]*)M)?(?:([0-9.]*)S)?)?$';
628
- const matches = new RegExp(re).exec(durationString);
629
+ const matches = new RegExp(re, 'i').exec(durationString);
629
630
 
630
631
  if (!matches) {
631
632
  shaka.log.warning('Invalid duration string:', durationString);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shaka-player",
3
3
  "description": "DASH/EME video player library",
4
- "version": "4.9.34",
4
+ "version": "4.9.36",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -43,7 +43,7 @@
43
43
  "karma-coverage": "^2.2.0",
44
44
  "karma-jasmine": "^4.0.1",
45
45
  "karma-jasmine-ajax": "^0.1.13",
46
- "karma-local-wd-launcher": "^1.6.7",
46
+ "karma-local-wd-launcher": "^1.6.9",
47
47
  "karma-opera-launcher": "^1.0.0",
48
48
  "karma-sourcemap-loader": "^0.3.8",
49
49
  "karma-spec-reporter": "^0.0.34",
@@ -105,7 +105,7 @@
105
105
  "prepublishOnly": "python build/checkversion.py && python build/all.py --force"
106
106
  },
107
107
  "dependencies": {
108
- "eme-encryption-scheme-polyfill": "^2.1.6"
108
+ "eme-encryption-scheme-polyfill": "^2.2.1"
109
109
  },
110
110
  "clean-package": {
111
111
  "remove": [
package/ui/controls.js CHANGED
@@ -1613,12 +1613,8 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
1613
1613
  goog.asserts.assert(
1614
1614
  this.seekBar_, 'Caller of seek_ must check for seekBar_ first!');
1615
1615
 
1616
- this.seekBar_.changeTo(currentTime);
1617
-
1618
- if (this.isOpaque()) {
1619
- // Only update the time and seek range if it's visible.
1620
- this.updateTimeAndSeekRange_();
1621
- }
1616
+ this.video_.currentTime = currentTime;
1617
+ this.updateTimeAndSeekRange_();
1622
1618
  }
1623
1619
 
1624
1620
  /**
@@ -8,6 +8,7 @@
8
8
  visibility: hidden;
9
9
  width: 15%;
10
10
  z-index: 1;
11
+ pointer-events: none;
11
12
 
12
13
  #shaka-player-ui-thumbnail-image {
13
14
  position: absolute;
@@ -119,7 +119,9 @@ shaka.ui.StatisticsButton = class extends shaka.ui.Element {
119
119
 
120
120
  const parseBytesDownloaded = (name) => {
121
121
  const bytes = parseInt(this.currentStats_[name], 10);
122
- if (bytes > 1e6) {
122
+ if (bytes > 2 * 1e9) {
123
+ return (bytes / 1e9).toFixed(2) + 'GB';
124
+ } else if (bytes > 1e6) {
123
125
  return (bytes / 1e6).toFixed(2) + 'MB';
124
126
  } else if (bytes > 1e3) {
125
127
  return (bytes / 1e3).toFixed(2) + 'KB';
package/ui/ui.js CHANGED
@@ -41,6 +41,35 @@ shaka.ui.Overlay = class {
41
41
  /** @private {!shaka.extern.UIConfiguration} */
42
42
  this.config_ = this.defaultConfig_();
43
43
 
44
+ // Get and configure cast app id.
45
+ let castAppId = '';
46
+
47
+ // Get and configure cast Android Receiver Compatibility
48
+ let castAndroidReceiverCompatible = false;
49
+
50
+ // Cast receiver id can be specified on either container or video.
51
+ // It should not be provided on both. If it was, we will use the last
52
+ // one we saw.
53
+ if (videoContainer['dataset'] &&
54
+ videoContainer['dataset']['shakaPlayerCastReceiverId']) {
55
+ const dataSet = videoContainer['dataset'];
56
+ castAppId = dataSet['shakaPlayerCastReceiverId'];
57
+ castAndroidReceiverCompatible =
58
+ dataSet['shakaPlayerCastAndroidReceiverCompatible'] === 'true';
59
+ } else if (video['dataset'] &&
60
+ video['dataset']['shakaPlayerCastReceiverId']) {
61
+ const dataSet = video['dataset'];
62
+ castAppId = dataSet['shakaPlayerCastReceiverId'];
63
+ castAndroidReceiverCompatible =
64
+ dataSet['shakaPlayerCastAndroidReceiverCompatible'] === 'true';
65
+ }
66
+
67
+ if (castAppId.length) {
68
+ this.config_.castReceiverAppId = castAppId;
69
+ this.config_.castAndroidReceiverCompatible =
70
+ castAndroidReceiverCompatible;
71
+ }
72
+
44
73
  // Make sure this container is discoverable and that the UI can be reached
45
74
  // through it.
46
75
  videoContainer['dataset']['shakaPlayerContainer'] = '';
@@ -55,10 +84,6 @@ shaka.ui.Overlay = class {
55
84
  this.controls_ = new shaka.ui.Controls(
56
85
  player, videoContainer, video, vrCanvas, this.config_);
57
86
 
58
- // Run the initial setup so that no configure() call is required for default
59
- // settings.
60
- this.configure({});
61
-
62
87
  // If the browser's native controls are disabled, use UI TextDisplayer.
63
88
  if (!video.controls) {
64
89
  player.setVideoContainer(videoContainer);
@@ -130,18 +155,29 @@ shaka.ui.Overlay = class {
130
155
 
131
156
  goog.asserts.assert(typeof(config) == 'object', 'Should be an object!');
132
157
 
158
+ const newConfig = /** @type {!shaka.extern.UIConfiguration} */(
159
+ Object.assign({}, this.config_));
133
160
  shaka.util.ConfigUtils.mergeConfigObjects(
134
- this.config_, config, this.defaultConfig_(),
161
+ newConfig, config, this.defaultConfig_(),
135
162
  /* overrides= */ {}, /* path= */ '');
136
163
 
137
164
  // If a cast receiver app id has been given, add a cast button to the UI
138
- if (this.config_.castReceiverAppId &&
139
- !this.config_.overflowMenuButtons.includes('cast')) {
140
- this.config_.overflowMenuButtons.push('cast');
165
+ if (newConfig.castReceiverAppId &&
166
+ !newConfig.overflowMenuButtons.includes('cast')) {
167
+ newConfig.overflowMenuButtons.push('cast');
141
168
  }
142
169
 
143
170
  goog.asserts.assert(this.player_ != null, 'Should have a player!');
144
171
 
172
+ const diff = shaka.util.ConfigUtils.getDifferenceFromConfigObjects(
173
+ newConfig, this.config_);
174
+ if (!Object.keys(diff).length) {
175
+ // No changes
176
+ return;
177
+ }
178
+
179
+ this.config_ = newConfig;
180
+
145
181
  this.controls_.configure(this.config_);
146
182
 
147
183
  this.controls_.dispatchEvent(new shaka.util.FakeEvent('uiupdated'));
@@ -432,33 +468,6 @@ shaka.ui.Overlay = class {
432
468
  // Attach Canvas used for LCEVC Decoding
433
469
  player.attachCanvas(/** @type {HTMLCanvasElement} */(lcevcCanvas));
434
470
 
435
- // Get and configure cast app id.
436
- let castAppId = '';
437
-
438
- // Get and configure cast Android Receiver Compatibility
439
- let castAndroidReceiverCompatible = false;
440
-
441
- // Cast receiver id can be specified on either container or video.
442
- // It should not be provided on both. If it was, we will use the last
443
- // one we saw.
444
- if (container['dataset'] &&
445
- container['dataset']['shakaPlayerCastReceiverId']) {
446
- castAppId = container['dataset']['shakaPlayerCastReceiverId'];
447
- castAndroidReceiverCompatible =
448
- container['dataset']['shakaPlayerCastAndroidReceiverCompatible'] ===
449
- 'true';
450
- } else if (video['dataset'] &&
451
- video['dataset']['shakaPlayerCastReceiverId']) {
452
- castAppId = video['dataset']['shakaPlayerCastReceiverId'];
453
- castAndroidReceiverCompatible =
454
- video['dataset']['shakaPlayerCastAndroidReceiverCompatible'] === 'true';
455
- }
456
-
457
- if (castAppId.length) {
458
- ui.configure({castReceiverAppId: castAppId,
459
- castAndroidReceiverCompatible: castAndroidReceiverCompatible});
460
- }
461
-
462
471
  if (shaka.util.Dom.asHTMLMediaElement(video).controls) {
463
472
  ui.getControls().setEnabledNativeControls(true);
464
473
  }