shaka-player 4.9.13 → 4.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +4 -0
  2. package/dist/controls.css +2 -2
  3. package/dist/controls.css.map +1 -1
  4. package/dist/deps.js +24 -19
  5. package/dist/locales.js +46 -35
  6. package/dist/shaka-player.compiled.d.ts +291 -12
  7. package/dist/shaka-player.compiled.debug.d.ts +291 -12
  8. package/dist/shaka-player.compiled.debug.externs.js +443 -6
  9. package/dist/shaka-player.compiled.debug.js +651 -556
  10. package/dist/shaka-player.compiled.debug.map +4 -4
  11. package/dist/shaka-player.compiled.externs.js +443 -6
  12. package/dist/shaka-player.compiled.js +1325 -1270
  13. package/dist/shaka-player.compiled.map +4 -4
  14. package/dist/shaka-player.ui.d.ts +306 -13
  15. package/dist/shaka-player.ui.debug.d.ts +306 -13
  16. package/dist/shaka-player.ui.debug.externs.js +477 -18
  17. package/dist/shaka-player.ui.debug.js +799 -681
  18. package/dist/shaka-player.ui.debug.map +4 -4
  19. package/dist/shaka-player.ui.externs.js +477 -18
  20. package/dist/shaka-player.ui.js +1600 -1533
  21. package/dist/shaka-player.ui.map +4 -4
  22. package/externs/shaka/ads.js +21 -1
  23. package/externs/shaka/manifest.js +20 -1
  24. package/externs/shaka/manifest_parser.js +18 -1
  25. package/externs/shaka/player.js +164 -50
  26. package/lib/ads/ad_manager.js +225 -10
  27. package/lib/ads/ad_utils.js +323 -0
  28. package/lib/ads/ads_stats.js +24 -0
  29. package/lib/ads/client_side_ad_manager.js +42 -34
  30. package/lib/ads/interstitial_ad.js +292 -0
  31. package/lib/ads/interstitial_ad_manager.js +772 -0
  32. package/lib/ads/media_tailor_ad_manager.js +19 -22
  33. package/lib/ads/server_side_ad_manager.js +12 -15
  34. package/lib/cast/cast_utils.js +1 -0
  35. package/lib/cea/cea_utils.js +12 -0
  36. package/lib/cea/mp4_cea_parser.js +17 -0
  37. package/lib/dash/dash_parser.js +81 -28
  38. package/lib/dash/segment_base.js +3 -0
  39. package/lib/hls/hls_parser.js +429 -121
  40. package/lib/hls/manifest_text_parser.js +1 -0
  41. package/lib/media/adaptation_set_criteria.js +31 -1
  42. package/lib/media/drm_engine.js +16 -2
  43. package/lib/media/manifest_filterer.js +7 -5
  44. package/lib/media/preload_manager.js +8 -10
  45. package/lib/media/presentation_timeline.js +37 -5
  46. package/lib/media/quality_observer.js +68 -2
  47. package/lib/media/segment_reference.js +1 -1
  48. package/lib/media/segment_utils.js +33 -1
  49. package/lib/media/streaming_engine.js +120 -43
  50. package/lib/mss/mss_parser.js +13 -2
  51. package/lib/net/networking_engine.js +1 -0
  52. package/lib/offline/manifest_converter.js +3 -0
  53. package/lib/offline/offline_manifest_parser.js +5 -0
  54. package/lib/offline/storage.js +2 -0
  55. package/lib/player.js +498 -165
  56. package/lib/util/fake_event.js +1 -0
  57. package/lib/util/manifest_parser_utils.js +9 -2
  58. package/lib/util/mp4_box_parsers.js +32 -0
  59. package/lib/util/player_configuration.js +21 -9
  60. package/lib/util/stats.js +43 -0
  61. package/package.json +1 -1
  62. package/shaka-player.uncompiled.js +2 -0
  63. package/ui/ad_counter.js +3 -3
  64. package/ui/ad_position.js +3 -3
  65. package/ui/ad_statistics_button.js +237 -0
  66. package/ui/audio_language_selection.js +8 -4
  67. package/ui/controls.js +6 -3
  68. package/ui/element.js +3 -3
  69. package/ui/enums.js +1 -0
  70. package/ui/externs/ui.js +3 -0
  71. package/ui/language_utils.js +48 -3
  72. package/ui/less/containers.less +32 -0
  73. package/ui/less/thumbnails.less +13 -0
  74. package/ui/locales/en.json +2 -0
  75. package/ui/locales/es-419.json +2 -0
  76. package/ui/locales/es.json +3 -0
  77. package/ui/locales/fr.json +1 -0
  78. package/ui/locales/pl.json +1 -0
  79. package/ui/locales/pt-BR.json +1 -0
  80. package/ui/locales/pt-PT.json +1 -0
  81. package/ui/locales/source.json +8 -0
  82. package/ui/mute_button.js +4 -4
  83. package/ui/overflow_menu.js +3 -3
  84. package/ui/play_button.js +5 -7
  85. package/ui/presentation_time.js +3 -3
  86. package/ui/save_video_frame_button.js +196 -0
  87. package/ui/seek_bar.js +75 -20
  88. package/ui/skip_ad_button.js +4 -4
  89. package/ui/statistics_button.js +14 -2
  90. package/ui/ui.js +15 -0
  91. package/ui/volume_bar.js +4 -4
@@ -155,6 +155,7 @@ shaka.util.FakeEvent = class {
155
155
  shaka.util.FakeEvent.EventName = {
156
156
  AbrStatusChanged: 'abrstatuschanged',
157
157
  Adaptation: 'adaptation',
158
+ AudioTrackChanged: 'audiotrackchanged',
158
159
  Buffering: 'buffering',
159
160
  Complete: 'complete',
160
161
  DownloadFailed: 'downloadfailed',
@@ -61,10 +61,11 @@ shaka.util.ManifestParserUtils = class {
61
61
  * @param {string} keySystem
62
62
  * @param {string} encryptionScheme
63
63
  * @param {Array.<shaka.extern.InitDataOverride>} initData
64
+ * @param {string} [keySystemUri]
64
65
  * @return {shaka.extern.DrmInfo}
65
66
  */
66
- static createDrmInfo(keySystem, encryptionScheme, initData) {
67
- return {
67
+ static createDrmInfo(keySystem, encryptionScheme, initData, keySystemUri) {
68
+ const drmInfo = {
68
69
  keySystem,
69
70
  encryptionScheme,
70
71
  licenseServerUri: '',
@@ -78,6 +79,12 @@ shaka.util.ManifestParserUtils = class {
78
79
  initData: initData || [],
79
80
  keyIds: new Set(),
80
81
  };
82
+
83
+ if (keySystemUri) {
84
+ drmInfo.keySystemUris = new Set([keySystemUri]);
85
+ }
86
+
87
+ return drmInfo;
81
88
  }
82
89
 
83
90
  /**
@@ -425,6 +425,27 @@ shaka.util.Mp4BoxParsers = class {
425
425
  return {codec};
426
426
  }
427
427
 
428
+ /**
429
+ * Parses a DVVC box.
430
+ * @param {string} codecBase
431
+ * @param {!shaka.util.DataViewReader} reader
432
+ * @param {string} boxName
433
+ * @return {!shaka.util.ParsedDVVCBox}
434
+ */
435
+ static parseDVVC(codecBase, reader, boxName) {
436
+ const Mp4BoxParsers = shaka.util.Mp4BoxParsers;
437
+ reader.skip(2); // Skip "dv_version_major" and "dv_version_minor"
438
+ const thirdByte = reader.readUint8();
439
+ const fourthByte = reader.readUint8();
440
+ const profile = (thirdByte >> 1) & 0x7f;
441
+ const level = ((thirdByte << 5) & 0x20) | ((fourthByte >> 3) & 0x1f);
442
+ const codec = codecBase + '.' +
443
+ Mp4BoxParsers.addLeadingZero_(profile) + '.' +
444
+ Mp4BoxParsers.addLeadingZero_(level);
445
+
446
+ return {codec};
447
+ }
448
+
428
449
  /**
429
450
  * Parses a VPCC box.
430
451
  * @param {string} codecBase
@@ -902,6 +923,17 @@ shaka.util.ParsedHVCCBox;
902
923
  */
903
924
  shaka.util.ParsedDVCCBox;
904
925
 
926
+ /**
927
+ * @typedef {{
928
+ * codec: string
929
+ * }}
930
+ *
931
+ * @property {string} codec
932
+ *
933
+ * @exportDoc
934
+ */
935
+ shaka.util.ParsedDVVCBox;
936
+
905
937
  /**
906
938
  * @typedef {{
907
939
  * codec: string
@@ -118,6 +118,7 @@ shaka.util.PlayerConfiguration = class {
118
118
  defaultPresentationDelay: 0,
119
119
  segmentRelativeVttTiming: false,
120
120
  raiseFatalErrorOnManifestUpdateRequestFailure: false,
121
+ continueLoadingWhenPaused: true,
121
122
  dash: {
122
123
  clockSyncUri: '',
123
124
  ignoreDrmInfo: false,
@@ -213,7 +214,6 @@ shaka.util.PlayerConfiguration = class {
213
214
  stallEnabled: true,
214
215
  stallThreshold: 1 /* seconds */,
215
216
  stallSkip: 0.1 /* seconds */,
216
- useNativeHlsOnSafari: true,
217
217
  useNativeHlsForFairPlay: true,
218
218
  // If we are within 2 seconds of the start of a live segment, fetch the
219
219
  // previous one. This allows for segment drift, but won't download an
@@ -238,14 +238,23 @@ shaka.util.PlayerConfiguration = class {
238
238
  disableAudioPrefetch: false,
239
239
  disableTextPrefetch: false,
240
240
  disableVideoPrefetch: false,
241
- liveSync: false,
242
- liveSyncTargetLatencyTolerance: 0.5,
243
- liveSyncMaxLatency: 1,
244
- liveSyncPlaybackRate: 1.1,
245
- liveSyncMinLatency: 0,
246
- liveSyncMinPlaybackRate: 0.95,
247
- liveSyncPanicMode: false,
248
- liveSyncPanicThreshold: 60,
241
+ liveSync: {
242
+ enabled: false,
243
+ targetLatency: 0.5,
244
+ targetLatencyTolerance: 0.5,
245
+ maxPlaybackRate: 1.1,
246
+ minPlaybackRate: 0.95,
247
+ panicMode: false,
248
+ panicThreshold: 60,
249
+ dynamicTargetLatency: {
250
+ enabled: false,
251
+ stabilityThreshold: 60,
252
+ rebufferIncrement: 0.5,
253
+ maxAttempts: 10,
254
+ maxLatency: 4,
255
+ minLatency: 1,
256
+ },
257
+ },
249
258
  allowMediaSourceRecoveries: true,
250
259
  minTimeBetweenRecoveries: 5,
251
260
  vodDynamicPlaybackRate: false,
@@ -256,6 +265,9 @@ shaka.util.PlayerConfiguration = class {
256
265
  loadTimeout: 30,
257
266
  clearDecodingCache: shaka.util.Platform.isPS4() ||
258
267
  shaka.util.Platform.isPS5(),
268
+ dontChooseCodecs: false,
269
+ shouldFixTimestampOffset: shaka.util.Platform.isWebOS() ||
270
+ shaka.util.Platform.isTizen(),
259
271
  };
260
272
 
261
273
  // WebOS, Tizen, Chromecast and Hisense have long hardware pipelines
package/lib/util/stats.js CHANGED
@@ -62,9 +62,18 @@ shaka.util.Stats = class {
62
62
  /** @private {number} */
63
63
  this.bandwidthEstimate_ = NaN;
64
64
 
65
+ /** @private {number} */
66
+ this.manifestSizeBytes_ = NaN;
65
67
  /** @private {number} */
66
68
  this.bytesDownloaded_ = NaN;
67
69
 
70
+ /** @private {number} */
71
+ this.nonFatalErrorCount_ = 0;
72
+ /** @private {number} */
73
+ this.manifestPeriodCount_ = NaN;
74
+ /** @private {number} */
75
+ this.manifestGapCount_ = NaN;
76
+
68
77
  /** @private {!shaka.util.StateHistory} */
69
78
  this.stateHistory_ = new shaka.util.StateHistory();
70
79
 
@@ -206,6 +215,13 @@ shaka.util.Stats = class {
206
215
  this.bandwidthEstimate_ = bandwidth;
207
216
  }
208
217
 
218
+ /**
219
+ * @param {number} size
220
+ */
221
+ setManifestSize(size) {
222
+ this.manifestSizeBytes_ = size;
223
+ }
224
+
209
225
  /**
210
226
  * @param {number} bytesDownloaded
211
227
  */
@@ -217,6 +233,25 @@ shaka.util.Stats = class {
217
233
  }
218
234
  }
219
235
 
236
+ /** */
237
+ addNonFatalError() {
238
+ this.nonFatalErrorCount_++;
239
+ }
240
+
241
+ /**
242
+ * @param {number} count
243
+ */
244
+ setManifestPeriodCount(count) {
245
+ this.manifestPeriodCount_ = count;
246
+ }
247
+
248
+ /**
249
+ * @param {number} count
250
+ */
251
+ setManifestGapCount(count) {
252
+ this.manifestGapCount_ = count;
253
+ }
254
+
220
255
  /**
221
256
  * @return {!shaka.util.StateHistory}
222
257
  */
@@ -258,7 +293,11 @@ shaka.util.Stats = class {
258
293
  licenseTime: this.licenseTimeSeconds_,
259
294
  liveLatency: this.liveLatencySeconds_,
260
295
  maxSegmentDuration: this.maxSegmentDurationSeconds_,
296
+ manifestSizeBytes: this.manifestSizeBytes_,
261
297
  bytesDownloaded: this.bytesDownloaded_,
298
+ nonFatalErrorCount: this.nonFatalErrorCount_,
299
+ manifestPeriodCount: this.manifestPeriodCount_,
300
+ manifestGapCount: this.manifestGapCount_,
262
301
  stateHistory: this.stateHistory_.getCopy(),
263
302
  switchHistory: this.switchHistory_.getCopy(),
264
303
  };
@@ -291,7 +330,11 @@ shaka.util.Stats = class {
291
330
  licenseTime: NaN,
292
331
  liveLatency: NaN,
293
332
  maxSegmentDuration: NaN,
333
+ manifestSizeBytes: NaN,
294
334
  bytesDownloaded: NaN,
335
+ nonFatalErrorCount: NaN,
336
+ manifestPeriodCount: NaN,
337
+ manifestGapCount: NaN,
295
338
  switchHistory: [],
296
339
  stateHistory: [],
297
340
  };
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.13",
4
+ "version": "4.10.1",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -86,6 +86,7 @@ goog.require('shaka.ui.OverflowMenu');
86
86
  goog.require('shaka.ui.AudioLanguageSelection');
87
87
  goog.require('shaka.ui.AdCounter');
88
88
  goog.require('shaka.ui.AdPosition');
89
+ goog.require('shaka.ui.AdStatisticsButton');
89
90
  goog.require('shaka.ui.AirPlayButton');
90
91
  goog.require('shaka.ui.BigPlayButton');
91
92
  goog.require('shaka.ui.CastButton');
@@ -106,6 +107,7 @@ goog.require('shaka.ui.RecenterVRButton');
106
107
  goog.require('shaka.ui.RemoteButton');
107
108
  goog.require('shaka.ui.ResolutionSelection');
108
109
  goog.require('shaka.ui.RewindButton');
110
+ goog.require('shaka.ui.SaveVideoFrameButton');
109
111
  goog.require('shaka.ui.SkipAdButton');
110
112
  goog.require('shaka.ui.SmallPlayButton');
111
113
  goog.require('shaka.ui.Spacer');
package/ui/ad_counter.js CHANGED
@@ -8,7 +8,7 @@
8
8
  goog.provide('shaka.ui.AdCounter');
9
9
 
10
10
  goog.require('goog.asserts');
11
- goog.require('shaka.ads.AdManager');
11
+ goog.require('shaka.ads.Utils');
12
12
  goog.require('shaka.ui.Element');
13
13
  goog.require('shaka.ui.Locales');
14
14
  goog.require('shaka.ui.Localization');
@@ -63,12 +63,12 @@ shaka.ui.AdCounter = class extends shaka.ui.Element {
63
63
  });
64
64
 
65
65
  this.eventManager.listen(
66
- this.adManager, shaka.ads.AdManager.AD_STARTED, () => {
66
+ this.adManager, shaka.ads.Utils.AD_STARTED, () => {
67
67
  this.onAdStarted_();
68
68
  });
69
69
 
70
70
  this.eventManager.listen(
71
- this.adManager, shaka.ads.AdManager.AD_STOPPED, () => {
71
+ this.adManager, shaka.ads.Utils.AD_STOPPED, () => {
72
72
  this.reset_();
73
73
  });
74
74
 
package/ui/ad_position.js CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  goog.provide('shaka.ui.AdPosition');
9
9
 
10
- goog.require('shaka.ads.AdManager');
10
+ goog.require('shaka.ads.Utils');
11
11
  goog.require('shaka.ui.Element');
12
12
  goog.require('shaka.ui.Locales');
13
13
  goog.require('shaka.ui.Localization');
@@ -63,12 +63,12 @@ shaka.ui.AdPosition = class extends shaka.ui.Element {
63
63
  });
64
64
 
65
65
  this.eventManager.listen(
66
- this.adManager, shaka.ads.AdManager.AD_STARTED, () => {
66
+ this.adManager, shaka.ads.Utils.AD_STARTED, () => {
67
67
  this.setPosition_();
68
68
  });
69
69
 
70
70
  this.eventManager.listen(
71
- this.adManager, shaka.ads.AdManager.AD_STOPPED, () => {
71
+ this.adManager, shaka.ads.Utils.AD_STOPPED, () => {
72
72
  this.span_.textContent = '';
73
73
  shaka.ui.Utils.setDisplay(this.container_, false);
74
74
  });
@@ -0,0 +1,237 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+
8
+ goog.provide('shaka.ui.AdStatisticsButton');
9
+
10
+ goog.require('shaka.log');
11
+ goog.require('shaka.ads.Utils');
12
+ goog.require('shaka.ui.ContextMenu');
13
+ goog.require('shaka.ui.Controls');
14
+ goog.require('shaka.ui.Element');
15
+ goog.require('shaka.ui.Enums');
16
+ goog.require('shaka.ui.Locales');
17
+ goog.require('shaka.ui.Localization');
18
+ goog.require('shaka.ui.OverflowMenu');
19
+ goog.require('shaka.ui.Utils');
20
+ goog.require('shaka.util.Dom');
21
+ goog.require('shaka.util.Timer');
22
+ goog.requireType('shaka.ui.Controls');
23
+
24
+
25
+ /**
26
+ * @extends {shaka.ui.Element}
27
+ * @final
28
+ * @export
29
+ */
30
+ shaka.ui.AdStatisticsButton = class extends shaka.ui.Element {
31
+ /**
32
+ * @param {!HTMLElement} parent
33
+ * @param {!shaka.ui.Controls} controls
34
+ */
35
+ constructor(parent, controls) {
36
+ super(parent, controls);
37
+
38
+ /** @private {!HTMLButtonElement} */
39
+ this.button_ = shaka.util.Dom.createButton();
40
+ this.button_.classList.add('shaka-ad-statistics-button');
41
+
42
+ /** @private {!HTMLElement} */
43
+ this.icon_ = shaka.util.Dom.createHTMLElement('i');
44
+ this.icon_.classList.add('material-icons-round');
45
+ this.icon_.textContent =
46
+ shaka.ui.Enums.MaterialDesignIcons.STATISTICS_ON;
47
+ this.button_.appendChild(this.icon_);
48
+
49
+ const label = shaka.util.Dom.createHTMLElement('label');
50
+ label.classList.add('shaka-overflow-button-label');
51
+
52
+ /** @private {!HTMLElement} */
53
+ this.nameSpan_ = shaka.util.Dom.createHTMLElement('span');
54
+ label.appendChild(this.nameSpan_);
55
+
56
+ /** @private {!HTMLElement} */
57
+ this.stateSpan_ = shaka.util.Dom.createHTMLElement('span');
58
+ this.stateSpan_.classList.add('shaka-current-selection-span');
59
+ label.appendChild(this.stateSpan_);
60
+
61
+ this.button_.appendChild(label);
62
+
63
+ this.parent.appendChild(this.button_);
64
+
65
+ /** @private {!HTMLElement} */
66
+ this.container_ = shaka.util.Dom.createHTMLElement('div');
67
+ this.container_.classList.add('shaka-no-propagation');
68
+ this.container_.classList.add('shaka-show-controls-on-mouse-over');
69
+ this.container_.classList.add('shaka-ad-statistics-container');
70
+ this.container_.classList.add('shaka-hidden');
71
+
72
+ const controlsContainer = this.controls.getControlsContainer();
73
+ controlsContainer.appendChild(this.container_);
74
+
75
+ /** @private {!Array} */
76
+ this.statisticsList_ = [];
77
+
78
+ /** @private {!Object.<string, (number|!Array.<number>)>} */
79
+ this.currentStats_ = this.adManager.getStats();
80
+
81
+ /** @private {!Object.<string, HTMLElement>} */
82
+ this.displayedElements_ = {};
83
+
84
+ const parseLoadTimes = (name) => {
85
+ let totalTime = 0;
86
+ const loadTimes =
87
+ /** @type {!Array.<number>} */ (this.currentStats_[name]);
88
+ for (const loadTime of loadTimes) {
89
+ totalTime += parseFloat(loadTime);
90
+ }
91
+ return totalTime;
92
+ };
93
+
94
+ const showNumber = (name) => {
95
+ return this.currentStats_[name];
96
+ };
97
+
98
+ /** @private {!Object.<string, function(string):string>} */
99
+ this.parseFrom_ = {
100
+ 'loadTimes': parseLoadTimes,
101
+ 'averageLoadTime': showNumber,
102
+ 'started': showNumber,
103
+ 'playedCompletely': showNumber,
104
+ 'skipped': showNumber,
105
+ 'errors': showNumber,
106
+ };
107
+
108
+ /** @private {shaka.util.Timer} */
109
+ this.timer_ = new shaka.util.Timer(() => {
110
+ this.onTimerTick_();
111
+ });
112
+
113
+ this.updateLocalizedStrings_();
114
+
115
+ this.loadContainer_();
116
+
117
+ this.eventManager.listen(
118
+ this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
119
+ this.updateLocalizedStrings_();
120
+ });
121
+
122
+ this.eventManager.listen(
123
+ this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => {
124
+ this.updateLocalizedStrings_();
125
+ });
126
+
127
+ this.eventManager.listen(this.button_, 'click', () => {
128
+ this.onClick_();
129
+ this.updateLocalizedStrings_();
130
+ });
131
+
132
+ this.eventManager.listen(this.player, 'loading', () => {
133
+ shaka.ui.Utils.setDisplay(this.button_, false);
134
+ });
135
+
136
+ this.eventManager.listen(
137
+ this.adManager, shaka.ads.Utils.AD_STARTED, () => {
138
+ shaka.ui.Utils.setDisplay(this.button_, true);
139
+ });
140
+ }
141
+
142
+ /** @private */
143
+ onClick_() {
144
+ shaka.ui.Utils.setDisplay(this.parent, false);
145
+
146
+ if (this.container_.classList.contains('shaka-hidden')) {
147
+ this.icon_.textContent =
148
+ shaka.ui.Enums.MaterialDesignIcons.STATISTICS_OFF;
149
+ this.timer_.tickEvery(0.1);
150
+ shaka.ui.Utils.setDisplay(this.container_, true);
151
+ } else {
152
+ this.icon_.textContent =
153
+ shaka.ui.Enums.MaterialDesignIcons.STATISTICS_ON;
154
+ this.timer_.stop();
155
+ shaka.ui.Utils.setDisplay(this.container_, false);
156
+ }
157
+ }
158
+
159
+ /** @private */
160
+ updateLocalizedStrings_() {
161
+ const LocIds = shaka.ui.Locales.Ids;
162
+
163
+ this.nameSpan_.textContent =
164
+ this.localization.resolve(LocIds.AD_STATISTICS);
165
+
166
+ this.button_.ariaLabel = this.localization.resolve(LocIds.AD_STATISTICS);
167
+
168
+ const labelText = this.container_.classList.contains('shaka-hidden') ?
169
+ LocIds.OFF : LocIds.ON;
170
+ this.stateSpan_.textContent = this.localization.resolve(labelText);
171
+ }
172
+
173
+ /** @private */
174
+ generateComponent_(name) {
175
+ const section = shaka.util.Dom.createHTMLElement('div');
176
+
177
+ const label = shaka.util.Dom.createHTMLElement('label');
178
+ label.textContent = name + ':';
179
+ section.appendChild(label);
180
+
181
+ const value = shaka.util.Dom.createHTMLElement('span');
182
+ value.textContent = this.parseFrom_[name](name);
183
+ section.appendChild(value);
184
+
185
+ this.displayedElements_[name] = value;
186
+
187
+ return section;
188
+ }
189
+
190
+ /** @private */
191
+ loadContainer_() {
192
+ for (const name of this.controls.getConfig().adStatisticsList) {
193
+ if (name in this.currentStats_) {
194
+ this.container_.appendChild(this.generateComponent_(name));
195
+ this.statisticsList_.push(name);
196
+ } else {
197
+ shaka.log.alwaysWarn('Unrecognized ad statistic element:', name);
198
+ }
199
+ }
200
+ }
201
+
202
+ /** @private */
203
+ onTimerTick_() {
204
+ this.currentStats_ = this.adManager.getStats();
205
+
206
+ for (const name of this.statisticsList_) {
207
+ this.displayedElements_[name].textContent =
208
+ this.parseFrom_[name](name);
209
+ }
210
+ }
211
+
212
+ /** @override */
213
+ release() {
214
+ this.timer_.stop();
215
+ this.timer_ = null;
216
+ super.release();
217
+ }
218
+ };
219
+
220
+
221
+ /**
222
+ * @implements {shaka.extern.IUIElement.Factory}
223
+ * @final
224
+ */
225
+ shaka.ui.AdStatisticsButton.Factory = class {
226
+ /** @override */
227
+ create(rootElement, controls) {
228
+ return new shaka.ui.AdStatisticsButton(rootElement, controls);
229
+ }
230
+ };
231
+
232
+
233
+ shaka.ui.OverflowMenu.registerElement(
234
+ 'ad_statistics', new shaka.ui.AdStatisticsButton.Factory());
235
+
236
+ shaka.ui.ContextMenu.registerElement(
237
+ 'ad_statistics', new shaka.ui.AdStatisticsButton.Factory());
@@ -97,13 +97,17 @@ shaka.ui.AudioLanguageSelection = class extends shaka.ui.SettingsMenu {
97
97
  * @private
98
98
  */
99
99
  onAudioTrackSelected_(track) {
100
+ let channelsCount = undefined;
100
101
  if (track.channelsCount &&
101
102
  this.controls.getConfig().showAudioChannelCountVariants) {
102
- this.player.selectAudioLanguage(
103
- track.language, track.roles[0], track.channelsCount);
104
- } else {
105
- this.player.selectAudioLanguage(track.language, track.roles[0]);
103
+ channelsCount = track.channelsCount;
106
104
  }
105
+ let codec = undefined;
106
+ if (track.audioCodec) {
107
+ codec = track.audioCodec;
108
+ }
109
+ this.player.selectAudioLanguage(track.language, track.roles[0],
110
+ channelsCount, /* safeMargin= */ 0, codec);
107
111
  }
108
112
 
109
113
 
package/ui/controls.js CHANGED
@@ -9,7 +9,7 @@ goog.provide('shaka.ui.Controls');
9
9
  goog.provide('shaka.ui.ControlsPanel');
10
10
 
11
11
  goog.require('goog.asserts');
12
- goog.require('shaka.ads.AdManager');
12
+ goog.require('shaka.ads.Utils');
13
13
  goog.require('shaka.cast.CastProxy');
14
14
  goog.require('shaka.log');
15
15
  goog.require('shaka.ui.AdCounter');
@@ -203,6 +203,9 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
203
203
  const locale = e['locales'][0];
204
204
  this.adManager_.setLocale(locale);
205
205
  });
206
+
207
+ this.adManager_.initInterstitial(
208
+ this.getClientSideAdContainer(), this.localPlayer_, this.localVideo_);
206
209
  }
207
210
 
208
211
  /**
@@ -1213,13 +1216,13 @@ shaka.ui.Controls = class extends shaka.util.FakeEventTarget {
1213
1216
  });
1214
1217
 
1215
1218
  this.eventManager_.listen(
1216
- this.adManager_, shaka.ads.AdManager.AD_STARTED, (e) => {
1219
+ this.adManager_, shaka.ads.Utils.AD_STARTED, (e) => {
1217
1220
  this.ad_ = (/** @type {!Object} */ (e))['ad'];
1218
1221
  this.showAdUI();
1219
1222
  });
1220
1223
 
1221
1224
  this.eventManager_.listen(
1222
- this.adManager_, shaka.ads.AdManager.AD_STOPPED, () => {
1225
+ this.adManager_, shaka.ads.Utils.AD_STOPPED, () => {
1223
1226
  this.ad_ = null;
1224
1227
  this.hideAdUI();
1225
1228
  });
package/ui/element.js CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  goog.provide('shaka.ui.Element');
9
9
 
10
- goog.require('shaka.ads.AdManager');
10
+ goog.require('shaka.ads.Utils');
11
11
  goog.require('shaka.util.EventManager');
12
12
  goog.requireType('shaka.Player');
13
13
  goog.requireType('shaka.ui.Controls');
@@ -73,12 +73,12 @@ shaka.ui.Element = class {
73
73
  */
74
74
  this.ad = controls.getAd();
75
75
 
76
- const AD_STARTED = shaka.ads.AdManager.AD_STARTED;
76
+ const AD_STARTED = shaka.ads.Utils.AD_STARTED;
77
77
  this.eventManager.listen(this.adManager, AD_STARTED, (e) => {
78
78
  this.ad = (/** @type {!Object} */ (e))['ad'];
79
79
  });
80
80
 
81
- const AD_STOPPED = shaka.ads.AdManager.AD_STOPPED;
81
+ const AD_STOPPED = shaka.ads.Utils.AD_STOPPED;
82
82
  this.eventManager.listen(this.adManager, AD_STOPPED, () => {
83
83
  this.ad = null;
84
84
  });
package/ui/enums.js CHANGED
@@ -46,4 +46,5 @@ shaka.ui.Enums.MaterialDesignIcons = {
46
46
  'STATISTICS_OFF': 'insert_chart',
47
47
  'RECENTER_VR': 'control_camera',
48
48
  'TOGGLE_STEREOSCOPIC': '3d_rotation',
49
+ 'DOWNLOAD': 'download',
49
50
  };
package/ui/externs/ui.js CHANGED
@@ -65,6 +65,7 @@ shaka.extern.UIVolumeBarColors;
65
65
  * overflowMenuButtons: !Array.<string>,
66
66
  * contextMenuElements: !Array.<string>,
67
67
  * statisticsList: !Array.<string>,
68
+ * adStatisticsList: !Array.<string>,
68
69
  * playbackRates: !Array.<number>,
69
70
  * fastForwardRates: !Array.<number>,
70
71
  * rewindRates: !Array.<number>,
@@ -106,6 +107,8 @@ shaka.extern.UIVolumeBarColors;
106
107
  * The ordered list of buttons in the context menu.
107
108
  * @property {!Array.<string>} statisticsList
108
109
  * The ordered list of statistics present in the statistics container.
110
+ * @property {!Array.<string>} adStatisticsList
111
+ * The ordered list of ad statistics present in the ad statistics container.
109
112
  * @property {!Array.<number>} playbackRates
110
113
  * The ordered list of rates for playback selection.
111
114
  * @property {!Array.<number>} fastForwardRates