shaka-player 3.1.2 → 3.1.6

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 (145) hide show
  1. package/.github/workflows/build_and_test.yaml +73 -0
  2. package/.github/workflows/release.yaml +53 -0
  3. package/AUTHORS +3 -0
  4. package/CHANGELOG.md +170 -1
  5. package/CONTRIBUTORS +3 -0
  6. package/build/checkversion.py +1 -1
  7. package/build/generateExterns.js +1 -1
  8. package/build/misspellings.txt +1 -0
  9. package/build/shakaBuildHelpers.py +6 -5
  10. package/build/subprocessWindowsPatch.py +103 -0
  11. package/build/test.py +6 -0
  12. package/demo/common/assets.js +1 -1
  13. package/dist/controls.css +2 -2
  14. package/dist/controls.css.map +1 -1
  15. package/dist/demo.compiled.debug.js +1 -1
  16. package/dist/demo.compiled.js +1 -1
  17. package/dist/deps.js +7 -7
  18. package/dist/locales.js +35 -35
  19. package/dist/receiver.compiled.debug.js +1 -1
  20. package/dist/receiver.compiled.js +1 -1
  21. package/dist/shaka-player.compiled.d.ts +172 -3
  22. package/dist/shaka-player.compiled.debug.d.ts +172 -3
  23. package/dist/shaka-player.compiled.debug.externs.js +184 -1
  24. package/dist/shaka-player.compiled.debug.js +390 -370
  25. package/dist/shaka-player.compiled.debug.map +3 -3
  26. package/dist/shaka-player.compiled.externs.js +184 -1
  27. package/dist/shaka-player.compiled.js +809 -805
  28. package/dist/shaka-player.compiled.map +3 -3
  29. package/dist/shaka-player.ui.d.ts +174 -14
  30. package/dist/shaka-player.ui.debug.d.ts +174 -14
  31. package/dist/shaka-player.ui.debug.externs.js +200 -26
  32. package/dist/shaka-player.ui.debug.js +431 -412
  33. package/dist/shaka-player.ui.debug.map +4 -4
  34. package/dist/shaka-player.ui.externs.js +200 -26
  35. package/dist/shaka-player.ui.js +934 -929
  36. package/dist/shaka-player.ui.map +4 -4
  37. package/docs/tutorials/fairplay.md +1 -1
  38. package/docs/tutorials/faq.md +14 -0
  39. package/externs/ima.js +4 -0
  40. package/externs/shaka/ads.js +2 -0
  41. package/externs/shaka/text.js +10 -0
  42. package/karma.conf.js +20 -15
  43. package/lib/ads/ad_manager.js +30 -11
  44. package/lib/ads/client_side_ad_manager.js +76 -86
  45. package/lib/ads/server_side_ad_manager.js +26 -11
  46. package/lib/cast/cast_proxy.js +6 -2
  47. package/lib/cast/cast_receiver.js +5 -1
  48. package/lib/cast/cast_sender.js +2 -2
  49. package/lib/cea/sei_processor.js +24 -17
  50. package/lib/dash/dash_parser.js +131 -24
  51. package/lib/dash/segment_list.js +1 -1
  52. package/lib/dash/segment_template.js +1 -1
  53. package/lib/hls/hls_parser.js +44 -17
  54. package/lib/hls/manifest_text_parser.js +1 -0
  55. package/lib/media/closed_caption_parser.js +3 -1
  56. package/lib/media/content_workarounds.js +12 -0
  57. package/lib/media/drm_engine.js +20 -1
  58. package/lib/media/gap_jumping_controller.js +8 -4
  59. package/lib/media/media_source_engine.js +1 -2
  60. package/lib/media/playhead.js +1 -1
  61. package/lib/media/region_observer.js +39 -33
  62. package/lib/media/region_timeline.js +17 -19
  63. package/lib/media/streaming_engine.js +8 -4
  64. package/lib/net/networking_engine.js +6 -1
  65. package/lib/offline/storage.js +10 -11
  66. package/lib/player.js +66 -30
  67. package/lib/polyfill/encryption_scheme.js +2 -0
  68. package/lib/polyfill/fullscreen.js +2 -0
  69. package/lib/polyfill/mathround.js +2 -0
  70. package/lib/polyfill/media_capabilities.js +73 -21
  71. package/lib/polyfill/mediasource.js +8 -0
  72. package/lib/polyfill/orientation.js +3 -1
  73. package/lib/polyfill/patchedmediakeys_apple.js +6 -4
  74. package/lib/polyfill/patchedmediakeys_ms.js +6 -4
  75. package/lib/polyfill/patchedmediakeys_nop.js +2 -0
  76. package/lib/polyfill/patchedmediakeys_webkit.js +6 -4
  77. package/lib/polyfill/pip_webkit.js +2 -0
  78. package/lib/polyfill/storage_estimate.js +2 -0
  79. package/lib/polyfill/video_play_promise.js +2 -0
  80. package/lib/polyfill/videoplaybackquality.js +2 -0
  81. package/lib/polyfill/vttcue.js +2 -0
  82. package/lib/text/cue.js +6 -0
  83. package/lib/text/mp4_ttml_parser.js +3 -0
  84. package/lib/text/text_engine.js +14 -2
  85. package/lib/text/ttml_text_parser.js +135 -87
  86. package/lib/text/ui_text_displayer.js +213 -80
  87. package/lib/text/vtt_text_parser.js +4 -2
  88. package/lib/util/fake_event.js +53 -7
  89. package/lib/util/fake_event_target.js +21 -1
  90. package/lib/util/mp4_box_parsers.js +1 -1
  91. package/lib/util/periods.js +4 -1
  92. package/lib/util/platform.js +13 -1
  93. package/lib/util/stream_utils.js +77 -10
  94. package/lib/util/xml_utils.js +19 -0
  95. package/package.json +3 -6
  96. package/test/cast/cast_proxy_unit.js +12 -6
  97. package/test/cast/cast_receiver_integration.js +1 -1
  98. package/test/cast/cast_utils_unit.js +1 -1
  99. package/test/cea/mp4_cea_parser_unit.js +26 -0
  100. package/test/dash/dash_parser_live_unit.js +43 -0
  101. package/test/dash/dash_parser_manifest_unit.js +222 -3
  102. package/test/hls/hls_parser_unit.js +79 -1
  103. package/test/media/closed_caption_parser_unit.js +20 -0
  104. package/test/media/drm_engine_unit.js +56 -0
  105. package/test/media/playhead_unit.js +27 -1
  106. package/test/media/region_observer_unit.js +40 -5
  107. package/test/media/region_timeline_unit.js +40 -22
  108. package/test/media/streaming_engine_integration.js +2 -1
  109. package/test/media/streaming_engine_unit.js +145 -0
  110. package/test/player_integration.js +38 -0
  111. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  112. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  113. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  114. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  115. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  116. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  117. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  118. package/test/test/assets/3675/dash_0.mpd +30 -0
  119. package/test/test/assets/3675/dash_1.mpd +30 -0
  120. package/test/test/assets/3675/dash_2.mpd +30 -0
  121. package/test/test/assets/3675/dash_3.mpd +30 -0
  122. package/test/test/assets/3675/dash_4.mpd +30 -0
  123. package/test/test/assets/3675/dash_5.mpd +26 -0
  124. package/test/test/assets/3675/init-stream0.m4s +0 -0
  125. package/test/test/assets/empty_caption_video_init.mp4 +0 -0
  126. package/test/test/assets/empty_caption_video_segment.mp4 +0 -0
  127. package/test/test/util/fake_ad_manager.js +4 -1
  128. package/test/test/util/ttml_utils.js +81 -0
  129. package/test/test/util/util.js +10 -7
  130. package/test/text/mp4_ttml_parser_unit.js +11 -18
  131. package/test/text/ttml_text_parser_unit.js +542 -220
  132. package/test/text/ui_text_displayer_unit.js +93 -20
  133. package/test/text/vtt_text_parser_unit.js +17 -1
  134. package/test/ui/localization_unit.js +15 -14
  135. package/test/ui/text_displayer_layout_unit.js +21 -8
  136. package/test/util/mp4_box_parsers_unit.js +28 -0
  137. package/test/util/stream_utils_unit.js +59 -2
  138. package/ui/cast_button.js +2 -3
  139. package/ui/controls.js +11 -6
  140. package/ui/less/buttons.less +0 -4
  141. package/ui/less/containers.less +6 -7
  142. package/ui/locales/ru.json +6 -6
  143. package/ui/localization.js +40 -87
  144. package/ui/pip_button.js +2 -3
  145. package/ui/text_selection.js +1 -0
@@ -31,7 +31,7 @@ player.configure('drm.initDataTransform', (initData, initDataType) => {
31
31
 
32
32
  // 'initData' is a buffer containing an 'skd://' URL as a UTF-8 string.
33
33
  const skdUri = shaka.util.StringUtils.fromBytesAutoDetect(initData);
34
- const contentId = getMyContentId(sdkUri);
34
+ const contentId = getMyContentId(skdUri);
35
35
  const cert = player.drmInfo().serverCertificate;
36
36
  return shaka.util.FairPlayUtils.initDataTransform(initData, contentId, cert);
37
37
  });
@@ -260,6 +260,20 @@ the {@link shaka.extern.ManifestConfiguration|`.manifest.disableVideo`} or
260
260
  configurations to signal that your content does not have a video or audio
261
261
  stream.
262
262
 
263
+ <hr>
264
+
265
+ **Q:** How can I make Shaka Player work with Vue?
266
+
267
+ **A:** Currently, Shaka Player does not support being made into a Vue reactive
268
+ object. When Vue wraps an object in a reactive Proxy, it
269
+ {@link https://v3.vuejs.org/guide/reactivity.html#proxied-objects|also wraps
270
+ nested objects}. This results in Vue converting some of our internal values into
271
+ Proxy objects, which causes failures at load-time.
272
+ If you want to use Shaka Player in Vue, avoid making it into a reactive object;
273
+ so don't declare it using a ref(), and if you put your player instance into a
274
+ data() object, you can prefix the property name with "$" or "_" to make Vue not
275
+ proxy them.
276
+
263
277
  [386]: https://github.com/google/shaka-player/issues/386#issuecomment-227898001
264
278
  [489]: https://github.com/google/shaka-player/issues/489#issuecomment-240466224
265
279
  [743]: https://github.com/google/shaka-player/issues/743
package/externs/ima.js CHANGED
@@ -43,6 +43,8 @@ google.ima.AdsLoader = class {
43
43
 
44
44
  /** @override */
45
45
  dispatchEvent() {}
46
+
47
+ destroy() {}
46
48
  };
47
49
 
48
50
 
@@ -79,6 +81,8 @@ google.ima.AdsManager = class {
79
81
 
80
82
  stop() {}
81
83
 
84
+ destroy() {}
85
+
82
86
  /**
83
87
  * @param {number} volume
84
88
  */
@@ -46,6 +46,8 @@ shaka.extern.IAdManager = class extends EventTarget {
46
46
  */
47
47
  setLocale(locale) {}
48
48
 
49
+ release() {}
50
+
49
51
  onAssetUnload() {}
50
52
 
51
53
  /**
@@ -349,6 +349,16 @@ shaka.extern.Cue = class {
349
349
  */
350
350
  this.nestedCues;
351
351
 
352
+ /**
353
+ * If true, this represents a container element that is "above" the main
354
+ * cues. For example, the <body> and <div> tags that contain the <p> tags
355
+ * in a TTML file. This controls the flow of the final cues; any nested cues
356
+ * within an "isContainer" cue will be laid out as separate lines.
357
+ * @type {boolean}
358
+ * @exportDoc
359
+ */
360
+ this.isContainer;
361
+
352
362
  /**
353
363
  * Whether or not the cue only acts as a line break between two nested cues.
354
364
  * Should only appear in nested cues.
package/karma.conf.js CHANGED
@@ -11,6 +11,7 @@ const Jimp = require('jimp');
11
11
  const fs = require('fs');
12
12
  const path = require('path');
13
13
  const rimraf = require('rimraf');
14
+ const {ssim} = require('ssim.js');
14
15
  const util = require('karma/common/util');
15
16
  const which = require('which');
16
17
 
@@ -140,6 +141,7 @@ module.exports = (config) => {
140
141
  included: false,
141
142
  },
142
143
  {pattern: 'test/test/assets/*', included: false},
144
+ {pattern: 'test/test/assets/3675/*', included: false},
143
145
  {pattern: 'dist/shaka-player.ui.js', included: false},
144
146
  {pattern: 'dist/locales.js', included: false},
145
147
  {pattern: 'demo/locales/en.json', included: false},
@@ -335,6 +337,10 @@ module.exports = (config) => {
335
337
 
336
338
  config.set({reporters: reporters});
337
339
 
340
+ if (reporters.includes('spec') && settings.spec_hide_passed) {
341
+ config.set({specReporter: {suppressPassed: true}});
342
+ }
343
+
338
344
  if (settings.random) {
339
345
  // If --seed was specified use that value, else generate a seed so that the
340
346
  // exact order can be reproduced if it catches an issue.
@@ -517,8 +523,7 @@ function WebDriverScreenshotMiddlewareFactory(launcher) {
517
523
  *
518
524
  * @param {karma.Launcher.Browser} browser
519
525
  * @param {!Object.<string, string>} params
520
- * @return {!Promise.<number>} The number of pixels changed between the old
521
- * and new screenshots, after cropping and scaling.
526
+ * @return {!Promise.<number>} A similarity score between 0 and 1.
522
527
  */
523
528
  async function diffScreenshot(browser, params) {
524
529
  const webDriverClient = getWebDriverClient(browser);
@@ -603,22 +608,22 @@ function WebDriverScreenshotMiddlewareFactory(launcher) {
603
608
  // Compare the new screenshot to the old one and produce a diff image.
604
609
  // Initially, the image data will be raw pixels, 4 bytes per pixel.
605
610
  // The threshold parameter affects the sensitivity of individual pixel
606
- // comparisons. Setting it too low means small rendering changes in the
607
- // browser can cause failures even when a human can't see the difference,
608
- // and setting it too high means human-noticeable changes could go
609
- // undetected by a test.
610
- const diff = Jimp.diff(oldScreenshot, newScreenshot, /* threshold= */ 0.07);
611
+ // comparisons. This diff is only used for visual review, not for
612
+ // automated similarity checks, so the threshold setting is not so critical
613
+ // as it used to be.
614
+ const threshold = 0.10;
615
+ const diff = Jimp.diff(oldScreenshot, newScreenshot, threshold);
611
616
 
612
617
  // Write the diff to disk. This is used to review when there are changes.
618
+ const fullSizeDiff =
619
+ diff.image.clone().resize(width, height, Jimp.RESIZE_BICUBIC);
613
620
  fs.writeFileSync(
614
- diffScreenshotPath, await diff.image.getBufferAsync('image/png'));
615
-
616
- // "percent" is, surprisingly, a number between 0 and 1, not between 0 and
617
- // 100. Convert this to a number of pixels changed, which has been found to
618
- // be a more effective and less flaky metric.
619
- const pixelsChanged =
620
- diff.percent * diff.image.bitmap.width * diff.image.bitmap.height;
621
- return pixelsChanged;
621
+ diffScreenshotPath, await fullSizeDiff.getBufferAsync('image/png'));
622
+
623
+ // Compare with a structural similarity algorithm. This produces a
624
+ // similarity score that we will use to pass or fail the test.
625
+ const ssimResult = ssim(oldScreenshot.bitmap, newScreenshot.bitmap);
626
+ return ssimResult.mssim; // A score between 0 and 1.
622
627
  }
623
628
 
624
629
  /**
@@ -16,6 +16,7 @@ goog.require('shaka.log');
16
16
  goog.require('shaka.util.Error');
17
17
  goog.require('shaka.util.FakeEvent');
18
18
  goog.require('shaka.util.FakeEventTarget');
19
+ goog.require('shaka.util.IReleasable');
19
20
 
20
21
 
21
22
  /**
@@ -359,6 +360,7 @@ goog.require('shaka.util.FakeEventTarget');
359
360
  /**
360
361
  * A class responsible for ad-related interactions.
361
362
  * @implements {shaka.extern.IAdManager}
363
+ * @implements {shaka.util.IReleasable}
362
364
  * @export
363
365
  */
364
366
  shaka.ads.AdManager = class extends shaka.util.FakeEventTarget {
@@ -403,6 +405,10 @@ shaka.ads.AdManager = class extends shaka.util.FakeEventTarget {
403
405
  shaka.util.Error.Code.CS_IMA_SDK_MISSING);
404
406
  }
405
407
 
408
+ if (this.csAdManager_) {
409
+ this.csAdManager_.release();
410
+ }
411
+
406
412
  this.csAdManager_ = new shaka.ads.ClientSideAdManager(
407
413
  adContainer, video, this.locale_,
408
414
  (e) => {
@@ -430,6 +436,23 @@ shaka.ads.AdManager = class extends shaka.util.FakeEventTarget {
430
436
  }
431
437
 
432
438
 
439
+ /**
440
+ * @override
441
+ * @export
442
+ */
443
+ release() {
444
+ if (this.csAdManager_) {
445
+ this.csAdManager_.release();
446
+ this.csAdManager_ = null;
447
+ }
448
+ if (this.ssAdManager_) {
449
+ this.ssAdManager_.release();
450
+ this.ssAdManager_ = null;
451
+ }
452
+ super.release();
453
+ }
454
+
455
+
433
456
  /**
434
457
  * @override
435
458
  * @export
@@ -438,21 +461,13 @@ shaka.ads.AdManager = class extends shaka.util.FakeEventTarget {
438
461
  if (this.csAdManager_) {
439
462
  this.csAdManager_.stop();
440
463
  }
464
+ if (this.ssAdManager_) {
465
+ this.ssAdManager_.stop();
466
+ }
441
467
 
442
468
  this.dispatchEvent(
443
469
  new shaka.util.FakeEvent(shaka.ads.AdManager.AD_STOPPED));
444
470
 
445
- // TODO:
446
- // For SS DAI streams, if a different asset gets unloaded as
447
- // part of the process
448
- // of loading a DAI asset, stream manager state gets reset and we
449
- // don't get any ad events.
450
- // We need to figure out if it makes sense to stop the SS
451
- // manager on unload, and, if it does, find
452
- // a way to do it safely.
453
- // if (this.ssAdManager_) {
454
- // this.ssAdManager_.stop();
455
- // }
456
471
  this.stats_ = new shaka.ads.AdsStats();
457
472
  }
458
473
 
@@ -491,6 +506,10 @@ shaka.ads.AdManager = class extends shaka.util.FakeEventTarget {
491
506
  shaka.util.Error.Code.SS_IMA_SDK_MISSING);
492
507
  }
493
508
 
509
+ if (this.ssAdManager_) {
510
+ this.ssAdManager_.release();
511
+ }
512
+
494
513
  this.ssAdManager_ = new shaka.ads.ServerSideAdManager(
495
514
  adContainer, video, this.locale_,
496
515
  (e) => {
@@ -13,10 +13,12 @@ goog.provide('shaka.ads.ClientSideAdManager');
13
13
 
14
14
  goog.require('goog.asserts');
15
15
  goog.require('shaka.ads.ClientSideAd');
16
+ goog.require('shaka.util.IReleasable');
16
17
 
17
18
 
18
19
  /**
19
20
  * A class responsible for client-side ad interactions.
21
+ * @implements {shaka.util.IReleasable}
20
22
  */
21
23
  shaka.ads.ClientSideAdManager = class {
22
24
  /**
@@ -32,6 +34,9 @@ shaka.ads.ClientSideAdManager = class {
32
34
  /** @private {HTMLMediaElement} */
33
35
  this.video_ = video;
34
36
 
37
+ /** @private {ResizeObserver} */
38
+ this.resizeObserver_ = null;
39
+
35
40
  /** @private {number} */
36
41
  this.requestAdsStartTime_ = NaN;
37
42
 
@@ -106,6 +111,21 @@ shaka.ads.ClientSideAdManager = class {
106
111
  }
107
112
  }
108
113
 
114
+ /** @override */
115
+ release() {
116
+ this.stop();
117
+ if (this.resizeObserver_) {
118
+ this.resizeObserver_.disconnect();
119
+ }
120
+ if (this.eventManager_) {
121
+ this.eventManager_.release();
122
+ }
123
+ if (this.imaAdsManager_) {
124
+ this.imaAdsManager_.destroy();
125
+ }
126
+ this.adsLoader_.destroy();
127
+ }
128
+
109
129
  /**
110
130
  * @param {!google.ima.AdErrorEvent} e
111
131
  * @private
@@ -118,7 +138,7 @@ shaka.ads.ClientSideAdManager = class {
118
138
  // Remove ad breaks from the timeline
119
139
  this.onEvent_(
120
140
  new shaka.util.FakeEvent(shaka.ads.AdManager.CUEPOINTS_CHANGED,
121
- {'cuepoints': []}));
141
+ (new Map()).set('cuepoints', [])));
122
142
  }
123
143
 
124
144
 
@@ -131,17 +151,14 @@ shaka.ads.ClientSideAdManager = class {
131
151
 
132
152
  const now = Date.now() / 1000;
133
153
  const loadTime = now - this.requestAdsStartTime_;
134
- this.onEvent_(
135
- new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
136
- {'loadTime': loadTime}));
154
+ this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
155
+ (new Map()).set('loadTime', loadTime)));
137
156
 
138
157
  this.imaAdsManager_ = e.getAdsManager(this.video_);
139
158
 
140
159
  this.onEvent_(new shaka.util.FakeEvent(
141
160
  shaka.ads.AdManager.IMA_AD_MANAGER_LOADED,
142
- {
143
- 'imaAdManager': this.imaAdsManager_,
144
- }));
161
+ (new Map()).set('imaAdManager', this.imaAdsManager_)));
145
162
 
146
163
  const cuePointStarts = this.imaAdsManager_.getCuePoints();
147
164
  if (cuePointStarts.length) {
@@ -152,9 +169,9 @@ shaka.ads.ClientSideAdManager = class {
152
169
  cuePoints.push(shakaCuePoint);
153
170
  }
154
171
 
155
- this.onEvent_(
156
- new shaka.util.FakeEvent(shaka.ads.AdManager.CUEPOINTS_CHANGED,
157
- {'cuepoints': cuePoints}));
172
+ this.onEvent_(new shaka.util.FakeEvent(
173
+ shaka.ads.AdManager.CUEPOINTS_CHANGED,
174
+ (new Map()).set('cuepoints', cuePoints)));
158
175
  }
159
176
 
160
177
  this.addImaEventListeners_();
@@ -176,6 +193,16 @@ shaka.ads.ClientSideAdManager = class {
176
193
  this.video_.offsetHeight, viewMode);
177
194
  });
178
195
 
196
+ if ('ResizeObserver' in window) {
197
+ this.resizeObserver_ = new ResizeObserver(() => {
198
+ const viewMode = document.fullscreenElement ?
199
+ google.ima.ViewMode.FULLSCREEN : google.ima.ViewMode.NORMAL;
200
+ this.imaAdsManager_.resize(this.video_.offsetWidth,
201
+ this.video_.offsetHeight, viewMode);
202
+ });
203
+ this.resizeObserver_.observe(this.video_);
204
+ }
205
+
179
206
  // Single video and overlay ads will start at this time
180
207
  // TODO (ismena): Need a better inderstanding of what this does.
181
208
  // The docs say it's called to 'start playing the ads,' but I haven't
@@ -194,6 +221,15 @@ shaka.ads.ClientSideAdManager = class {
194
221
  * @private
195
222
  */
196
223
  addImaEventListeners_() {
224
+ /**
225
+ * @param {!Event} e
226
+ * @param {string} type
227
+ */
228
+ const convertEventAndSend = (e, type) => {
229
+ const data = (new Map()).set('originalEvent', e);
230
+ this.onEvent_(new shaka.util.FakeEvent(type, data));
231
+ };
232
+
197
233
  this.eventManager_.listen(this.imaAdsManager_,
198
234
  google.ima.AdErrorEvent.Type.AD_ERROR, (error) => {
199
235
  this.onAdError_(/** @type {!google.ima.AdErrorEvent} */ (error));
@@ -211,30 +247,22 @@ shaka.ads.ClientSideAdManager = class {
211
247
 
212
248
  this.eventManager_.listen(this.imaAdsManager_,
213
249
  google.ima.AdEvent.Type.FIRST_QUARTILE, (e) => {
214
- this.onEvent_(
215
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_FIRST_QUARTILE,
216
- {'originalEvent': e}));
250
+ convertEventAndSend(e, shaka.ads.AdManager.AD_FIRST_QUARTILE);
217
251
  });
218
252
 
219
253
  this.eventManager_.listen(this.imaAdsManager_,
220
254
  google.ima.AdEvent.Type.MIDPOINT, (e) => {
221
- this.onEvent_(
222
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_MIDPOINT,
223
- {'originalEvent': e}));
255
+ convertEventAndSend(e, shaka.ads.AdManager.AD_MIDPOINT);
224
256
  });
225
257
 
226
258
  this.eventManager_.listen(this.imaAdsManager_,
227
259
  google.ima.AdEvent.Type.THIRD_QUARTILE, (e) => {
228
- this.onEvent_(
229
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_THIRD_QUARTILE,
230
- {'originalEvent': e}));
260
+ convertEventAndSend(e, shaka.ads.AdManager.AD_THIRD_QUARTILE);
231
261
  });
232
262
 
233
263
  this.eventManager_.listen(this.imaAdsManager_,
234
264
  google.ima.AdEvent.Type.COMPLETE, (e) => {
235
- this.onEvent_(
236
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_COMPLETE,
237
- {'originalEvent': e}));
265
+ convertEventAndSend(e, shaka.ads.AdManager.AD_COMPLETE);
238
266
  });
239
267
 
240
268
  this.eventManager_.listen(this.imaAdsManager_,
@@ -249,140 +277,102 @@ shaka.ads.ClientSideAdManager = class {
249
277
 
250
278
  this.eventManager_.listen(this.imaAdsManager_,
251
279
  google.ima.AdEvent.Type.SKIPPED, (e) => {
252
- this.onEvent_(
253
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_SKIPPED,
254
- {'originalEvent': e}));
280
+ convertEventAndSend(e, shaka.ads.AdManager.AD_SKIPPED);
255
281
  });
256
282
 
257
283
  this.eventManager_.listen(this.imaAdsManager_,
258
284
  google.ima.AdEvent.Type.VOLUME_CHANGED, (e) => {
259
- this.onEvent_(
260
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_VOLUME_CHANGED,
261
- {'originalEvent': e}));
285
+ convertEventAndSend(e, shaka.ads.AdManager.AD_VOLUME_CHANGED);
262
286
  });
263
287
 
264
288
  this.eventManager_.listen(this.imaAdsManager_,
265
289
  google.ima.AdEvent.Type.VOLUME_MUTED, (e) => {
266
- this.onEvent_(
267
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_MUTED,
268
- {'originalEvent': e}));
290
+ convertEventAndSend(e, shaka.ads.AdManager.AD_MUTED);
269
291
  });
270
292
 
271
293
  this.eventManager_.listen(this.imaAdsManager_,
272
294
  google.ima.AdEvent.Type.PAUSED, (e) => {
273
295
  goog.asserts.assert(this.ad_ != null, 'Ad should not be null!');
274
296
  this.ad_.setPaused(true);
275
- this.onEvent_(
276
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_PAUSED,
277
- {'originalEvent': e}));
297
+ convertEventAndSend(e, shaka.ads.AdManager.AD_PAUSED);
278
298
  });
279
299
 
280
300
  this.eventManager_.listen(this.imaAdsManager_,
281
301
  google.ima.AdEvent.Type.RESUMED, (e) => {
282
302
  goog.asserts.assert(this.ad_ != null, 'Ad should not be null!');
283
303
  this.ad_.setPaused(false);
284
- this.onEvent_(
285
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_RESUMED,
286
- {'originalEvent': e}));
304
+ convertEventAndSend(e, shaka.ads.AdManager.AD_RESUMED);
287
305
  });
288
306
 
289
307
  this.eventManager_.listen(this.imaAdsManager_,
290
308
  google.ima.AdEvent.Type.SKIPPABLE_STATE_CHANGED, (e) => {
291
309
  goog.asserts.assert(this.ad_ != null, 'Ad should not be null!');
292
- this.onEvent_(new shaka.util.FakeEvent(
293
- shaka.ads.AdManager.AD_SKIP_STATE_CHANGED,
294
- {'originalEvent': e}));
310
+ convertEventAndSend(e, shaka.ads.AdManager.AD_SKIP_STATE_CHANGED);
295
311
  });
296
312
 
297
313
  this.eventManager_.listen(this.imaAdsManager_,
298
314
  google.ima.AdEvent.Type.CLICK, (e) => {
299
- this.onEvent_(new shaka.util.FakeEvent(
300
- shaka.ads.AdManager.AD_CLICKED,
301
- {'originalEvent': e}));
315
+ convertEventAndSend(e, shaka.ads.AdManager.AD_CLICKED);
302
316
  });
303
317
 
304
318
  this.eventManager_.listen(this.imaAdsManager_,
305
319
  google.ima.AdEvent.Type.AD_PROGRESS, (e) => {
306
- this.onEvent_(new shaka.util.FakeEvent(
307
- shaka.ads.AdManager.AD_PROGRESS,
308
- {'originalEvent': e}));
320
+ convertEventAndSend(e, shaka.ads.AdManager.AD_PROGRESS);
309
321
  });
310
322
 
311
323
  this.eventManager_.listen(this.imaAdsManager_,
312
324
  google.ima.AdEvent.Type.AD_BUFFERING, (e) => {
313
- this.onEvent_(new shaka.util.FakeEvent(
314
- shaka.ads.AdManager.AD_BUFFERING,
315
- {'originalEvent': e}));
325
+ convertEventAndSend(e, shaka.ads.AdManager.AD_BUFFERING);
316
326
  });
317
327
 
318
328
  this.eventManager_.listen(this.imaAdsManager_,
319
329
  google.ima.AdEvent.Type.IMPRESSION, (e) => {
320
- this.onEvent_(new shaka.util.FakeEvent(
321
- shaka.ads.AdManager.AD_IMPRESSION,
322
- {'originalEvent': e}));
330
+ convertEventAndSend(e, shaka.ads.AdManager.AD_IMPRESSION);
323
331
  });
324
332
 
325
333
  this.eventManager_.listen(this.imaAdsManager_,
326
334
  google.ima.AdEvent.Type.DURATION_CHANGE, (e) => {
327
- this.onEvent_(new shaka.util.FakeEvent(
328
- shaka.ads.AdManager.AD_DURATION_CHANGED,
329
- {'originalEvent': e}));
335
+ convertEventAndSend(e, shaka.ads.AdManager.AD_DURATION_CHANGED);
330
336
  });
331
337
 
332
338
  this.eventManager_.listen(this.imaAdsManager_,
333
339
  google.ima.AdEvent.Type.USER_CLOSE, (e) => {
334
- this.onEvent_(new shaka.util.FakeEvent(
335
- shaka.ads.AdManager.AD_CLOSED,
336
- {'originalEvent': e}));
340
+ convertEventAndSend(e, shaka.ads.AdManager.AD_CLOSED);
337
341
  });
338
342
 
339
343
  this.eventManager_.listen(this.imaAdsManager_,
340
344
  google.ima.AdEvent.Type.LOADED, (e) => {
341
- this.onEvent_(new shaka.util.FakeEvent(
342
- shaka.ads.AdManager.AD_LOADED,
343
- {'originalEvent': e}));
345
+ convertEventAndSend(e, shaka.ads.AdManager.AD_LOADED);
344
346
  });
345
347
 
346
348
  this.eventManager_.listen(this.imaAdsManager_,
347
349
  google.ima.AdEvent.Type.ALL_ADS_COMPLETED, (e) => {
348
- this.onEvent_(new shaka.util.FakeEvent(
349
- shaka.ads.AdManager.ALL_ADS_COMPLETED,
350
- {'originalEvent': e}));
350
+ convertEventAndSend(e, shaka.ads.AdManager.ALL_ADS_COMPLETED);
351
351
  });
352
352
 
353
353
  this.eventManager_.listen(this.imaAdsManager_,
354
354
  google.ima.AdEvent.Type.LINEAR_CHANGED, (e) => {
355
- this.onEvent_(new shaka.util.FakeEvent(
356
- shaka.ads.AdManager.AD_LINEAR_CHANGED,
357
- {'originalEvent': e}));
355
+ convertEventAndSend(e, shaka.ads.AdManager.AD_LINEAR_CHANGED);
358
356
  });
359
357
 
360
358
  this.eventManager_.listen(this.imaAdsManager_,
361
359
  google.ima.AdEvent.Type.AD_METADATA, (e) => {
362
- this.onEvent_(new shaka.util.FakeEvent(
363
- shaka.ads.AdManager.AD_METADATA,
364
- {'originalEvent': e}));
360
+ convertEventAndSend(e, shaka.ads.AdManager.AD_METADATA);
365
361
  });
366
362
 
367
363
  this.eventManager_.listen(this.imaAdsManager_,
368
364
  google.ima.AdEvent.Type.LOG, (e) => {
369
- this.onEvent_(new shaka.util.FakeEvent(
370
- shaka.ads.AdManager.AD_RECOVERABLE_ERROR,
371
- {'originalEvent': e}));
365
+ convertEventAndSend(e, shaka.ads.AdManager.AD_RECOVERABLE_ERROR);
372
366
  });
373
367
 
374
368
  this.eventManager_.listen(this.imaAdsManager_,
375
369
  google.ima.AdEvent.Type.AD_BREAK_READY, (e) => {
376
- this.onEvent_(new shaka.util.FakeEvent(
377
- shaka.ads.AdManager.AD_BREAK_READY,
378
- {'originalEvent': e}));
370
+ convertEventAndSend(e, shaka.ads.AdManager.AD_BREAK_READY);
379
371
  });
380
372
 
381
373
  this.eventManager_.listen(this.imaAdsManager_,
382
374
  google.ima.AdEvent.Type.INTERACTION, (e) => {
383
- this.onEvent_(new shaka.util.FakeEvent(
384
- shaka.ads.AdManager.AD_INTERACTION,
385
- {'originalEvent': e}));
375
+ convertEventAndSend(e, shaka.ads.AdManager.AD_INTERACTION);
386
376
  });
387
377
  }
388
378
 
@@ -396,12 +386,12 @@ shaka.ads.ClientSideAdManager = class {
396
386
 
397
387
  const imaAd = e.getAd();
398
388
  this.ad_ = new shaka.ads.ClientSideAd(imaAd, this.imaAdsManager_);
399
- this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.AD_STARTED,
400
- {
401
- 'ad': this.ad_,
402
- 'sdkAdObject': imaAd,
403
- 'originalEvent': e,
404
- }));
389
+ const data = new Map()
390
+ .set('ad', this.ad_)
391
+ .set('sdkAdObject', imaAd)
392
+ .set('originalEvent', e);
393
+ this.onEvent_(new shaka.util.FakeEvent(
394
+ shaka.ads.AdManager.AD_STARTED, data));
405
395
  this.adContainer_.setAttribute('ad-active', 'true');
406
396
  this.video_.pause();
407
397
  }
@@ -412,7 +402,7 @@ shaka.ads.ClientSideAdManager = class {
412
402
  */
413
403
  onAdComplete_(e) {
414
404
  this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.AD_STOPPED,
415
- {'originalEvent': e}));
405
+ (new Map()).set('originalEvent', e)));
416
406
  this.adContainer_.removeAttribute('ad-active');
417
407
  this.video_.play();
418
408
  }
@@ -14,10 +14,12 @@ goog.provide('shaka.ads.ServerSideAdManager');
14
14
  goog.require('goog.asserts');
15
15
  goog.require('shaka.ads.ServerSideAd');
16
16
  goog.require('shaka.log');
17
+ goog.require('shaka.util.IReleasable');
17
18
 
18
19
 
19
20
  /**
20
21
  * A class responsible for server-side ad interactions.
22
+ * @implements {shaka.util.IReleasable}
21
23
  */
22
24
  shaka.ads.ServerSideAdManager = class {
23
25
  /**
@@ -75,9 +77,7 @@ shaka.ads.ServerSideAdManager = class {
75
77
 
76
78
  this.onEvent_(new shaka.util.FakeEvent(
77
79
  shaka.ads.AdManager.IMA_STREAM_MANAGER_LOADED,
78
- {
79
- 'imaStreamManager': this.streamManager_,
80
- }));
80
+ (new Map()).set('imaStreamManager', this.streamManager_)));
81
81
 
82
82
  // Events
83
83
  this.eventManager_.listen(this.streamManager_,
@@ -201,11 +201,27 @@ shaka.ads.ServerSideAdManager = class {
201
201
  * Resets the stream manager and removes any continuous polling.
202
202
  */
203
203
  stop() {
204
- this.streamManager_.reset();
204
+ // TODO:
205
+ // For SS DAI streams, if a different asset gets unloaded as
206
+ // part of the process
207
+ // of loading a DAI asset, stream manager state gets reset and we
208
+ // don't get any ad events.
209
+ // We need to figure out if it makes sense to stop the SS
210
+ // manager on unload, and, if it does, find
211
+ // a way to do it safely.
212
+ // this.streamManager_.reset();
205
213
  this.backupUrl_ = '';
206
214
  this.snapForwardTime_ = null;
207
215
  }
208
216
 
217
+ /** @override */
218
+ release() {
219
+ this.stop();
220
+ if (this.eventManager_) {
221
+ this.eventManager_.release();
222
+ }
223
+ }
224
+
209
225
  /**
210
226
  * @param {string} type
211
227
  * @param {Uint8Array|string} data
@@ -280,7 +296,7 @@ shaka.ads.ServerSideAdManager = class {
280
296
  }
281
297
 
282
298
  this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.AD_STARTED,
283
- {'ad': this.ad_}));
299
+ (new Map()).set('ad', this.ad_)));
284
300
  this.adContainer_.setAttribute('ad-active', 'true');
285
301
  }
286
302
 
@@ -306,9 +322,8 @@ shaka.ads.ServerSideAdManager = class {
306
322
  onLoaded_(e) {
307
323
  const now = Date.now() / 1000;
308
324
  const loadTime = now - this.streamRequestStartTime_;
309
- this.onEvent_(
310
- new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
311
- {'loadTime': loadTime}));
325
+ this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
326
+ (new Map()).set('loadTime', loadTime)));
312
327
 
313
328
  const streamData = e.getStreamData();
314
329
  const url = streamData.url;
@@ -368,8 +383,8 @@ shaka.ads.ServerSideAdManager = class {
368
383
  cuePoints.push(shakaCuePoint);
369
384
  }
370
385
 
371
- this.onEvent_(
372
- new shaka.util.FakeEvent(shaka.ads.AdManager.CUEPOINTS_CHANGED,
373
- {'cuepoints': cuePoints}));
386
+ this.onEvent_(new shaka.util.FakeEvent(
387
+ shaka.ads.AdManager.CUEPOINTS_CHANGED,
388
+ (new Map()).set('cuepoints', cuePoints)));
374
389
  }
375
390
  };