shaka-player 3.2.1 → 3.2.2

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 (96) hide show
  1. package/AUTHORS +3 -0
  2. package/CHANGELOG.md +57 -0
  3. package/CONTRIBUTORS +3 -0
  4. package/build/generateExterns.js +1 -1
  5. package/demo/common/assets.js +1 -1
  6. package/demo/index.html +1 -1
  7. package/dist/controls.css +2 -2
  8. package/dist/controls.css.map +1 -1
  9. package/dist/demo.compiled.debug.js +1 -1
  10. package/dist/demo.compiled.js +1 -1
  11. package/dist/deps.js +1 -1
  12. package/dist/locales.js +37 -37
  13. package/dist/receiver.compiled.debug.js +1 -1
  14. package/dist/receiver.compiled.js +1 -1
  15. package/dist/shaka-player.compiled.d.ts +1 -1
  16. package/dist/shaka-player.compiled.debug.d.ts +1 -1
  17. package/dist/shaka-player.compiled.debug.externs.js +1 -1
  18. package/dist/shaka-player.compiled.debug.js +188 -181
  19. package/dist/shaka-player.compiled.debug.map +3 -3
  20. package/dist/shaka-player.compiled.externs.js +1 -1
  21. package/dist/shaka-player.compiled.js +795 -790
  22. package/dist/shaka-player.compiled.map +3 -3
  23. package/dist/shaka-player.ui.d.ts +1 -1
  24. package/dist/shaka-player.ui.debug.d.ts +1 -1
  25. package/dist/shaka-player.ui.debug.externs.js +3 -3
  26. package/dist/shaka-player.ui.debug.js +217 -210
  27. package/dist/shaka-player.ui.debug.map +4 -4
  28. package/dist/shaka-player.ui.externs.js +3 -3
  29. package/dist/shaka-player.ui.js +945 -940
  30. package/dist/shaka-player.ui.map +4 -4
  31. package/docs/tutorials/fairplay.md +1 -1
  32. package/docs/tutorials/ui.md +5 -5
  33. package/karma.conf.js +1 -0
  34. package/lib/ads/client_side_ad_manager.js +46 -86
  35. package/lib/ads/server_side_ad_manager.js +7 -10
  36. package/lib/cast/cast_proxy.js +3 -2
  37. package/lib/cast/cast_receiver.js +2 -1
  38. package/lib/cast/cast_sender.js +2 -2
  39. package/lib/dash/dash_parser.js +93 -2
  40. package/lib/dash/segment_list.js +1 -1
  41. package/lib/dash/segment_template.js +1 -1
  42. package/lib/hls/hls_parser.js +30 -17
  43. package/lib/media/drm_engine.js +7 -0
  44. package/lib/media/gap_jumping_controller.js +4 -2
  45. package/lib/media/media_source_engine.js +1 -2
  46. package/lib/media/streaming_engine.js +2 -1
  47. package/lib/net/networking_engine.js +2 -1
  48. package/lib/player.js +26 -25
  49. package/lib/polyfill/media_capabilities.js +7 -1
  50. package/lib/polyfill/mediasource.js +6 -0
  51. package/lib/polyfill/orientation.js +1 -1
  52. package/lib/polyfill/patchedmediakeys_apple.js +4 -4
  53. package/lib/polyfill/patchedmediakeys_ms.js +4 -4
  54. package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
  55. package/lib/text/mp4_ttml_parser.js +3 -0
  56. package/lib/text/text_engine.js +14 -2
  57. package/lib/text/ttml_text_parser.js +5 -0
  58. package/lib/text/ui_text_displayer.js +85 -37
  59. package/lib/util/fake_event.js +53 -7
  60. package/lib/util/periods.js +4 -1
  61. package/lib/util/platform.js +13 -1
  62. package/lib/util/stream_utils.js +13 -0
  63. package/package.json +1 -1
  64. package/test/cast/cast_proxy_unit.js +12 -6
  65. package/test/cast/cast_utils_unit.js +1 -1
  66. package/test/dash/dash_parser_manifest_unit.js +187 -1
  67. package/test/hls/hls_parser_unit.js +5 -1
  68. package/test/media/closed_caption_parser_unit.js +6 -1
  69. package/test/media/drm_engine_unit.js +44 -0
  70. package/test/player_integration.js +38 -0
  71. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  72. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  73. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  74. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  75. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  76. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  77. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  78. package/test/test/assets/3675/dash_0.mpd +30 -0
  79. package/test/test/assets/3675/dash_1.mpd +30 -0
  80. package/test/test/assets/3675/dash_2.mpd +30 -0
  81. package/test/test/assets/3675/dash_3.mpd +30 -0
  82. package/test/test/assets/3675/dash_4.mpd +30 -0
  83. package/test/test/assets/3675/dash_5.mpd +26 -0
  84. package/test/test/assets/3675/init-stream0.m4s +0 -0
  85. package/test/test/util/fake_ad_manager.js +1 -1
  86. package/test/text/ttml_text_parser_unit.js +9 -0
  87. package/test/text/ui_text_displayer_unit.js +29 -17
  88. package/test/ui/localization_unit.js +15 -14
  89. package/test/ui/text_displayer_layout_unit.js +13 -1
  90. package/test/util/stream_utils_unit.js +35 -0
  91. package/ui/cast_button.js +2 -3
  92. package/ui/controls.js +4 -6
  93. package/ui/less/containers.less +3 -7
  94. package/ui/locales/ru.json +6 -6
  95. package/ui/localization.js +28 -51
  96. package/ui/pip_button.js +2 -3
@@ -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
  });
@@ -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="1BA79154">
33
+ data-shaka-player-cast-receiver-id="E7271BEC">
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="1BA79154">
114
+ data-shaka-player-cast-receiver-id="E7271BEC">
115
115
  </div>
116
116
  ```
117
117
 
@@ -137,7 +137,7 @@ or a `<source>` tag inside it to enable auto loading of the specified content.
137
137
 
138
138
  ```html
139
139
  <div data-shaka-player-container style="max-width:40em"
140
- data-shaka-player-cast-receiver-id="1BA79154">
140
+ data-shaka-player-cast-receiver-id="E7271BEC">
141
141
  <!-- The manifest url in the src attribute will be automatically loaded -->
142
142
  <video autoplay data-shaka-player id="video" style="width:100%;height:100%"
143
143
  src="https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd"></video>
@@ -148,7 +148,7 @@ or
148
148
 
149
149
  ```html
150
150
  <div data-shaka-player-container style="max-width:40em"
151
- data-shaka-player-cast-receiver-id="1BA79154">
151
+ data-shaka-player-cast-receiver-id="E7271BEC">
152
152
  <video autoplay data-shaka-player id="video" style="width:100%;height:100%">
153
153
  <!-- The manifest url in the src attribute will be auto loaded -->
154
154
  <source src="https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd"/>
@@ -161,7 +161,7 @@ call to the first one fails.
161
161
 
162
162
  ```html
163
163
  <div data-shaka-player-container style="max-width:40em"
164
- data-shaka-player-cast-receiver-id="1BA79154">
164
+ data-shaka-player-cast-receiver-id="E7271BEC">
165
165
  <video autoplay data-shaka-player id="video" style="width:100%;height:100%">
166
166
  <!-- Try this first -->
167
167
  <source src="https://storage.googleapis.com/shaka-demo-assets/angel-one/dash.mpd"/>
package/karma.conf.js CHANGED
@@ -140,6 +140,7 @@ module.exports = (config) => {
140
140
  included: false,
141
141
  },
142
142
  {pattern: 'test/test/assets/*', included: false},
143
+ {pattern: 'test/test/assets/3675/*', included: false},
143
144
  {pattern: 'dist/shaka-player.ui.js', included: false},
144
145
  {pattern: 'dist/locales.js', included: false},
145
146
  {pattern: 'demo/locales/en.json', included: false},
@@ -138,7 +138,7 @@ shaka.ads.ClientSideAdManager = class {
138
138
  // Remove ad breaks from the timeline
139
139
  this.onEvent_(
140
140
  new shaka.util.FakeEvent(shaka.ads.AdManager.CUEPOINTS_CHANGED,
141
- {'cuepoints': []}));
141
+ (new Map()).set('cuepoints', [])));
142
142
  }
143
143
 
144
144
 
@@ -151,17 +151,14 @@ shaka.ads.ClientSideAdManager = class {
151
151
 
152
152
  const now = Date.now() / 1000;
153
153
  const loadTime = now - this.requestAdsStartTime_;
154
- this.onEvent_(
155
- new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
156
- {'loadTime': loadTime}));
154
+ this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
155
+ (new Map()).set('loadTime', loadTime)));
157
156
 
158
157
  this.imaAdsManager_ = e.getAdsManager(this.video_);
159
158
 
160
159
  this.onEvent_(new shaka.util.FakeEvent(
161
160
  shaka.ads.AdManager.IMA_AD_MANAGER_LOADED,
162
- {
163
- 'imaAdManager': this.imaAdsManager_,
164
- }));
161
+ (new Map()).set('imaAdManager', this.imaAdsManager_)));
165
162
 
166
163
  const cuePointStarts = this.imaAdsManager_.getCuePoints();
167
164
  if (cuePointStarts.length) {
@@ -176,9 +173,9 @@ shaka.ads.ClientSideAdManager = class {
176
173
  cuePoints.push(shakaCuePoint);
177
174
  }
178
175
 
179
- this.onEvent_(
180
- new shaka.util.FakeEvent(shaka.ads.AdManager.CUEPOINTS_CHANGED,
181
- {'cuepoints': cuePoints}));
176
+ this.onEvent_(new shaka.util.FakeEvent(
177
+ shaka.ads.AdManager.CUEPOINTS_CHANGED,
178
+ (new Map()).set('cuepoints', cuePoints)));
182
179
  }
183
180
 
184
181
  this.addImaEventListeners_();
@@ -228,6 +225,15 @@ shaka.ads.ClientSideAdManager = class {
228
225
  * @private
229
226
  */
230
227
  addImaEventListeners_() {
228
+ /**
229
+ * @param {!Event} e
230
+ * @param {string} type
231
+ */
232
+ const convertEventAndSend = (e, type) => {
233
+ const data = (new Map()).set('originalEvent', e);
234
+ this.onEvent_(new shaka.util.FakeEvent(type, data));
235
+ };
236
+
231
237
  this.eventManager_.listen(this.imaAdsManager_,
232
238
  google.ima.AdErrorEvent.Type.AD_ERROR, (error) => {
233
239
  this.onAdError_(/** @type {!google.ima.AdErrorEvent} */ (error));
@@ -245,30 +251,22 @@ shaka.ads.ClientSideAdManager = class {
245
251
 
246
252
  this.eventManager_.listen(this.imaAdsManager_,
247
253
  google.ima.AdEvent.Type.FIRST_QUARTILE, (e) => {
248
- this.onEvent_(
249
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_FIRST_QUARTILE,
250
- {'originalEvent': e}));
254
+ convertEventAndSend(e, shaka.ads.AdManager.AD_FIRST_QUARTILE);
251
255
  });
252
256
 
253
257
  this.eventManager_.listen(this.imaAdsManager_,
254
258
  google.ima.AdEvent.Type.MIDPOINT, (e) => {
255
- this.onEvent_(
256
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_MIDPOINT,
257
- {'originalEvent': e}));
259
+ convertEventAndSend(e, shaka.ads.AdManager.AD_MIDPOINT);
258
260
  });
259
261
 
260
262
  this.eventManager_.listen(this.imaAdsManager_,
261
263
  google.ima.AdEvent.Type.THIRD_QUARTILE, (e) => {
262
- this.onEvent_(
263
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_THIRD_QUARTILE,
264
- {'originalEvent': e}));
264
+ convertEventAndSend(e, shaka.ads.AdManager.AD_THIRD_QUARTILE);
265
265
  });
266
266
 
267
267
  this.eventManager_.listen(this.imaAdsManager_,
268
268
  google.ima.AdEvent.Type.COMPLETE, (e) => {
269
- this.onEvent_(
270
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_COMPLETE,
271
- {'originalEvent': e}));
269
+ convertEventAndSend(e, shaka.ads.AdManager.AD_COMPLETE);
272
270
  });
273
271
 
274
272
  this.eventManager_.listen(this.imaAdsManager_,
@@ -283,140 +281,102 @@ shaka.ads.ClientSideAdManager = class {
283
281
 
284
282
  this.eventManager_.listen(this.imaAdsManager_,
285
283
  google.ima.AdEvent.Type.SKIPPED, (e) => {
286
- this.onEvent_(
287
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_SKIPPED,
288
- {'originalEvent': e}));
284
+ convertEventAndSend(e, shaka.ads.AdManager.AD_SKIPPED);
289
285
  });
290
286
 
291
287
  this.eventManager_.listen(this.imaAdsManager_,
292
288
  google.ima.AdEvent.Type.VOLUME_CHANGED, (e) => {
293
- this.onEvent_(
294
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_VOLUME_CHANGED,
295
- {'originalEvent': e}));
289
+ convertEventAndSend(e, shaka.ads.AdManager.AD_VOLUME_CHANGED);
296
290
  });
297
291
 
298
292
  this.eventManager_.listen(this.imaAdsManager_,
299
293
  google.ima.AdEvent.Type.VOLUME_MUTED, (e) => {
300
- this.onEvent_(
301
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_MUTED,
302
- {'originalEvent': e}));
294
+ convertEventAndSend(e, shaka.ads.AdManager.AD_MUTED);
303
295
  });
304
296
 
305
297
  this.eventManager_.listen(this.imaAdsManager_,
306
298
  google.ima.AdEvent.Type.PAUSED, (e) => {
307
299
  goog.asserts.assert(this.ad_ != null, 'Ad should not be null!');
308
300
  this.ad_.setPaused(true);
309
- this.onEvent_(
310
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_PAUSED,
311
- {'originalEvent': e}));
301
+ convertEventAndSend(e, shaka.ads.AdManager.AD_PAUSED);
312
302
  });
313
303
 
314
304
  this.eventManager_.listen(this.imaAdsManager_,
315
305
  google.ima.AdEvent.Type.RESUMED, (e) => {
316
306
  goog.asserts.assert(this.ad_ != null, 'Ad should not be null!');
317
307
  this.ad_.setPaused(false);
318
- this.onEvent_(
319
- new shaka.util.FakeEvent(shaka.ads.AdManager.AD_RESUMED,
320
- {'originalEvent': e}));
308
+ convertEventAndSend(e, shaka.ads.AdManager.AD_RESUMED);
321
309
  });
322
310
 
323
311
  this.eventManager_.listen(this.imaAdsManager_,
324
312
  google.ima.AdEvent.Type.SKIPPABLE_STATE_CHANGED, (e) => {
325
313
  goog.asserts.assert(this.ad_ != null, 'Ad should not be null!');
326
- this.onEvent_(new shaka.util.FakeEvent(
327
- shaka.ads.AdManager.AD_SKIP_STATE_CHANGED,
328
- {'originalEvent': e}));
314
+ convertEventAndSend(e, shaka.ads.AdManager.AD_SKIP_STATE_CHANGED);
329
315
  });
330
316
 
331
317
  this.eventManager_.listen(this.imaAdsManager_,
332
318
  google.ima.AdEvent.Type.CLICK, (e) => {
333
- this.onEvent_(new shaka.util.FakeEvent(
334
- shaka.ads.AdManager.AD_CLICKED,
335
- {'originalEvent': e}));
319
+ convertEventAndSend(e, shaka.ads.AdManager.AD_CLICKED);
336
320
  });
337
321
 
338
322
  this.eventManager_.listen(this.imaAdsManager_,
339
323
  google.ima.AdEvent.Type.AD_PROGRESS, (e) => {
340
- this.onEvent_(new shaka.util.FakeEvent(
341
- shaka.ads.AdManager.AD_PROGRESS,
342
- {'originalEvent': e}));
324
+ convertEventAndSend(e, shaka.ads.AdManager.AD_PROGRESS);
343
325
  });
344
326
 
345
327
  this.eventManager_.listen(this.imaAdsManager_,
346
328
  google.ima.AdEvent.Type.AD_BUFFERING, (e) => {
347
- this.onEvent_(new shaka.util.FakeEvent(
348
- shaka.ads.AdManager.AD_BUFFERING,
349
- {'originalEvent': e}));
329
+ convertEventAndSend(e, shaka.ads.AdManager.AD_BUFFERING);
350
330
  });
351
331
 
352
332
  this.eventManager_.listen(this.imaAdsManager_,
353
333
  google.ima.AdEvent.Type.IMPRESSION, (e) => {
354
- this.onEvent_(new shaka.util.FakeEvent(
355
- shaka.ads.AdManager.AD_IMPRESSION,
356
- {'originalEvent': e}));
334
+ convertEventAndSend(e, shaka.ads.AdManager.AD_IMPRESSION);
357
335
  });
358
336
 
359
337
  this.eventManager_.listen(this.imaAdsManager_,
360
338
  google.ima.AdEvent.Type.DURATION_CHANGE, (e) => {
361
- this.onEvent_(new shaka.util.FakeEvent(
362
- shaka.ads.AdManager.AD_DURATION_CHANGED,
363
- {'originalEvent': e}));
339
+ convertEventAndSend(e, shaka.ads.AdManager.AD_DURATION_CHANGED);
364
340
  });
365
341
 
366
342
  this.eventManager_.listen(this.imaAdsManager_,
367
343
  google.ima.AdEvent.Type.USER_CLOSE, (e) => {
368
- this.onEvent_(new shaka.util.FakeEvent(
369
- shaka.ads.AdManager.AD_CLOSED,
370
- {'originalEvent': e}));
344
+ convertEventAndSend(e, shaka.ads.AdManager.AD_CLOSED);
371
345
  });
372
346
 
373
347
  this.eventManager_.listen(this.imaAdsManager_,
374
348
  google.ima.AdEvent.Type.LOADED, (e) => {
375
- this.onEvent_(new shaka.util.FakeEvent(
376
- shaka.ads.AdManager.AD_LOADED,
377
- {'originalEvent': e}));
349
+ convertEventAndSend(e, shaka.ads.AdManager.AD_LOADED);
378
350
  });
379
351
 
380
352
  this.eventManager_.listen(this.imaAdsManager_,
381
353
  google.ima.AdEvent.Type.ALL_ADS_COMPLETED, (e) => {
382
- this.onEvent_(new shaka.util.FakeEvent(
383
- shaka.ads.AdManager.ALL_ADS_COMPLETED,
384
- {'originalEvent': e}));
354
+ convertEventAndSend(e, shaka.ads.AdManager.ALL_ADS_COMPLETED);
385
355
  });
386
356
 
387
357
  this.eventManager_.listen(this.imaAdsManager_,
388
358
  google.ima.AdEvent.Type.LINEAR_CHANGED, (e) => {
389
- this.onEvent_(new shaka.util.FakeEvent(
390
- shaka.ads.AdManager.AD_LINEAR_CHANGED,
391
- {'originalEvent': e}));
359
+ convertEventAndSend(e, shaka.ads.AdManager.AD_LINEAR_CHANGED);
392
360
  });
393
361
 
394
362
  this.eventManager_.listen(this.imaAdsManager_,
395
363
  google.ima.AdEvent.Type.AD_METADATA, (e) => {
396
- this.onEvent_(new shaka.util.FakeEvent(
397
- shaka.ads.AdManager.AD_METADATA,
398
- {'originalEvent': e}));
364
+ convertEventAndSend(e, shaka.ads.AdManager.AD_METADATA);
399
365
  });
400
366
 
401
367
  this.eventManager_.listen(this.imaAdsManager_,
402
368
  google.ima.AdEvent.Type.LOG, (e) => {
403
- this.onEvent_(new shaka.util.FakeEvent(
404
- shaka.ads.AdManager.AD_RECOVERABLE_ERROR,
405
- {'originalEvent': e}));
369
+ convertEventAndSend(e, shaka.ads.AdManager.AD_RECOVERABLE_ERROR);
406
370
  });
407
371
 
408
372
  this.eventManager_.listen(this.imaAdsManager_,
409
373
  google.ima.AdEvent.Type.AD_BREAK_READY, (e) => {
410
- this.onEvent_(new shaka.util.FakeEvent(
411
- shaka.ads.AdManager.AD_BREAK_READY,
412
- {'originalEvent': e}));
374
+ convertEventAndSend(e, shaka.ads.AdManager.AD_BREAK_READY);
413
375
  });
414
376
 
415
377
  this.eventManager_.listen(this.imaAdsManager_,
416
378
  google.ima.AdEvent.Type.INTERACTION, (e) => {
417
- this.onEvent_(new shaka.util.FakeEvent(
418
- shaka.ads.AdManager.AD_INTERACTION,
419
- {'originalEvent': e}));
379
+ convertEventAndSend(e, shaka.ads.AdManager.AD_INTERACTION);
420
380
  });
421
381
  }
422
382
 
@@ -430,12 +390,12 @@ shaka.ads.ClientSideAdManager = class {
430
390
 
431
391
  const imaAd = e.getAd();
432
392
  this.ad_ = new shaka.ads.ClientSideAd(imaAd, this.imaAdsManager_);
433
- this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.AD_STARTED,
434
- {
435
- 'ad': this.ad_,
436
- 'sdkAdObject': imaAd,
437
- 'originalEvent': e,
438
- }));
393
+ const data = new Map()
394
+ .set('ad', this.ad_)
395
+ .set('sdkAdObject', imaAd)
396
+ .set('originalEvent', e);
397
+ this.onEvent_(new shaka.util.FakeEvent(
398
+ shaka.ads.AdManager.AD_STARTED, data));
439
399
  this.adContainer_.setAttribute('ad-active', 'true');
440
400
  this.video_.pause();
441
401
  }
@@ -446,7 +406,7 @@ shaka.ads.ClientSideAdManager = class {
446
406
  */
447
407
  onAdComplete_(e) {
448
408
  this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.AD_STOPPED,
449
- {'originalEvent': e}));
409
+ (new Map()).set('originalEvent', e)));
450
410
  this.adContainer_.removeAttribute('ad-active');
451
411
  this.video_.play();
452
412
  }
@@ -80,9 +80,7 @@ shaka.ads.ServerSideAdManager = class {
80
80
 
81
81
  this.onEvent_(new shaka.util.FakeEvent(
82
82
  shaka.ads.AdManager.IMA_STREAM_MANAGER_LOADED,
83
- {
84
- 'imaStreamManager': this.streamManager_,
85
- }));
83
+ (new Map()).set('imaStreamManager', this.streamManager_)));
86
84
 
87
85
  // Events
88
86
  this.eventManager_.listen(this.streamManager_,
@@ -309,7 +307,7 @@ shaka.ads.ServerSideAdManager = class {
309
307
  }
310
308
 
311
309
  this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.AD_STARTED,
312
- {'ad': this.ad_}));
310
+ (new Map()).set('ad', this.ad_)));
313
311
  this.adContainer_.setAttribute('ad-active', 'true');
314
312
  }
315
313
 
@@ -335,9 +333,8 @@ shaka.ads.ServerSideAdManager = class {
335
333
  onLoaded_(e) {
336
334
  const now = Date.now() / 1000;
337
335
  const loadTime = now - this.streamRequestStartTime_;
338
- this.onEvent_(
339
- new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
340
- {'loadTime': loadTime}));
336
+ this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.ADS_LOADED,
337
+ (new Map()).set('loadTime', loadTime)));
341
338
 
342
339
  const streamData = e.getStreamData();
343
340
  const url = streamData.url;
@@ -403,8 +400,8 @@ shaka.ads.ServerSideAdManager = class {
403
400
 
404
401
  this.currentCuePoints_ = cuePoints;
405
402
 
406
- this.onEvent_(
407
- new shaka.util.FakeEvent(shaka.ads.AdManager.CUEPOINTS_CHANGED,
408
- {'cuepoints': cuePoints}));
403
+ this.onEvent_(new shaka.util.FakeEvent(
404
+ shaka.ads.AdManager.CUEPOINTS_CHANGED,
405
+ (new Map()).set('cuepoints', cuePoints)));
409
406
  }
410
407
  };
@@ -525,7 +525,8 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
525
525
  goog.asserts.assert(error instanceof shaka.util.Error,
526
526
  'Wrong error type!');
527
527
  const eventType = shaka.Player.EventName.Error;
528
- const event = new shaka.util.FakeEvent(eventType, {'detail': error});
528
+ const data = (new Map()).set('detail', error);
529
+ const event = new shaka.util.FakeEvent(eventType, data);
529
530
  this.localPlayer_.dispatchEvent(event);
530
531
  });
531
532
  }
@@ -598,7 +599,7 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
598
599
 
599
600
  // Convert this real Event into a FakeEvent for dispatch from our
600
601
  // FakeEventListener.
601
- const fakeEvent = new shaka.util.FakeEvent(event.type, event);
602
+ const fakeEvent = shaka.util.FakeEvent.fromRealEvent(event);
602
603
  this.videoEventTarget_.dispatchEvent(fakeEvent);
603
604
  }
604
605
 
@@ -407,7 +407,8 @@ shaka.cast.CastReceiver = class extends shaka.util.FakeEventTarget {
407
407
  goog.asserts.assert(error instanceof shaka.util.Error,
408
408
  'Wrong error type!');
409
409
  const eventType = shaka.Player.EventName.Error;
410
- const event = new shaka.util.FakeEvent(eventType, {'detail': error});
410
+ const data = (new Map()).set('detail', error);
411
+ const event = new shaka.util.FakeEvent(eventType, data);
411
412
  // Only dispatch the event if the player still exists.
412
413
  if (this.player_) {
413
414
  this.player_.dispatchEvent(event);
@@ -647,7 +647,7 @@ shaka.cast.CastSender = class {
647
647
  case 'event': {
648
648
  const targetName = message['targetName'];
649
649
  const event = message['event'];
650
- const fakeEvent = new shaka.util.FakeEvent(event['type'], event);
650
+ const fakeEvent = shaka.util.FakeEvent.fromRealEvent(event);
651
651
  this.onRemoteEvent_(targetName, fakeEvent);
652
652
  break;
653
653
  }
@@ -725,7 +725,7 @@ shaka.cast.CastSender = class {
725
725
 
726
726
  // Dispatch it through the Player proxy
727
727
  const fakeEvent = new shaka.util.FakeEvent(
728
- 'error', {'detail': shakaError});
728
+ 'error', (new Map()).set('detail', shakaError));
729
729
  this.onRemoteEvent_('player', fakeEvent);
730
730
 
731
731
  // Force this session to disconnect and transfer playback to the local
@@ -95,6 +95,18 @@ shaka.dash.DashParser = class {
95
95
  /** @private {!shaka.util.OperationManager} */
96
96
  this.operationManager_ = new shaka.util.OperationManager();
97
97
 
98
+ /**
99
+ * Largest period start time seen.
100
+ * @private {?number}
101
+ */
102
+ this.largestPeriodStartTime_ = null;
103
+
104
+ /**
105
+ * Period IDs seen in previous manifest.
106
+ * @private {!Array.<number>}
107
+ */
108
+ this.lastManifestUpdatePeriodIds_ = [];
109
+
98
110
  /**
99
111
  * The minimum of the availabilityTimeOffset values among the adaptation
100
112
  * sets.
@@ -538,6 +550,7 @@ shaka.dash.DashParser = class {
538
550
  for (const {i, item: elem, next} of enumerate(periodNodes)) {
539
551
  const start = /** @type {number} */ (
540
552
  XmlUtils.parseAttr(elem, 'start', XmlUtils.parseDuration, prevEnd));
553
+ const periodId = elem.id;
541
554
  const givenDuration =
542
555
  XmlUtils.parseAttr(elem, 'duration', XmlUtils.parseDuration);
543
556
 
@@ -571,6 +584,42 @@ shaka.dash.DashParser = class {
571
584
  periodDuration = givenDuration;
572
585
  }
573
586
 
587
+ /**
588
+ * This is to improve robustness when the player observes manifest with
589
+ * past periods that are inconsistent to previous ones.
590
+ *
591
+ * This may happen when a CDN or proxy server switches its upstream from
592
+ * one encoder to another redundant encoder.
593
+ *
594
+ * Skip periods that match all of the following criteria:
595
+ * - Start time is earlier than latest period start time ever seen
596
+ * - Period ID is never seen in the previous manifest
597
+ * - Not the last period in the manifest
598
+ *
599
+ * Periods that meet the aforementioned criteria are considered invalid
600
+ * and should be safe to discard.
601
+ */
602
+
603
+ if (this.largestPeriodStartTime_ !== null &&
604
+ periodId !== null && start !== null &&
605
+ start < this.largestPeriodStartTime_ &&
606
+ !this.lastManifestUpdatePeriodIds_.includes(periodId) &&
607
+ i + 1 != periodNodes.length) {
608
+ shaka.log.debug(
609
+ `Skipping Period with ID ${periodId} as its start time is smaller` +
610
+ ' than the largest period start time that has been seen, and ID ' +
611
+ 'is unseen before');
612
+ continue;
613
+ }
614
+
615
+
616
+ // Save maximum period start time if it is the last period
617
+ if (start !== null &&
618
+ (this.largestPeriodStartTime_ === null ||
619
+ start > this.largestPeriodStartTime_)) {
620
+ this.largestPeriodStartTime_ = start;
621
+ }
622
+
574
623
  // Parse child nodes.
575
624
  const info = {
576
625
  start: start,
@@ -602,6 +651,9 @@ shaka.dash.DashParser = class {
602
651
  prevEnd = start + periodDuration;
603
652
  } // end of period parsing loop
604
653
 
654
+ // Replace previous seen periods with the current one.
655
+ this.lastManifestUpdatePeriodIds_ = periods.map((el) => el.id);
656
+
605
657
  if (presentationDuration != null) {
606
658
  if (prevEnd != presentationDuration) {
607
659
  shaka.log.warning(
@@ -813,6 +865,25 @@ shaka.dash.DashParser = class {
813
865
  }
814
866
  }
815
867
 
868
+ // Parallel for HLS VIDEO-RANGE as defined in DASH-IF IOP v4.3 6.2.5.1.
869
+ let videoRange;
870
+ const videoRangeScheme = 'urn:mpeg:mpegB:cicp:TransferCharacteristics';
871
+ const getVideoRangeFromTransferCharacteristicCICP = (cicp) => {
872
+ switch (cicp) {
873
+ case 1:
874
+ case 6:
875
+ case 13:
876
+ case 14:
877
+ case 15:
878
+ return 'SDR';
879
+ case 16:
880
+ return 'PQ';
881
+ case 18:
882
+ return 'HLG';
883
+ }
884
+ return undefined;
885
+ };
886
+
816
887
  const essentialProperties =
817
888
  XmlUtils.findChildren(elem, 'EssentialProperty');
818
889
  // ID of real AdaptationSet if this is a trick mode set:
@@ -822,11 +893,26 @@ shaka.dash.DashParser = class {
822
893
  const schemeId = prop.getAttribute('schemeIdUri');
823
894
  if (schemeId == 'http://dashif.org/guidelines/trickmode') {
824
895
  trickModeFor = prop.getAttribute('value');
896
+ } else if (schemeId == videoRangeScheme) {
897
+ videoRange = getVideoRangeFromTransferCharacteristicCICP(
898
+ parseInt(prop.getAttribute('value'), 10),
899
+ );
825
900
  } else {
826
901
  unrecognizedEssentialProperty = true;
827
902
  }
828
903
  }
829
904
 
905
+ const supplementalProperties =
906
+ XmlUtils.findChildren(elem, 'SupplementalProperty');
907
+ for (const prop of supplementalProperties) {
908
+ const schemeId = prop.getAttribute('schemeIdUri');
909
+ if (schemeId == videoRangeScheme) {
910
+ videoRange = getVideoRangeFromTransferCharacteristicCICP(
911
+ parseInt(prop.getAttribute('value'), 10),
912
+ );
913
+ }
914
+ }
915
+
830
916
  const accessibilities = XmlUtils.findChildren(elem, 'Accessibility');
831
917
  const LanguageUtils = shaka.util.LanguageUtils;
832
918
  const closedCaptions = new Map();
@@ -952,8 +1038,13 @@ shaka.dash.DashParser = class {
952
1038
  // Parse Representations into Streams.
953
1039
  const representations = XmlUtils.findChildren(elem, 'Representation');
954
1040
  const streams = representations.map((representation) => {
955
- return this.parseRepresentation_(context, contentProtection, kind,
956
- language, label, main, roleValues, closedCaptions, representation);
1041
+ const parsedRepresentation = this.parseRepresentation_(context,
1042
+ contentProtection, kind, language, label, main, roleValues,
1043
+ closedCaptions, representation);
1044
+ if (parsedRepresentation) {
1045
+ parsedRepresentation.hdr = parsedRepresentation.hdr || videoRange;
1046
+ }
1047
+ return parsedRepresentation;
957
1048
  }).filter((s) => !!s);
958
1049
 
959
1050
  if (streams.length == 0) {
@@ -63,12 +63,12 @@ shaka.dash.SegmentList = class {
63
63
  const start = context.presentationTimeline.getSegmentAvailabilityStart();
64
64
  segmentIndex.mergeAndEvict(references, start);
65
65
  } else {
66
- context.presentationTimeline.notifySegments(references);
67
66
  segmentIndex = new shaka.media.SegmentIndex(references);
68
67
  if (id && context.dynamic) {
69
68
  segmentIndexMap[id] = segmentIndex;
70
69
  }
71
70
  }
71
+ context.presentationTimeline.notifySegments(references);
72
72
 
73
73
  if (!context.dynamic || !context.periodInfo.isLastPeriod) {
74
74
  const periodStart = context.periodInfo.start;
@@ -116,12 +116,12 @@ shaka.dash.SegmentTemplate = class {
116
116
  segmentIndex.mergeAndEvict(references,
117
117
  context.presentationTimeline.getSegmentAvailabilityStart());
118
118
  } else {
119
- context.presentationTimeline.notifySegments(references);
120
119
  segmentIndex = new shaka.media.SegmentIndex(references);
121
120
  if (id && context.dynamic) {
122
121
  segmentIndexMap[id] = segmentIndex;
123
122
  }
124
123
  }
124
+ context.presentationTimeline.notifySegments(references);
125
125
 
126
126
  if (shouldFit) {
127
127
  segmentIndex.fit(periodStart, periodEnd);