shaka-player 4.1.3 → 4.2.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 (68) hide show
  1. package/.github/workflows/selenium-lab-tests.yaml +158 -53
  2. package/CHANGELOG.md +39 -29
  3. package/demo/common/assets.js +25 -0
  4. package/demo/common/message_ids.js +2 -0
  5. package/demo/config.js +5 -1
  6. package/demo/index.html +1 -1
  7. package/demo/locales/en.json +2 -0
  8. package/demo/locales/source.json +8 -0
  9. package/dist/controls.css +1 -1
  10. package/dist/controls.css.map +1 -1
  11. package/dist/demo.compiled.debug.js +25 -23
  12. package/dist/demo.compiled.debug.map +3 -3
  13. package/dist/demo.compiled.js +25 -23
  14. package/dist/demo.compiled.map +3 -3
  15. package/dist/deps.js +3 -2
  16. package/dist/locales.js +32 -32
  17. package/dist/receiver.compiled.debug.js +24 -22
  18. package/dist/receiver.compiled.debug.map +3 -3
  19. package/dist/receiver.compiled.js +24 -22
  20. package/dist/receiver.compiled.map +3 -3
  21. package/dist/shaka-player.compiled.d.ts +57 -6
  22. package/dist/shaka-player.compiled.debug.d.ts +57 -6
  23. package/dist/shaka-player.compiled.debug.externs.js +62 -6
  24. package/dist/shaka-player.compiled.debug.js +305 -262
  25. package/dist/shaka-player.compiled.debug.map +4 -4
  26. package/dist/shaka-player.compiled.externs.js +62 -6
  27. package/dist/shaka-player.compiled.js +817 -801
  28. package/dist/shaka-player.compiled.map +4 -4
  29. package/dist/shaka-player.ui.d.ts +57 -6
  30. package/dist/shaka-player.ui.debug.d.ts +57 -6
  31. package/dist/shaka-player.ui.debug.externs.js +62 -6
  32. package/dist/shaka-player.ui.debug.js +308 -265
  33. package/dist/shaka-player.ui.debug.map +4 -4
  34. package/dist/shaka-player.ui.externs.js +62 -6
  35. package/dist/shaka-player.ui.js +942 -925
  36. package/dist/shaka-player.ui.map +4 -4
  37. package/docs/tutorials/fairplay.md +149 -0
  38. package/docs/tutorials/ui.md +6 -6
  39. package/externs/shaka/abr_manager.js +8 -0
  40. package/externs/shaka/manifest.js +43 -0
  41. package/externs/shaka/player.js +13 -2
  42. package/lib/abr/simple_abr_manager.js +72 -4
  43. package/lib/hls/hls_parser.js +138 -96
  44. package/lib/media/drm_engine.js +0 -2
  45. package/lib/media/segment_index.js +8 -0
  46. package/lib/media/segment_reference.js +7 -1
  47. package/lib/media/streaming_engine.js +38 -2
  48. package/lib/net/networking_engine.js +1 -0
  49. package/lib/player.js +20 -1
  50. package/lib/polyfill/patchedmediakeys_apple.js +729 -0
  51. package/lib/text/ui_text_displayer.js +8 -0
  52. package/lib/text/vtt_text_parser.js +61 -4
  53. package/lib/util/error.js +23 -11
  54. package/lib/util/fairplay_utils.js +100 -2
  55. package/lib/util/platform.js +12 -1
  56. package/lib/util/player_configuration.js +4 -10
  57. package/package.json +1 -1
  58. package/shaka-player.uncompiled.js +1 -0
  59. package/test/hls/hls_parser_unit.js +101 -34
  60. package/test/media/drm_engine_unit.js +29 -0
  61. package/test/media/streaming_engine_unit.js +79 -5
  62. package/test/player_src_equals_integration.js +2 -0
  63. package/test/player_unit.js +39 -1
  64. package/test/test/assets/small.mp4 +0 -0
  65. package/test/test/util/simple_fakes.js +4 -0
  66. package/test/test/util/streaming_engine_util.js +10 -2
  67. package/test/text/vtt_text_parser_unit.js +26 -0
  68. package/ui/less/ad_controls.less +4 -0
@@ -1,8 +1,41 @@
1
1
  # FairPlay Support
2
2
 
3
3
  We support FairPlay with EME on compatible environments or native `src=`.
4
+
5
+ By default Shaka Player supports Modern EME, if your provider doesn't support
6
+ Modern EME yet, you can use legacy Apple Media Keys with:
7
+ ```js
8
+ shaka.polyfill.PatchedMediaKeysApple.install();
9
+ ```
10
+
11
+ The support in each case would be the following:
12
+
13
+ | |Modern EME |legacy Apple Media Keys|
14
+ |:----------:|:---------:|:---------------------:|
15
+ |src= (CMAF) |**Y** |**Y** |
16
+ |src= (TS) |**Y** |**Y** |
17
+ |MSE (CMAF) |**Y** | - |
18
+ |MSE (TS) | - | - |
19
+
20
+
4
21
  Adding FairPlay support involves a bit more work than other key systems.
5
22
 
23
+
24
+ ## Keysystem used in EME
25
+
26
+ Depending on the EME implementation that is being used, the Fairplay keysystem
27
+ varies.
28
+
29
+ For Modern EME:
30
+ ```
31
+ com.apple.fps
32
+ ```
33
+
34
+ For legacy Apple Media Keys:
35
+ ```
36
+ com.apple.fps.1_0
37
+ ```
38
+
6
39
  ## Server certificate
7
40
 
8
41
  All FairPlay content requires setting a server certificate. You can either
@@ -22,6 +55,27 @@ player.configure('drm.advanced.com\\.apple\\.fps\\.serverCertificateUri',
22
55
  'https://example.com/cert.der');
23
56
  ```
24
57
 
58
+ ## Content ID
59
+
60
+ Note: Normally only applies to legacy Apple Media Keys but some providers also
61
+ need it in Modern EME.
62
+
63
+ Some FairPlay content use custom signaling for the content ID. The content ID
64
+ is used by the browser to generate the license request. If you don't use the
65
+ default content ID derivation, you need to specify a custom init data transform:
66
+
67
+ ```js
68
+ player.configure('drm.initDataTransform', (initData, initDataType) => {
69
+ if (initDataType != 'skd')
70
+ return initData;
71
+ // 'initData' is a buffer containing an 'skd://' URL as a UTF-8 string.
72
+ const skdUri = shaka.util.StringUtils.fromBytesAutoDetect(initData);
73
+ const contentId = getMyContentId(skdUri);
74
+ const cert = player.drmInfo().serverCertificate;
75
+ return shaka.util.FairPlayUtils.initDataTransform(initData, contentId, cert);
76
+ });
77
+ ```
78
+
25
79
  ## License wrapping
26
80
 
27
81
  Some FairPlay servers need to accept the license request in a different format
@@ -61,3 +115,98 @@ player.getNetworkingEngine().registerResponseFilter((type, response) => {
61
115
  response.data = shaka.util.Uint8ArrayUtils.fromBase64(responseText).buffer;
62
116
  });
63
117
  ```
118
+
119
+ ### Integration with some DRMs providers
120
+
121
+ Note: Some providers support both Modern EME and legacy Apple Media Keys.
122
+
123
+ #### EZDRM (Modern EME)
124
+
125
+ For integration with EZDRM the following can be used:
126
+
127
+ ```js
128
+ const FairPlayUtils = shaka.util.FairPlayUtils;
129
+ player.getNetworkingEngine()
130
+ .registerRequestFilter(FairPlayUtils.ezdrmFairPlayRequest);
131
+ player.getNetworkingEngine()
132
+ .registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
133
+ ```
134
+
135
+ Note: If the url of the license server has to undergo any transformation
136
+ (eg: add the contentId), you would have to create your filter manually.
137
+
138
+ ```js
139
+ player.getNetworkingEngine().registerRequestFilter((type, request) => {
140
+ if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
141
+ return;
142
+ }
143
+ const uri = request.uris[0];
144
+ const FairPlayUtils = shaka.util.FairPlayUtils;
145
+ const contentId = FairPlayUtils.defaultGetContentId(request.initData);
146
+ const newUri = uri.replace('^assetId^', contentId);
147
+ request.uris = [newUri];
148
+ request.headers['Content-Type'] = 'application/octet-stream'
149
+ });
150
+ ```
151
+
152
+ #### EZDRM (legacy Apple Media Keys)
153
+
154
+ For integration with EZDRM the following can be used:
155
+
156
+ ```js
157
+ shaka.polyfill.PatchedMediaKeysApple.install();
158
+ const FairPlayUtils = shaka.util.FairPlayUtils;
159
+ player.getNetworkingEngine()
160
+ .registerRequestFilter(FairPlayUtils.ezdrmFairPlayRequest);
161
+ player.getNetworkingEngine()
162
+ .registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
163
+ player.configure('drm.initDataTransform',
164
+ FairPlayUtils.ezdrmInitDataTransform);
165
+ ```
166
+
167
+ Note: If the url of the license server has to undergo any transformation
168
+ (eg: add the contentId), you would have to create your filter manually.
169
+
170
+ ```js
171
+ player.getNetworkingEngine().registerRequestFilter((type, request) => {
172
+ if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
173
+ return;
174
+ }
175
+ const uri = request.uris[0];
176
+ const FairPlayUtils = shaka.util.FairPlayUtils;
177
+ const contentId = FairPlayUtils.defaultGetContentId(request.initData);
178
+ const newUri = uri.replace('^assetId^', contentId);
179
+ request.uris = [newUri];
180
+ request.headers['Content-Type'] = 'application/octet-stream'
181
+ });
182
+ ```
183
+
184
+ #### Verimatrix (legacy Apple Media Keys)
185
+
186
+ For integration with Verimatrix the following can be used:
187
+
188
+ ```js
189
+ shaka.polyfill.PatchedMediaKeysApple.install();
190
+ const FairPlayUtils = shaka.util.FairPlayUtils;
191
+ player.getNetworkingEngine()
192
+ .registerRequestFilter(FairPlayUtils.verimatrixFairPlayRequest);
193
+ player.getNetworkingEngine()
194
+ .registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
195
+ player.configure('drm.initDataTransform',
196
+ FairPlayUtils.verimatrixInitDataTransform);
197
+ ```
198
+
199
+ #### Conax (legacy Apple Media Keys)
200
+
201
+ For integration with Conax the following can be used:
202
+
203
+ ```js
204
+ shaka.polyfill.PatchedMediaKeysApple.install();
205
+ const FairPlayUtils = shaka.util.FairPlayUtils;
206
+ player.getNetworkingEngine()
207
+ .registerRequestFilter(FairPlayUtils.conaxFairPlayRequest);
208
+ player.getNetworkingEngine()
209
+ .registerResponseFilter(FairPlayUtils.commonFairPlayResponse);
210
+ player.configure('drm.initDataTransform',
211
+ FairPlayUtils.conaxInitDataTransform);
212
+ ```
@@ -30,7 +30,7 @@ Set up controls with HTML data attributes:
30
30
  The data-shaka-player-cast-receiver-id tag allows you to provide a Cast Application ID that
31
31
  the cast button will cast to; the value provided here is the sample cast receiver. -->
32
32
  <div data-shaka-player-container style="max-width:40em"
33
- data-shaka-player-cast-receiver-id="06EDA6EE">
33
+ data-shaka-player-cast-receiver-id="07AEE832">
34
34
  <!-- The data-shaka-player tag will make the UI library use this video element.
35
35
  If no video is provided, the UI will automatically make one inside the container div. -->
36
36
  <video autoplay data-shaka-player id="video" style="width:100%;height:100%"></video>
@@ -111,7 +111,7 @@ set up a listener for the 'caststatuschanged' events.
111
111
  <!-- Add a data-shaka-player-cast-receiver-id tag to provide a Cast Application ID that
112
112
  the cast button will cast to; the value provided here is the sample cast receiver. -->
113
113
  <div data-shaka-player-container style="max-width:40em"
114
- data-shaka-player-cast-receiver-id="06EDA6EE">
114
+ data-shaka-player-cast-receiver-id="07AEE832">
115
115
  </div>
116
116
  ```
117
117
 
@@ -154,7 +154,7 @@ or a `<source>` tag inside it to enable auto loading of the specified content.
154
154
 
155
155
  ```html
156
156
  <div data-shaka-player-container style="max-width:40em"
157
- data-shaka-player-cast-receiver-id="06EDA6EE">
157
+ data-shaka-player-cast-receiver-id="07AEE832">
158
158
  <!-- The manifest url in the src attribute will be automatically loaded -->
159
159
  <video autoplay data-shaka-player id="video" style="width:100%;height:100%"
160
160
  src="https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd"></video>
@@ -165,7 +165,7 @@ or
165
165
 
166
166
  ```html
167
167
  <div data-shaka-player-container style="max-width:40em"
168
- data-shaka-player-cast-receiver-id="06EDA6EE">
168
+ data-shaka-player-cast-receiver-id="07AEE832">
169
169
  <video autoplay data-shaka-player id="video" style="width:100%;height:100%">
170
170
  <!-- The manifest url in the src attribute will be auto loaded -->
171
171
  <source src="https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd"/>
@@ -178,7 +178,7 @@ call to the first one fails.
178
178
 
179
179
  ```html
180
180
  <div data-shaka-player-container style="max-width:40em"
181
- data-shaka-player-cast-receiver-id="06EDA6EE">
181
+ data-shaka-player-cast-receiver-id="07AEE832">
182
182
  <video autoplay data-shaka-player id="video" style="width:100%;height:100%">
183
183
  <!-- Try this first -->
184
184
  <source src="https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd"/>
@@ -222,7 +222,7 @@ const video = controls.getVideo();
222
222
  // Receiver Compatability.
223
223
  ui.configure({
224
224
  // Set the castReceiverAppId
225
- 'castReceiverAppId': '06EDA6EE',
225
+ 'castReceiverAppId': '07AEE832',
226
226
  // Enable casting to native Android Apps (e.g. Android TV Apps)
227
227
  'castAndroidReceiverCompatible': true,
228
228
  });
@@ -103,6 +103,14 @@ shaka.extern.AbrManager = class {
103
103
  */
104
104
  playbackRateChanged(rate) {}
105
105
 
106
+ /**
107
+ * Set media element.
108
+ *
109
+ * @param {HTMLMediaElement} mediaElement
110
+ * @exportDoc
111
+ */
112
+ setMediaElement(mediaElement) {}
113
+
106
114
  /**
107
115
  * Sets the ABR configuration.
108
116
  *
@@ -244,6 +244,49 @@ shaka.extern.Variant;
244
244
  shaka.extern.CreateSegmentIndexFunction;
245
245
 
246
246
 
247
+ /**
248
+ * @typedef {{
249
+ * method: string,
250
+ * cryptoKey: (webCrypto.CryptoKey|undefined),
251
+ * fetchKey: (shaka.extern.CreateSegmentIndexFunction|undefined),
252
+ * iv: (!Uint8Array|undefined),
253
+ * firstMediaSequenceNumber: number
254
+ * }}
255
+ *
256
+ * @description
257
+ * AES-128 key and iv info from the HLS manifest.
258
+ *
259
+ * @property {string} method
260
+ * The key method defined in the HLS manifest.
261
+ * @property {webCrypto.CryptoKey|undefined} cryptoKey
262
+ * Web crypto key object of the AES-128 CBC key. If unset, the "fetchKey"
263
+ * property should be provided.
264
+ * @property {shaka.extern.FetchCryptoKeysFunction|undefined} fetchKey
265
+ * A function that fetches the key.
266
+ * Should be provided if the "cryptoKey" property is unset.
267
+ * Should update this object in-place, to set "cryptoKey".
268
+ * @property {(!Uint8Array|undefined)} iv
269
+ * The IV in the HLS manifest, if defined. See HLS RFC 8216 Section 5.2 for
270
+ * handling undefined IV.
271
+ * @property {number} firstMediaSequenceNumber
272
+ * The starting Media Sequence Number of the playlist, used when IV is
273
+ * undefined.
274
+ *
275
+ * @exportDoc
276
+ */
277
+ shaka.extern.HlsAes128Key;
278
+
279
+
280
+ /**
281
+ * A function that fetches the crypto keys for AES-128.
282
+ * Returns a promise that resolves when the keys have been fetched.
283
+ *
284
+ * @typedef {function(): !Promise}
285
+ * @exportDoc
286
+ */
287
+ shaka.extern.FetchCryptoKeysFunction;
288
+
289
+
247
290
  /**
248
291
  * @typedef {{
249
292
  * id: number,
@@ -1000,7 +1000,9 @@ shaka.extern.StreamingConfiguration;
1000
1000
  * switchInterval: number,
1001
1001
  * bandwidthUpgradeTarget: number,
1002
1002
  * bandwidthDowngradeTarget: number,
1003
- * advanced: shaka.extern.AdvancedAbrConfiguration
1003
+ * advanced: shaka.extern.AdvancedAbrConfiguration,
1004
+ * restrictToElementSize: boolean,
1005
+ * ignoreDevicePixelRatio: boolean
1004
1006
  * }}
1005
1007
  *
1006
1008
  * @property {boolean} enabled
@@ -1029,7 +1031,16 @@ shaka.extern.StreamingConfiguration;
1029
1031
  * The largest fraction of the estimated bandwidth we should use. We should
1030
1032
  * downgrade to avoid this.
1031
1033
  * @property {shaka.extern.AdvancedAbrConfiguration} advanced
1032
- * Advanced ABR configuration.
1034
+ * Advanced ABR configuration
1035
+ * @property {boolean} restrictToElementSize
1036
+ * If true, restrict the quality to media element size.
1037
+ * Note: The use of ResizeObserver is required for it to work properly. If
1038
+ * true without ResizeObserver, it behaves as false.
1039
+ * Defaults false.
1040
+ * @property {boolean} ignoreDevicePixelRatio
1041
+ * If true,device pixel ratio is ignored when restricting the quality to
1042
+ * media element size.
1043
+ * Defaults false.
1033
1044
  * @exportDoc
1034
1045
  */
1035
1046
  shaka.extern.AbrConfiguration;
@@ -10,6 +10,7 @@ goog.require('goog.asserts');
10
10
  goog.require('shaka.abr.EwmaBandwidthEstimator');
11
11
  goog.require('shaka.log');
12
12
  goog.require('shaka.util.StreamUtils');
13
+ goog.require('shaka.util.Timer');
13
14
 
14
15
 
15
16
  /**
@@ -85,6 +86,22 @@ shaka.abr.SimpleAbrManager = class {
85
86
 
86
87
  /** @private {?shaka.extern.AbrConfiguration} */
87
88
  this.config_ = null;
89
+
90
+ /** @private {HTMLMediaElement} */
91
+ this.mediaElement_ = null;
92
+
93
+ /** @private {ResizeObserver} */
94
+ this.resizeObserver_ = null;
95
+
96
+ /** @private {shaka.util.Timer} */
97
+ this.resizeObserverTimer_ = new shaka.util.Timer(() => {
98
+ if (this.config_.restrictToElementSize) {
99
+ const chosenVariant = this.chooseVariant();
100
+ if (chosenVariant) {
101
+ this.switch_(chosenVariant);
102
+ }
103
+ }
104
+ });
88
105
  }
89
106
 
90
107
 
@@ -98,6 +115,14 @@ shaka.abr.SimpleAbrManager = class {
98
115
  this.variants_ = [];
99
116
  this.playbackRate_ = 1;
100
117
  this.lastTimeChosenMs_ = null;
118
+ this.mediaElement_ = null;
119
+
120
+ if (this.resizeObserver_) {
121
+ this.resizeObserver_.disconnect();
122
+ this.resizeObserver_ = null;
123
+ }
124
+
125
+ this.resizeObserverTimer_.stop();
101
126
 
102
127
  // Don't reset |startupComplete_|: if we've left the startup interval, we
103
128
  // can start using bandwidth estimates right away after init() is called.
@@ -120,9 +145,19 @@ shaka.abr.SimpleAbrManager = class {
120
145
  chooseVariant() {
121
146
  const SimpleAbrManager = shaka.abr.SimpleAbrManager;
122
147
 
148
+ let maxHeight = Infinity;
149
+ let maxWidth = Infinity;
150
+
151
+ if (this.resizeObserver_ && this.config_.restrictToElementSize) {
152
+ const devicePixelRatio =
153
+ this.config_.ignoreDevicePixelRatio ? 1 : window.devicePixelRatio;
154
+ maxHeight = this.mediaElement_.clientWidth * devicePixelRatio;
155
+ maxWidth = this.mediaElement_.clientHeight * devicePixelRatio;
156
+ }
157
+
123
158
  // Get sorted Variants.
124
159
  let sortedVariants = SimpleAbrManager.filterAndSortVariants_(
125
- this.config_.restrictions, this.variants_);
160
+ this.config_.restrictions, this.variants_, maxHeight, maxWidth);
126
161
 
127
162
  const defaultBandwidthEstimate = this.getDefaultBandwidth_();
128
163
  const currentBandwidth = this.bandwidthEstimator_.getBandwidthEstimate(
@@ -137,7 +172,8 @@ shaka.abr.SimpleAbrManager = class {
137
172
  shaka.log.warning('No variants met the ABR restrictions. ' +
138
173
  'Choosing a variant by lowest bandwidth.');
139
174
  sortedVariants = SimpleAbrManager.filterAndSortVariants_(
140
- /* restrictions= */ null, this.variants_);
175
+ /* restrictions= */ null, this.variants_,
176
+ /* maxHeight= */ Infinity, /* maxWidth= */ Infinity);
141
177
  sortedVariants = [sortedVariants[0]];
142
178
  }
143
179
 
@@ -243,6 +279,28 @@ shaka.abr.SimpleAbrManager = class {
243
279
  }
244
280
 
245
281
 
282
+ /**
283
+ * @override
284
+ * @export
285
+ */
286
+ setMediaElement(mediaElement) {
287
+ this.mediaElement_ = mediaElement;
288
+ if (this.resizeObserver_) {
289
+ this.resizeObserver_.disconnect();
290
+ this.resizeObserver_ = null;
291
+ }
292
+ if (this.mediaElement_ && 'ResizeObserver' in window) {
293
+ this.resizeObserver_ = new ResizeObserver(() => {
294
+ const SimpleAbrManager = shaka.abr.SimpleAbrManager;
295
+ // Batch up resize changes before checking them.
296
+ this.resizeObserverTimer_.tickAfter(
297
+ /* seconds= */ SimpleAbrManager.RESIZE_OBSERVER_BATCH_TIME);
298
+ });
299
+ this.resizeObserver_.observe(this.mediaElement_);
300
+ }
301
+ }
302
+
303
+
246
304
  /**
247
305
  * @override
248
306
  * @export
@@ -320,11 +378,13 @@ shaka.abr.SimpleAbrManager = class {
320
378
  /**
321
379
  * @param {?shaka.extern.Restrictions} restrictions
322
380
  * @param {!Array.<shaka.extern.Variant>} variants
381
+ * @param {!number} maxHeight
382
+ * @param {!number} maxWidth
323
383
  * @return {!Array.<shaka.extern.Variant>} variants filtered according to
324
384
  * |restrictions| and sorted in ascending order of bandwidth.
325
385
  * @private
326
386
  */
327
- static filterAndSortVariants_(restrictions, variants) {
387
+ static filterAndSortVariants_(restrictions, variants, maxHeight, maxWidth) {
328
388
  if (restrictions) {
329
389
  variants = variants.filter((variant) => {
330
390
  // This was already checked in another scope, but the compiler doesn't
@@ -333,7 +393,7 @@ shaka.abr.SimpleAbrManager = class {
333
393
 
334
394
  return shaka.util.StreamUtils.meetsRestrictions(
335
395
  variant, restrictions,
336
- /* maxHwRes= */ {width: Infinity, height: Infinity});
396
+ /* maxHwRes= */ {width: maxWidth, height: maxHeight});
337
397
  });
338
398
  }
339
399
 
@@ -342,3 +402,11 @@ shaka.abr.SimpleAbrManager = class {
342
402
  });
343
403
  }
344
404
  };
405
+
406
+
407
+ /**
408
+ * The amount of time, in seconds, we wait to batch up rapid resize changes.
409
+ * This allows us to avoid multiple resize events in most cases.
410
+ * @type {number}
411
+ */
412
+ shaka.abr.SimpleAbrManager.RESIZE_OBSERVER_BATCH_TIME = 1;