shaka-player 4.12.8 → 4.13.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.
Files changed (261) hide show
  1. package/AUTHORS +1 -0
  2. package/CONTRIBUTORS +4 -0
  3. package/README.md +22 -21
  4. package/cspell.config.yaml +18 -0
  5. package/dist/controls.css +1 -1
  6. package/dist/controls.css.map +1 -1
  7. package/dist/deps.js +29 -24
  8. package/dist/locales.js +33 -33
  9. package/dist/shaka-player.compiled.d.ts +138 -36
  10. package/dist/shaka-player.compiled.debug.d.ts +138 -36
  11. package/dist/shaka-player.compiled.debug.externs.js +367 -107
  12. package/dist/shaka-player.compiled.debug.js +828 -765
  13. package/dist/shaka-player.compiled.debug.map +4 -4
  14. package/dist/shaka-player.compiled.externs.js +367 -107
  15. package/dist/shaka-player.compiled.js +1451 -1416
  16. package/dist/shaka-player.compiled.map +4 -4
  17. package/dist/shaka-player.ui.d.ts +172 -38
  18. package/dist/shaka-player.ui.debug.d.ts +172 -38
  19. package/dist/shaka-player.ui.debug.externs.js +406 -113
  20. package/dist/shaka-player.ui.debug.js +842 -766
  21. package/dist/shaka-player.ui.debug.map +4 -4
  22. package/dist/shaka-player.ui.externs.js +406 -113
  23. package/dist/shaka-player.ui.js +1670 -1628
  24. package/dist/shaka-player.ui.map +4 -4
  25. package/eslint.config.mjs +343 -0
  26. package/externs/airplay.js +1 -1
  27. package/externs/audiotrack.js +1 -1
  28. package/externs/awesomplete.js +1 -1
  29. package/externs/cast-sdk-v2.js +2 -2
  30. package/externs/cmcd.js +16 -1
  31. package/externs/device_sensor_event.js +1 -1
  32. package/externs/ima.js +8 -8
  33. package/externs/isoboxer.js +31 -31
  34. package/externs/jwk_set.js +1 -1
  35. package/externs/lcevc.js +8 -8
  36. package/externs/mediakeys.js +1 -1
  37. package/externs/mediasession.js +3 -2
  38. package/externs/mediatailor.js +18 -18
  39. package/externs/pictureinpicture.js +41 -1
  40. package/externs/playstation.js +2 -2
  41. package/externs/prefixed_eme.js +1 -1
  42. package/externs/shaka/abortable.js +4 -4
  43. package/externs/shaka/abr_manager.js +1 -1
  44. package/externs/shaka/ads.js +45 -6
  45. package/externs/shaka/cea.js +2 -2
  46. package/externs/shaka/codecs.js +4 -4
  47. package/externs/shaka/drm_info.js +6 -6
  48. package/externs/shaka/error.js +5 -5
  49. package/externs/shaka/manifest.js +51 -56
  50. package/externs/shaka/manifest_parser.js +3 -9
  51. package/externs/shaka/net.js +23 -20
  52. package/externs/shaka/offline.js +37 -37
  53. package/externs/shaka/offline_compat_v1.js +10 -10
  54. package/externs/shaka/offline_compat_v2.js +10 -10
  55. package/externs/shaka/player.js +139 -109
  56. package/externs/shaka/text.js +10 -3
  57. package/externs/shaka/transmuxer.js +1 -1
  58. package/externs/videotrack.js +1 -1
  59. package/lib/abr/ewma.js +1 -1
  60. package/lib/abr/simple_abr_manager.js +70 -22
  61. package/lib/ads/ad_manager.js +43 -18
  62. package/lib/ads/ad_utils.js +160 -58
  63. package/lib/ads/ads_stats.js +1 -1
  64. package/lib/ads/client_side_ad_manager.js +2 -2
  65. package/lib/ads/interstitial_ad.js +16 -11
  66. package/lib/ads/interstitial_ad_manager.js +419 -72
  67. package/lib/ads/interstitial_static_ad.js +299 -0
  68. package/lib/ads/media_tailor_ad.js +1 -0
  69. package/lib/ads/media_tailor_ad_manager.js +37 -36
  70. package/lib/ads/server_side_ad_manager.js +7 -6
  71. package/lib/cast/cast_receiver.js +5 -3
  72. package/lib/cast/cast_sender.js +2 -2
  73. package/lib/cast/cast_utils.js +20 -13
  74. package/lib/cea/cea608_data_channel.js +53 -53
  75. package/lib/cea/cea708_service.js +42 -40
  76. package/lib/cea/cea708_window.js +5 -2
  77. package/lib/cea/cea_decoder.js +5 -7
  78. package/lib/cea/mp4_cea_parser.js +1 -1
  79. package/lib/cea/sei_processor.js +1 -1
  80. package/lib/dash/content_protection.js +62 -192
  81. package/lib/dash/dash_parser.js +119 -119
  82. package/lib/dash/mpd_utils.js +14 -13
  83. package/lib/dash/segment_base.js +5 -5
  84. package/lib/dash/segment_list.js +10 -10
  85. package/lib/dash/segment_template.js +55 -53
  86. package/lib/debug/log.js +2 -2
  87. package/lib/dependencies/all.js +2 -1
  88. package/lib/{media → drm}/drm_engine.js +274 -143
  89. package/lib/{util → drm}/drm_utils.js +20 -11
  90. package/lib/drm/playready.js +233 -0
  91. package/lib/hls/hls_classes.js +14 -14
  92. package/lib/hls/hls_parser.js +257 -196
  93. package/lib/hls/hls_utils.js +14 -14
  94. package/lib/hls/manifest_text_parser.js +10 -10
  95. package/lib/media/adaptation_set.js +6 -5
  96. package/lib/media/adaptation_set_criteria.js +51 -379
  97. package/lib/media/buffering_observer.js +5 -4
  98. package/lib/media/closed_caption_parser.js +2 -2
  99. package/lib/media/content_workarounds.js +2 -2
  100. package/lib/media/example_based_criteria.js +69 -0
  101. package/lib/media/gap_jumping_controller.js +14 -1
  102. package/lib/media/manifest_filterer.js +8 -8
  103. package/lib/media/manifest_parser.js +2 -2
  104. package/lib/media/media_source_capabilities.js +20 -1
  105. package/lib/media/media_source_engine.js +84 -35
  106. package/lib/media/mp4_segment_index_parser.js +5 -5
  107. package/lib/media/playhead.js +2 -8
  108. package/lib/media/playhead_observer.js +1 -1
  109. package/lib/media/preference_based_criteria.js +333 -0
  110. package/lib/media/preload_manager.js +53 -37
  111. package/lib/media/presentation_timeline.js +2 -2
  112. package/lib/media/quality_observer.js +35 -35
  113. package/lib/media/region_observer.js +2 -2
  114. package/lib/media/region_timeline.js +3 -3
  115. package/lib/media/segment_index.js +14 -14
  116. package/lib/media/segment_prefetch.js +17 -13
  117. package/lib/media/segment_reference.js +7 -7
  118. package/lib/media/segment_utils.js +9 -9
  119. package/lib/media/streaming_engine.js +77 -38
  120. package/lib/media/time_ranges_utils.js +1 -1
  121. package/lib/media/video_wrapper.js +1 -1
  122. package/lib/media/webm_segment_index_parser.js +4 -4
  123. package/lib/mss/content_protection.js +17 -222
  124. package/lib/mss/mss_parser.js +23 -24
  125. package/lib/net/data_uri_plugin.js +1 -0
  126. package/lib/net/http_fetch_plugin.js +8 -7
  127. package/lib/net/http_plugin_utils.js +5 -2
  128. package/lib/net/http_xhr_plugin.js +4 -3
  129. package/lib/net/networking_engine.js +72 -17
  130. package/lib/net/networking_utils.js +5 -2
  131. package/lib/offline/download_info.js +5 -1
  132. package/lib/offline/download_manager.js +15 -4
  133. package/lib/offline/download_progress_estimator.js +1 -1
  134. package/lib/offline/indexeddb/base_storage_cell.js +9 -9
  135. package/lib/offline/indexeddb/db_connection.js +1 -1
  136. package/lib/offline/indexeddb/db_operation.js +2 -2
  137. package/lib/offline/indexeddb/eme_session_storage_cell.js +1 -1
  138. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  139. package/lib/offline/indexeddb/v1_storage_cell.js +3 -3
  140. package/lib/offline/indexeddb/v2_storage_cell.js +2 -2
  141. package/lib/offline/manifest_converter.js +11 -12
  142. package/lib/offline/offline_scheme.js +8 -4
  143. package/lib/offline/session_deleter.js +11 -11
  144. package/lib/offline/storage.js +137 -88
  145. package/lib/offline/storage_muxer.js +8 -8
  146. package/lib/offline/stored_content_utils.js +3 -3
  147. package/lib/offline/stream_bandwidth_estimator.js +1 -1
  148. package/lib/player.js +291 -207
  149. package/lib/polyfill/all.js +1 -1
  150. package/lib/polyfill/media_capabilities.js +5 -5
  151. package/lib/polyfill/patchedmediakeys_apple.js +6 -6
  152. package/lib/polyfill/patchedmediakeys_webkit.js +8 -8
  153. package/lib/polyfill/video_play_promise.js +0 -1
  154. package/lib/text/cue.js +3 -2
  155. package/lib/text/lrc_text_parser.js +1 -1
  156. package/lib/text/mp4_ttml_parser.js +1 -1
  157. package/lib/text/mp4_vtt_parser.js +3 -3
  158. package/lib/text/sbv_text_parser.js +1 -1
  159. package/lib/text/simple_text_displayer.js +37 -10
  160. package/lib/text/ssa_text_parser.js +3 -1
  161. package/lib/text/stub_text_displayer.js +12 -5
  162. package/lib/text/text_engine.js +5 -4
  163. package/lib/text/text_utils.js +4 -4
  164. package/lib/text/ttml_text_parser.js +21 -20
  165. package/lib/text/ui_text_displayer.js +20 -13
  166. package/lib/text/vtt_text_parser.js +10 -10
  167. package/lib/text/web_vtt_generator.js +2 -2
  168. package/lib/transmuxer/aac_transmuxer.js +2 -2
  169. package/lib/transmuxer/ac3_transmuxer.js +2 -2
  170. package/lib/transmuxer/adts.js +2 -0
  171. package/lib/transmuxer/ec3.js +3 -3
  172. package/lib/transmuxer/ec3_transmuxer.js +2 -2
  173. package/lib/transmuxer/h264.js +5 -5
  174. package/lib/transmuxer/h265.js +3 -3
  175. package/lib/transmuxer/mp3_transmuxer.js +2 -2
  176. package/lib/transmuxer/mpeg_audio.js +6 -6
  177. package/lib/transmuxer/mss_transmuxer.js +2 -0
  178. package/lib/transmuxer/transmuxer_engine.js +1 -1
  179. package/lib/transmuxer/ts_transmuxer.js +10 -10
  180. package/lib/util/abortable_operation.js +10 -10
  181. package/lib/util/array_utils.js +6 -6
  182. package/lib/util/cmcd_manager.js +149 -18
  183. package/lib/util/cmsd_manager.js +11 -11
  184. package/lib/util/config_utils.js +3 -3
  185. package/lib/util/content_steering_manager.js +17 -17
  186. package/lib/util/data_view_reader.js +3 -3
  187. package/lib/util/ebml_parser.js +1 -1
  188. package/lib/util/error.js +11 -6
  189. package/lib/util/event_manager.js +1 -1
  190. package/lib/util/exp_golomb.js +1 -1
  191. package/lib/util/fairplay_utils.js +6 -1
  192. package/lib/util/fake_event.js +3 -2
  193. package/lib/util/fake_event_target.js +1 -1
  194. package/lib/util/functional.js +8 -8
  195. package/lib/util/id3_utils.js +1 -1
  196. package/lib/util/iterables.js +6 -6
  197. package/lib/util/language_utils.js +17 -17
  198. package/lib/util/manifest_parser_utils.js +13 -13
  199. package/lib/util/map_utils.js +6 -6
  200. package/lib/util/media_ready_state_utils.js +1 -1
  201. package/lib/util/mime_utils.js +15 -4
  202. package/lib/util/mp4_box_parsers.js +5 -5
  203. package/lib/util/mp4_generator.js +31 -30
  204. package/lib/util/mp4_parser.js +2 -2
  205. package/lib/util/multi_map.js +5 -5
  206. package/lib/util/mutex.js +1 -1
  207. package/lib/util/networking.js +1 -1
  208. package/lib/util/object_utils.js +5 -1
  209. package/lib/util/operation_manager.js +1 -1
  210. package/lib/util/periods.js +24 -24
  211. package/lib/util/platform.js +8 -4
  212. package/lib/util/player_configuration.js +50 -17
  213. package/lib/util/pssh.js +34 -6
  214. package/lib/util/public_promise.js +2 -2
  215. package/lib/util/state_history.js +2 -2
  216. package/lib/util/stream_utils.js +138 -120
  217. package/lib/util/string_utils.js +4 -3
  218. package/lib/util/switch_history.js +2 -2
  219. package/lib/util/tXml.js +22 -17
  220. package/lib/util/text_parser.js +2 -2
  221. package/lib/util/timer.js +1 -1
  222. package/lib/util/ts_parser.js +22 -22
  223. package/lib/util/xml_utils.js +1 -0
  224. package/package.json +7 -4
  225. package/project-words.txt +485 -0
  226. package/shaka-player.uncompiled.js +1 -1
  227. package/third_party/closure-uri/uri.js +2 -2
  228. package/third_party/closure-uri/utils.js +2 -2
  229. package/third_party/language-mapping-list/language-mapping-list.js +1 -1
  230. package/ui/ad_statistics_button.js +9 -5
  231. package/ui/airplay_button.js +1 -0
  232. package/ui/audio_language_selection.js +2 -1
  233. package/ui/context_menu.js +2 -2
  234. package/ui/controls.js +7 -7
  235. package/ui/externs/ui.js +29 -21
  236. package/ui/externs/watermark.js +64 -0
  237. package/ui/fast_forward_button.js +1 -1
  238. package/ui/gl_matrix/matrix_4x4.js +11 -5
  239. package/ui/hidden_fast_forward_button.js +1 -1
  240. package/ui/hidden_seek_button.js +1 -1
  241. package/ui/language_utils.js +27 -26
  242. package/ui/less/buttons.less +2 -2
  243. package/ui/localization.js +21 -21
  244. package/ui/loop_button.js +2 -2
  245. package/ui/overflow_menu.js +2 -2
  246. package/ui/playback_rate_selection.js +1 -1
  247. package/ui/presentation_time.js +4 -1
  248. package/ui/range_element.js +2 -2
  249. package/ui/resolution_selection.js +42 -6
  250. package/ui/rewind_button.js +1 -1
  251. package/ui/seek_bar.js +5 -5
  252. package/ui/statistics_button.js +8 -4
  253. package/ui/text_selection.js +3 -2
  254. package/ui/ui.js +32 -2
  255. package/ui/vr_manager.js +3 -3
  256. package/ui/vr_utils.js +14 -14
  257. package/ui/vr_webgl.js +5 -5
  258. package/ui/watermark.js +313 -0
  259. package/.eslintignore +0 -4
  260. package/.eslintrc.js +0 -310
  261. package/lib/polyfill/patchedmediakeys_nop.js +0 -148
@@ -10,10 +10,12 @@ goog.provide('shaka.ads.InterstitialAdManager');
10
10
  goog.require('goog.asserts');
11
11
  goog.require('shaka.Player');
12
12
  goog.require('shaka.ads.InterstitialAd');
13
+ goog.require('shaka.ads.InterstitialStaticAd');
13
14
  goog.require('shaka.ads.Utils');
14
15
  goog.require('shaka.log');
15
16
  goog.require('shaka.media.PreloadManager');
16
17
  goog.require('shaka.net.NetworkingEngine');
18
+ goog.require('shaka.net.NetworkingUtils');
17
19
  goog.require('shaka.util.Dom');
18
20
  goog.require('shaka.util.Error');
19
21
  goog.require('shaka.util.EventManager');
@@ -63,14 +65,14 @@ shaka.ads.InterstitialAdManager = class {
63
65
  /** @private {function(!shaka.util.FakeEvent)} */
64
66
  this.onEvent_ = onEvent;
65
67
 
66
- /** @private {!Set.<string>} */
68
+ /** @private {!Set<string>} */
67
69
  this.interstitialIds_ = new Set();
68
70
 
69
- /** @private {!Set.<shaka.extern.AdInterstitial>} */
71
+ /** @private {!Set<shaka.extern.AdInterstitial>} */
70
72
  this.interstitials_ = new Set();
71
73
 
72
74
  /**
73
- * @private {!Map.<shaka.extern.AdInterstitial,
75
+ * @private {!Map<shaka.extern.AdInterstitial,
74
76
  * Promise<?shaka.media.PreloadManager>>}
75
77
  */
76
78
  this.preloadManagerInterstitials_ = new Map();
@@ -95,6 +97,12 @@ shaka.ads.InterstitialAdManager = class {
95
97
  /** @private {?shaka.extern.AdInterstitial} */
96
98
  this.lastPlayedAd_ = null;
97
99
 
100
+ /** @private {?shaka.util.Timer} */
101
+ this.playoutLimitTimer_ = null;
102
+
103
+ /** @private {?function()} */
104
+ this.lastOnSkip_ = null;
105
+
98
106
  this.eventManager_.listen(this.baseVideo_, 'timeupdate', () => {
99
107
  if (this.playingAd_ || this.lastTime_ ||
100
108
  this.basePlayer_.isRemotePlayback()) {
@@ -178,11 +186,14 @@ shaka.ads.InterstitialAdManager = class {
178
186
  this.interstitialIds_.delete(interstitialId);
179
187
  }
180
188
  this.interstitials_.delete(interstitial);
181
- cuepointsChanged = true;
189
+ if (!interstitial.overlay) {
190
+ cuepointsChanged = true;
191
+ }
182
192
  } else {
183
193
  const difference = interstitial.startTime - this.lastTime_;
184
194
  if (difference > 0 && difference <= 10) {
185
- if (!this.preloadManagerInterstitials_.has(interstitial)) {
195
+ if (!this.preloadManagerInterstitials_.has(interstitial) &&
196
+ this.isPreloadAllowed_(interstitial)) {
186
197
  this.preloadManagerInterstitials_.set(
187
198
  interstitial, this.player_.preload(
188
199
  interstitial.uri,
@@ -259,6 +270,16 @@ shaka.ads.InterstitialAdManager = class {
259
270
  this.playingAd_ = false;
260
271
  this.lastTime_ = null;
261
272
  this.lastPlayedAd_ = null;
273
+ this.usingBaseVideo_ = true;
274
+ this.video_ = this.baseVideo_;
275
+ this.adVideo_ = null;
276
+ if (this.adContainer_) {
277
+ shaka.util.Dom.removeAllChildren(this.adContainer_);
278
+ }
279
+ if (this.playoutLimitTimer_) {
280
+ this.playoutLimitTimer_.stop();
281
+ this.playoutLimitTimer_ = null;
282
+ }
262
283
  }
263
284
 
264
285
  /** @override */
@@ -270,9 +291,6 @@ shaka.ads.InterstitialAdManager = class {
270
291
  if (this.adEventManager_) {
271
292
  this.adEventManager_.release();
272
293
  }
273
- if (this.adContainer_) {
274
- shaka.util.Dom.removeAllChildren(this.adContainer_);
275
- }
276
294
  if (this.timeUpdateTimer_) {
277
295
  this.timeUpdateTimer_.stop();
278
296
  this.timeUpdateTimer_ = null;
@@ -284,6 +302,12 @@ shaka.ads.InterstitialAdManager = class {
284
302
  this.player_.destroy();
285
303
  }
286
304
 
305
+ /**
306
+ * @return {shaka.Player}
307
+ */
308
+ getPlayer() {
309
+ return this.player_;
310
+ }
287
311
 
288
312
  /**
289
313
  * @param {shaka.extern.HLSInterstitial} hlsInterstitial
@@ -303,14 +327,11 @@ shaka.ads.InterstitialAdManager = class {
303
327
  */
304
328
  addRegion(region) {
305
329
  let alternativeMPDUri;
306
- let alternativeMPDmode;
307
330
  for (const node of region.eventNode.children) {
308
331
  if (node.tagName == 'AlternativeMPD') {
309
332
  const uri = node.attributes['uri'];
310
- const mode = node.attributes['mode'];
311
333
  if (uri) {
312
334
  alternativeMPDUri = uri;
313
- alternativeMPDmode = mode;
314
335
  break;
315
336
  }
316
337
  }
@@ -319,8 +340,10 @@ shaka.ads.InterstitialAdManager = class {
319
340
  shaka.log.alwaysWarn('Unsupported MPD alternate', region);
320
341
  return;
321
342
  }
322
- const isReplace = alternativeMPDmode == 'replace';
323
- const isInsert = alternativeMPDmode == 'insert';
343
+ const isReplace =
344
+ region.schemeIdUri == 'urn:mpeg:dash:event:alternativeMPD:replace:2025';
345
+ const isInsert =
346
+ region.schemeIdUri == 'urn:mpeg:dash:event:alternativeMPD:insert:2025';
324
347
  if (!isReplace && !isInsert) {
325
348
  shaka.log.warning('Unsupported MPD alternate', region);
326
349
  return;
@@ -329,6 +352,7 @@ shaka.ads.InterstitialAdManager = class {
329
352
  /** @type {!shaka.extern.AdInterstitial} */
330
353
  const interstitial = {
331
354
  id: region.id,
355
+ groupId: null,
332
356
  startTime: region.startTime,
333
357
  endTime: region.endTime,
334
358
  uri: alternativeMPDUri,
@@ -343,6 +367,114 @@ shaka.ads.InterstitialAdManager = class {
343
367
  pre: false,
344
368
  post: false,
345
369
  timelineRange: isReplace && !isInsert,
370
+ loop: false,
371
+ overlay: null,
372
+ };
373
+ this.addInterstitials([interstitial]);
374
+ }
375
+
376
+ /**
377
+ * @param {shaka.extern.TimelineRegionInfo} region
378
+ */
379
+ addOverlayRegion(region) {
380
+ const TXml = shaka.util.TXml;
381
+
382
+ goog.asserts.assert(region.eventNode, 'Need a region eventNode');
383
+ const overlayEvent = TXml.findChild(region.eventNode, 'OverlayEvent');
384
+ const uri = overlayEvent.attributes['uri'];
385
+ const mimeType = overlayEvent.attributes['mimeType'];
386
+ const loop = overlayEvent.attributes['loop'] == 'true';
387
+ if (!uri || !mimeType) {
388
+ shaka.log.warning('Unsupported OverlayEvent', region);
389
+ return;
390
+ }
391
+
392
+ /** @type {!shaka.extern.AdInterstitialOverlay} */
393
+ let overlay = {
394
+ viewport: {
395
+ x: 1920,
396
+ y: 1080,
397
+ },
398
+ topLeft: {
399
+ x: 0,
400
+ y: 0,
401
+ },
402
+ size: {
403
+ x: 1920,
404
+ y: 1080,
405
+ },
406
+ };
407
+
408
+ const viewport = TXml.findChild(overlayEvent, 'Viewport');
409
+ const topLeft = TXml.findChild(overlayEvent, 'TopLeft');
410
+ const size = TXml.findChild(overlayEvent, 'Size');
411
+ if (viewport && topLeft && size) {
412
+ const viewportX = TXml.parseAttr(viewport, 'x', TXml.parseInt);
413
+ if (viewportX == null) {
414
+ shaka.log.warning('Unsupported OverlayEvent', region);
415
+ return;
416
+ }
417
+ const viewportY = TXml.parseAttr(viewport, 'y', TXml.parseInt);
418
+ if (viewportY == null) {
419
+ shaka.log.warning('Unsupported OverlayEvent', region);
420
+ return;
421
+ }
422
+ const topLeftX = TXml.parseAttr(topLeft, 'x', TXml.parseInt);
423
+ if (topLeftX == null) {
424
+ shaka.log.warning('Unsupported OverlayEvent', region);
425
+ return;
426
+ }
427
+ const topLeftY = TXml.parseAttr(topLeft, 'y', TXml.parseInt);
428
+ if (topLeftY == null) {
429
+ shaka.log.warning('Unsupported OverlayEvent', region);
430
+ return;
431
+ }
432
+ const sizeX = TXml.parseAttr(size, 'x', TXml.parseInt);
433
+ if (sizeX == null) {
434
+ shaka.log.warning('Unsupported OverlayEvent', region);
435
+ return;
436
+ }
437
+ const sizeY = TXml.parseAttr(size, 'y', TXml.parseInt);
438
+ if (sizeY == null) {
439
+ shaka.log.warning('Unsupported OverlayEvent', region);
440
+ return;
441
+ }
442
+ overlay = {
443
+ viewport: {
444
+ x: viewportX,
445
+ y: viewportY,
446
+ },
447
+ topLeft: {
448
+ x: topLeftX,
449
+ y: topLeftY,
450
+ },
451
+ size: {
452
+ x: sizeX,
453
+ y: sizeY,
454
+ },
455
+ };
456
+ }
457
+
458
+ /** @type {!shaka.extern.AdInterstitial} */
459
+ const interstitial = {
460
+ id: region.id,
461
+ groupId: null,
462
+ startTime: region.startTime,
463
+ endTime: region.endTime,
464
+ uri,
465
+ mimeType,
466
+ isSkippable: false,
467
+ skipOffset: null,
468
+ skipFor: null,
469
+ canJump: true,
470
+ resumeOffset: null,
471
+ playoutLimit: null,
472
+ once: false,
473
+ pre: false,
474
+ post: false,
475
+ timelineRange: true,
476
+ loop,
477
+ overlay,
346
478
  };
347
479
  this.addInterstitials([interstitial]);
348
480
  }
@@ -388,16 +520,36 @@ shaka.ads.InterstitialAdManager = class {
388
520
 
389
521
 
390
522
  /**
391
- * @param {!Array.<shaka.extern.AdInterstitial>} interstitials
523
+ * @param {!Array<shaka.extern.AdInterstitial>} interstitials
392
524
  */
393
- addInterstitials(interstitials) {
525
+ async addInterstitials(interstitials) {
394
526
  let cuepointsChanged = false;
395
527
  for (const interstitial of interstitials) {
528
+ if (!interstitial.uri) {
529
+ shaka.log.alwaysWarn('Missing URL in interstitial', interstitial);
530
+ continue;
531
+ }
532
+ if (!interstitial.mimeType) {
533
+ try {
534
+ const netEngine = this.player_.getNetworkingEngine();
535
+ goog.asserts.assert(netEngine, 'Need networking engine');
536
+ // eslint-disable-next-line no-await-in-loop
537
+ interstitial.mimeType = await shaka.net.NetworkingUtils.getMimeType(
538
+ interstitial.uri, netEngine,
539
+ this.basePlayer_.getConfiguration().streaming.retryParameters);
540
+ } catch (error) {}
541
+ }
396
542
  const interstitialId = interstitial.id || JSON.stringify(interstitial);
397
543
  if (this.interstitialIds_.has(interstitialId)) {
398
544
  continue;
399
545
  }
400
- cuepointsChanged = true;
546
+ if (interstitial.loop && !interstitial.overlay) {
547
+ shaka.log.alwaysWarn('Loop is only supported in overlay interstitials',
548
+ interstitial);
549
+ }
550
+ if (!interstitial.overlay) {
551
+ cuepointsChanged = true;
552
+ }
401
553
  this.interstitialIds_.add(interstitialId);
402
554
  this.interstitials_.add(interstitial);
403
555
  let shouldPreload = false;
@@ -412,7 +564,8 @@ shaka.ads.InterstitialAdManager = class {
412
564
  }
413
565
  }
414
566
  if (shouldPreload) {
415
- if (!this.preloadManagerInterstitials_.has(interstitial)) {
567
+ if (!this.preloadManagerInterstitials_.has(interstitial) &&
568
+ this.isPreloadAllowed_(interstitial)) {
416
569
  this.preloadManagerInterstitials_.set(
417
570
  interstitial, this.player_.preload(
418
571
  interstitial.uri,
@@ -440,6 +593,7 @@ shaka.ads.InterstitialAdManager = class {
440
593
  video.style.width = '100%';
441
594
  video.style.height = '100%';
442
595
  video.style.backgroundColor = 'rgb(0, 0, 0)';
596
+ video.style.display = 'none';
443
597
  video.setAttribute('playsinline', '');
444
598
  return video;
445
599
  }
@@ -520,17 +674,15 @@ shaka.ads.InterstitialAdManager = class {
520
674
  * @param {number=} oncePlayed
521
675
  * @private
522
676
  */
523
- async setupAd_(interstitial, sequenceLength, adPosition, initialTime,
677
+ setupAd_(interstitial, sequenceLength, adPosition, initialTime,
524
678
  oncePlayed = 0) {
525
- this.determineIfUsingBaseVideo_();
526
- goog.asserts.assert(this.video_, 'Must have video');
527
-
528
- this.lastPlayedAd_ = interstitial;
529
-
530
679
  shaka.log.info('Starting interstitial',
531
680
  interstitial.startTime, 'at', this.lastTime_);
532
681
 
533
- const startTime = Date.now();
682
+ this.lastPlayedAd_ = interstitial;
683
+
684
+ this.determineIfUsingBaseVideo_();
685
+ goog.asserts.assert(this.video_, 'Must have video');
534
686
 
535
687
  if (!this.video_.parentElement && this.adContainer_) {
536
688
  this.adContainer_.appendChild(this.video_);
@@ -550,8 +702,152 @@ shaka.ads.InterstitialAdManager = class {
550
702
  if (interstitial.once) {
551
703
  oncePlayed++;
552
704
  this.interstitials_.delete(interstitial);
553
- this.cuepointsChanged_();
705
+ if (!interstitial.overlay) {
706
+ this.cuepointsChanged_();
707
+ }
708
+ }
709
+
710
+ if (interstitial.mimeType) {
711
+ if (interstitial.mimeType.startsWith('image/') ||
712
+ interstitial.mimeType === 'text/html') {
713
+ if (!interstitial.overlay) {
714
+ shaka.log.alwaysWarn('Unsupported interstitial', interstitial);
715
+ return;
716
+ }
717
+ this.setupStaticAd_(interstitial, sequenceLength, adPosition,
718
+ oncePlayed);
719
+ return;
720
+ }
721
+ }
722
+ if (this.usingBaseVideo_ && interstitial.overlay) {
723
+ shaka.log.alwaysWarn('Unsupported interstitial', interstitial);
724
+ return;
725
+ }
726
+ this.setupVideoAd_(interstitial, sequenceLength, adPosition, initialTime,
727
+ oncePlayed);
728
+ }
729
+
730
+
731
+ /**
732
+ * @param {shaka.extern.AdInterstitial} interstitial
733
+ * @param {number} sequenceLength
734
+ * @param {number} adPosition
735
+ * @param {number} oncePlayed
736
+ * @private
737
+ */
738
+ setupStaticAd_(interstitial, sequenceLength, adPosition, oncePlayed) {
739
+ const overlay = interstitial.overlay;
740
+ goog.asserts.assert(overlay, 'Must have overlay');
741
+
742
+ const tagName = interstitial.mimeType == 'text/html' ? 'iframe' : 'img';
743
+
744
+ const htmlElement = /** @type {!(HTMLImageElement|HTMLIFrameElement)} */ (
745
+ document.createElement(tagName));
746
+ htmlElement.style.objectFit = 'contain';
747
+ htmlElement.style.position = 'absolute';
748
+ htmlElement.style.border = 'none';
749
+
750
+ const basicTask = () => {
751
+ if (this.playoutLimitTimer_) {
752
+ this.playoutLimitTimer_.stop();
753
+ this.playoutLimitTimer_ = null;
754
+ }
755
+ this.adContainer_.removeChild(htmlElement);
756
+ this.onEvent_(
757
+ new shaka.util.FakeEvent(shaka.ads.Utils.AD_STOPPED));
758
+ const nextCurrentInterstitial = this.getCurrentInterstitial_(
759
+ interstitial.pre, adPosition - oncePlayed);
760
+ if (nextCurrentInterstitial) {
761
+ this.adEventManager_.removeAll();
762
+ this.setupAd_(nextCurrentInterstitial, sequenceLength,
763
+ ++adPosition, /* initialTime= */ Date.now(), oncePlayed);
764
+ } else {
765
+ this.playingAd_ = false;
766
+ }
767
+ };
768
+
769
+ const ad = new shaka.ads.InterstitialStaticAd(
770
+ interstitial, sequenceLength, adPosition);
771
+
772
+ this.onEvent_(
773
+ new shaka.util.FakeEvent(shaka.ads.Utils.AD_STARTED,
774
+ (new Map()).set('ad', ad)));
775
+
776
+ if (tagName == 'iframe') {
777
+ htmlElement.src = interstitial.uri;
778
+ } else {
779
+ htmlElement.src = interstitial.uri;
780
+ htmlElement.onerror = (e) => {
781
+ this.onEvent_(new shaka.util.FakeEvent(shaka.ads.Utils.AD_ERROR,
782
+ (new Map()).set('originalEvent', e)));
783
+ basicTask();
784
+ };
554
785
  }
786
+
787
+ const viewport = overlay.viewport;
788
+ const topLeft = overlay.topLeft;
789
+ const size = overlay.size;
790
+ // Special case for VAST non-linear ads
791
+ if (viewport.x == 0 && viewport.y == 0) {
792
+ htmlElement.width = interstitial.overlay.size.x;
793
+ htmlElement.height = interstitial.overlay.size.y;
794
+ htmlElement.style.bottom = '10%';
795
+ htmlElement.style.left = '0';
796
+ htmlElement.style.right = '0';
797
+ htmlElement.style.width = '100%';
798
+ if (!interstitial.overlay.size.y && tagName == 'iframe') {
799
+ htmlElement.style.height = 'auto';
800
+ }
801
+ } else {
802
+ htmlElement.style.height = (size.y / viewport.y * 100) + '%';
803
+ htmlElement.style.left = (topLeft.x / viewport.x * 100) + '%';
804
+ htmlElement.style.top = (topLeft.y / viewport.y * 100) + '%';
805
+ htmlElement.style.width = (size.x / viewport.x * 100) + '%';
806
+ }
807
+ this.adContainer_.appendChild(htmlElement);
808
+
809
+ const startTime = Date.now();
810
+ if (this.playoutLimitTimer_) {
811
+ this.playoutLimitTimer_.stop();
812
+ }
813
+ this.playoutLimitTimer_ = new shaka.util.Timer(() => {
814
+ if (interstitial.playoutLimit &&
815
+ (Date.now() - startTime) / 1000 > interstitial.playoutLimit) {
816
+ this.onEvent_(
817
+ new shaka.util.FakeEvent(shaka.ads.Utils.AD_COMPLETE));
818
+ basicTask();
819
+ } else if (interstitial.endTime &&
820
+ this.baseVideo_.currentTime > interstitial.endTime) {
821
+ this.onEvent_(
822
+ new shaka.util.FakeEvent(shaka.ads.Utils.AD_COMPLETE));
823
+ basicTask();
824
+ } else if (this.baseVideo_.currentTime < interstitial.startTime) {
825
+ this.onEvent_(
826
+ new shaka.util.FakeEvent(shaka.ads.Utils.AD_SKIPPED));
827
+ basicTask();
828
+ }
829
+ });
830
+ if (interstitial.playoutLimit && !interstitial.endTime) {
831
+ this.playoutLimitTimer_.tickAfter(interstitial.playoutLimit);
832
+ } else if (interstitial.endTime) {
833
+ this.playoutLimitTimer_.tickEvery(/* seconds= */ 0.025);
834
+ }
835
+ }
836
+
837
+
838
+ /**
839
+ * @param {shaka.extern.AdInterstitial} interstitial
840
+ * @param {number} sequenceLength
841
+ * @param {number} adPosition
842
+ * @param {number} initialTime the clock time the ad started at
843
+ * @param {number} oncePlayed
844
+ * @private
845
+ */
846
+ async setupVideoAd_(interstitial, sequenceLength, adPosition, initialTime,
847
+ oncePlayed) {
848
+ goog.asserts.assert(this.video_, 'Must have video');
849
+ const startTime = Date.now();
850
+
555
851
  this.playingAd_ = true;
556
852
 
557
853
  if (this.usingBaseVideo_ && adPosition == 1) {
@@ -575,19 +871,34 @@ shaka.ads.InterstitialAdManager = class {
575
871
  await detachBasePlayerPromise;
576
872
  }
577
873
  if (!this.usingBaseVideo_) {
578
- this.baseVideo_.pause();
579
- if (interstitial.resumeOffset != null &&
580
- interstitial.resumeOffset != 0) {
581
- this.baseVideo_.currentTime += interstitial.resumeOffset;
874
+ this.video_.style.display = '';
875
+ if (interstitial.overlay) {
876
+ this.video_.loop = interstitial.loop;
877
+ const viewport = interstitial.overlay.viewport;
878
+ const topLeft = interstitial.overlay.topLeft;
879
+ const size = interstitial.overlay.size;
880
+ this.video_.style.height = (size.y / viewport.y * 100) + '%';
881
+ this.video_.style.left = (topLeft.x / viewport.x * 100) + '%';
882
+ this.video_.style.top = (topLeft.y / viewport.y * 100) + '%';
883
+ this.video_.style.width = (size.x / viewport.x * 100) + '%';
884
+ } else {
885
+ this.baseVideo_.pause();
886
+ if (interstitial.resumeOffset != null &&
887
+ interstitial.resumeOffset != 0) {
888
+ this.baseVideo_.currentTime += interstitial.resumeOffset;
889
+ }
890
+ this.video_.loop = false;
891
+ this.video_.style.height = '100%';
892
+ this.video_.style.left = '0';
893
+ this.video_.style.top = '0';
894
+ this.video_.style.width = '100%';
582
895
  }
583
896
  }
584
897
 
585
898
  let unloadingInterstitial = false;
586
- /** @type {?shaka.util.Timer} */
587
- let playoutLimitTimer = null;
588
899
 
589
900
  const updateBaseVideoTime = () => {
590
- if (!this.usingBaseVideo_) {
901
+ if (!this.usingBaseVideo_ && !interstitial.overlay) {
591
902
  if (interstitial.resumeOffset == null) {
592
903
  if (interstitial.timelineRange && interstitial.endTime &&
593
904
  interstitial.endTime != Infinity) {
@@ -603,24 +914,27 @@ shaka.ads.InterstitialAdManager = class {
603
914
  }
604
915
  };
605
916
 
606
- const basicTask = async () => {
917
+ const basicTask = async (isSkip) => {
607
918
  updateBaseVideoTime();
608
- if (playoutLimitTimer) {
609
- playoutLimitTimer.stop();
610
- }
611
- goog.asserts.assert(typeof(oncePlayed) == 'number',
612
- 'Should be an number!');
613
919
  // Optimization to avoid returning to main content when there is another
614
920
  // interstitial below.
615
- const nextCurrentInterstitial = this.getCurrentInterstitial_(
921
+ let nextCurrentInterstitial = this.getCurrentInterstitial_(
616
922
  interstitial.pre, adPosition - oncePlayed);
617
- if (nextCurrentInterstitial) {
618
- this.onEvent_(
619
- new shaka.util.FakeEvent(shaka.ads.Utils.AD_STOPPED));
620
- this.adEventManager_.removeAll();
621
- this.setupAd_(nextCurrentInterstitial, sequenceLength,
622
- ++adPosition, initialTime, oncePlayed);
623
- } else {
923
+ if (isSkip && interstitial.groupId) {
924
+ while (nextCurrentInterstitial &&
925
+ nextCurrentInterstitial.groupId == interstitial.groupId) {
926
+ adPosition++;
927
+ nextCurrentInterstitial = this.getCurrentInterstitial_(
928
+ interstitial.pre, adPosition - oncePlayed);
929
+ }
930
+ }
931
+ if (this.playoutLimitTimer_ && (!interstitial.groupId ||
932
+ (nextCurrentInterstitial &&
933
+ nextCurrentInterstitial.groupId != interstitial.groupId))) {
934
+ this.playoutLimitTimer_.stop();
935
+ this.playoutLimitTimer_ = null;
936
+ }
937
+ if (!nextCurrentInterstitial || nextCurrentInterstitial.overlay) {
624
938
  if (interstitial.post) {
625
939
  this.lastTime_ = null;
626
940
  this.lastPlayedAd_ = null;
@@ -649,6 +963,7 @@ shaka.ads.InterstitialAdManager = class {
649
963
  this.adEventManager_.removeAll();
650
964
  this.playingAd_ = false;
651
965
  if (!this.usingBaseVideo_) {
966
+ this.video_.style.display = 'none';
652
967
  updateBaseVideoTime();
653
968
  if (!this.baseVideo_.ended) {
654
969
  this.baseVideo_.play();
@@ -656,7 +971,14 @@ shaka.ads.InterstitialAdManager = class {
656
971
  } else {
657
972
  this.cuepointsChanged_();
658
973
  }
659
- this.determineIfUsingBaseVideo_();
974
+ }
975
+ this.determineIfUsingBaseVideo_();
976
+ if (nextCurrentInterstitial) {
977
+ this.onEvent_(
978
+ new shaka.util.FakeEvent(shaka.ads.Utils.AD_STOPPED));
979
+ this.adEventManager_.removeAll();
980
+ this.setupAd_(nextCurrentInterstitial, sequenceLength,
981
+ ++adPosition, initialTime, oncePlayed);
660
982
  }
661
983
  };
662
984
  const error = async (e) => {
@@ -666,29 +988,28 @@ shaka.ads.InterstitialAdManager = class {
666
988
  unloadingInterstitial = true;
667
989
  this.onEvent_(new shaka.util.FakeEvent(shaka.ads.Utils.AD_ERROR,
668
990
  (new Map()).set('originalEvent', e)));
669
- await basicTask();
991
+ await basicTask(/* isSkip= */ false);
670
992
  };
671
993
  const complete = async () => {
672
994
  if (unloadingInterstitial) {
673
995
  return;
674
996
  }
675
997
  unloadingInterstitial = true;
676
- await basicTask();
998
+ await basicTask(/* isSkip= */ false);
677
999
  this.onEvent_(
678
1000
  new shaka.util.FakeEvent(shaka.ads.Utils.AD_COMPLETE));
679
1001
  };
680
- const onSkip = async () => {
1002
+ this.lastOnSkip_ = async () => {
681
1003
  if (unloadingInterstitial) {
682
1004
  return;
683
1005
  }
684
1006
  unloadingInterstitial = true;
685
1007
  this.onEvent_(new shaka.util.FakeEvent(shaka.ads.Utils.AD_SKIPPED));
686
- await basicTask();
1008
+ await basicTask(/* isSkip= */ true);
687
1009
  };
688
1010
 
689
1011
  const ad = new shaka.ads.InterstitialAd(this.video_,
690
- interstitial.isSkippable, interstitial.skipOffset,
691
- interstitial.skipFor, onSkip, sequenceLength, adPosition,
1012
+ interstitial, this.lastOnSkip_, sequenceLength, adPosition,
692
1013
  !this.usingBaseVideo_);
693
1014
  if (!this.usingBaseVideo_) {
694
1015
  ad.setMuted(this.baseVideo_.muted);
@@ -768,9 +1089,9 @@ shaka.ads.InterstitialAdManager = class {
768
1089
  this.player_.configure('playRangeEnd', duration);
769
1090
  }
770
1091
  }
771
- if (interstitial.playoutLimit) {
772
- playoutLimitTimer = new shaka.util.Timer(() => {
773
- ad.skip();
1092
+ if (interstitial.playoutLimit && !this.playoutLimitTimer_) {
1093
+ this.playoutLimitTimer_ = new shaka.util.Timer(() => {
1094
+ this.lastOnSkip_();
774
1095
  }).tickAfter(interstitial.playoutLimit);
775
1096
  this.player_.configure('playRangeEnd', interstitial.playoutLimit);
776
1097
  }
@@ -793,14 +1114,6 @@ shaka.ads.InterstitialAdManager = class {
793
1114
  /* startTime= */ null,
794
1115
  interstitial.mimeType || undefined);
795
1116
  }
796
- if (interstitial.playoutLimit) {
797
- if (playoutLimitTimer) {
798
- playoutLimitTimer.stop();
799
- }
800
- playoutLimitTimer = new shaka.util.Timer(() => {
801
- ad.skip();
802
- }).tickAfter(interstitial.playoutLimit);
803
- }
804
1117
  const loadTime = (Date.now() - startTime) / 1000;
805
1118
  this.onEvent_(new shaka.util.FakeEvent(shaka.ads.Utils.ADS_LOADED,
806
1119
  (new Map()).set('loadTime', loadTime)));
@@ -808,6 +1121,9 @@ shaka.ads.InterstitialAdManager = class {
808
1121
  this.baseVideo_.play();
809
1122
  }
810
1123
  } catch (e) {
1124
+ if (!this.playingAd_) {
1125
+ return;
1126
+ }
811
1127
  error(e);
812
1128
  }
813
1129
  }
@@ -815,7 +1131,7 @@ shaka.ads.InterstitialAdManager = class {
815
1131
 
816
1132
  /**
817
1133
  * @param {shaka.extern.HLSInterstitial} hlsInterstitial
818
- * @return {!Promise.<!Array.<shaka.extern.AdInterstitial>>}
1134
+ * @return {!Promise<!Array<shaka.extern.AdInterstitial>>}
819
1135
  * @private
820
1136
  */
821
1137
  async getInterstitialsInfo_(hlsInterstitial) {
@@ -918,6 +1234,7 @@ shaka.ads.InterstitialAdManager = class {
918
1234
  }
919
1235
  interstitialsAd.push({
920
1236
  id,
1237
+ groupId: null,
921
1238
  startTime,
922
1239
  endTime,
923
1240
  uri,
@@ -932,6 +1249,8 @@ shaka.ads.InterstitialAdManager = class {
932
1249
  pre,
933
1250
  post,
934
1251
  timelineRange,
1252
+ loop: false,
1253
+ overlay: null,
935
1254
  });
936
1255
  } else if (assetList) {
937
1256
  const uri = /** @type {string} */(assetList.data);
@@ -969,7 +1288,8 @@ shaka.ads.InterstitialAdManager = class {
969
1288
  const asset = dataAsJson['ASSETS'][i];
970
1289
  if (asset['URI']) {
971
1290
  interstitialsAd.push({
972
- id: id + '_asset_' + i,
1291
+ id: id + '_shaka_asset_' + i,
1292
+ groupId: id,
973
1293
  startTime,
974
1294
  endTime,
975
1295
  uri: asset['URI'],
@@ -984,6 +1304,8 @@ shaka.ads.InterstitialAdManager = class {
984
1304
  pre,
985
1305
  post,
986
1306
  timelineRange,
1307
+ loop: false,
1308
+ overlay: null,
987
1309
  });
988
1310
  }
989
1311
  }
@@ -999,9 +1321,12 @@ shaka.ads.InterstitialAdManager = class {
999
1321
  * @private
1000
1322
  */
1001
1323
  cuepointsChanged_() {
1002
- /** @type {!Array.<!shaka.extern.AdCuePoint>} */
1324
+ /** @type {!Array<!shaka.extern.AdCuePoint>} */
1003
1325
  const cuePoints = [];
1004
1326
  for (const interstitial of this.interstitials_) {
1327
+ if (interstitial.overlay) {
1328
+ continue;
1329
+ }
1005
1330
  /** @type {shaka.extern.AdCuePoint} */
1006
1331
  const shakaCuePoint = {
1007
1332
  start: interstitial.startTime,
@@ -1041,15 +1366,13 @@ shaka.ads.InterstitialAdManager = class {
1041
1366
  this.player_.configure('ads.disableDASHInterstitial', true);
1042
1367
  const netEngine = this.player_.getNetworkingEngine();
1043
1368
  goog.asserts.assert(netEngine, 'Need networking engine');
1044
- netEngine.clearAllRequestFilters();
1045
- netEngine.clearAllResponseFilters();
1046
1369
  this.basePlayer_.getNetworkingEngine().copyFiltersInto(netEngine);
1047
1370
  }
1048
1371
 
1049
1372
  /**
1050
1373
  * @param {string} url
1051
1374
  * @param {shaka.extern.RequestContext=} context
1052
- * @return {!Promise.<BufferSource>}
1375
+ * @return {!Promise<BufferSource>}
1053
1376
  * @private
1054
1377
  */
1055
1378
  async makeAdRequest_(url, context) {
@@ -1062,16 +1385,40 @@ shaka.ads.InterstitialAdManager = class {
1062
1385
  const response = await op.promise;
1063
1386
  return response.data;
1064
1387
  }
1388
+
1389
+ /**
1390
+ * @param {!shaka.extern.AdInterstitial} interstitial
1391
+ * @return {boolean}
1392
+ * @private
1393
+ */
1394
+ isPreloadAllowed_(interstitial) {
1395
+ const interstitialMimeType = interstitial.mimeType;
1396
+ if (!interstitialMimeType) {
1397
+ return true;
1398
+ }
1399
+ return !interstitialMimeType.startsWith('image/') &&
1400
+ interstitialMimeType !== 'text/html';
1401
+ }
1402
+
1403
+
1404
+ /**
1405
+ * Only for testing
1406
+ *
1407
+ * @return {!Array<shaka.extern.AdInterstitial>}
1408
+ */
1409
+ getInterstitials() {
1410
+ return Array.from(this.interstitials_);
1411
+ }
1065
1412
  };
1066
1413
 
1067
1414
 
1068
1415
  /**
1069
1416
  * @typedef {{
1070
- * ASSETS: !Array.<shaka.ads.InterstitialAdManager.Asset>,
1417
+ * ASSETS: !Array<shaka.ads.InterstitialAdManager.Asset>,
1071
1418
  * SKIP-CONTROL: ?shaka.ads.InterstitialAdManager.SkipControl
1072
1419
  * }}
1073
1420
  *
1074
- * @property {!Array.<shaka.ads.InterstitialAdManager.Asset>} ASSETS
1421
+ * @property {!Array<shaka.ads.InterstitialAdManager.Asset>} ASSETS
1075
1422
  * @property {shaka.ads.InterstitialAdManager.SkipControl} SKIP-CONTROL
1076
1423
  */
1077
1424
  shaka.ads.InterstitialAdManager.AssetsList;