shaka-player 3.1.3 → 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 (182) hide show
  1. package/AUTHORS +3 -0
  2. package/CHANGELOG.md +175 -3
  3. package/CONTRIBUTORS +3 -0
  4. package/README.md +4 -4
  5. package/build/generateExterns.js +1 -1
  6. package/build/types/polyfill +1 -0
  7. package/demo/common/asset.js +9 -7
  8. package/demo/common/assets.js +11 -2
  9. package/demo/common/message_ids.js +2 -1
  10. package/demo/config.js +5 -2
  11. package/demo/index.html +1 -1
  12. package/demo/locales/en.json +2 -1
  13. package/demo/locales/source.json +8 -4
  14. package/demo/main.js +2 -1
  15. package/dist/controls.css +2 -2
  16. package/dist/controls.css.map +1 -1
  17. package/dist/demo.compiled.debug.js +15 -15
  18. package/dist/demo.compiled.debug.map +2 -2
  19. package/dist/demo.compiled.js +15 -15
  20. package/dist/demo.compiled.map +2 -2
  21. package/dist/deps.js +22 -21
  22. package/dist/locales.js +36 -36
  23. package/dist/receiver.compiled.debug.js +9 -9
  24. package/dist/receiver.compiled.debug.map +2 -2
  25. package/dist/receiver.compiled.js +9 -9
  26. package/dist/receiver.compiled.map +2 -2
  27. package/dist/shaka-player.compiled.d.ts +58 -10
  28. package/dist/shaka-player.compiled.debug.d.ts +58 -10
  29. package/dist/shaka-player.compiled.debug.externs.js +777 -717
  30. package/dist/shaka-player.compiled.debug.js +639 -607
  31. package/dist/shaka-player.compiled.debug.map +4 -4
  32. package/dist/shaka-player.compiled.externs.js +777 -717
  33. package/dist/shaka-player.compiled.js +826 -819
  34. package/dist/shaka-player.compiled.map +4 -4
  35. package/dist/shaka-player.ui.d.ts +58 -10
  36. package/dist/shaka-player.ui.debug.d.ts +58 -10
  37. package/dist/shaka-player.ui.debug.externs.js +529 -469
  38. package/dist/shaka-player.ui.debug.js +676 -645
  39. package/dist/shaka-player.ui.debug.map +4 -4
  40. package/dist/shaka-player.ui.externs.js +529 -469
  41. package/dist/shaka-player.ui.js +963 -955
  42. package/dist/shaka-player.ui.map +4 -4
  43. package/docs/tutorials/fairplay.md +1 -1
  44. package/docs/tutorials/ui.md +5 -5
  45. package/externs/aria.js +6 -0
  46. package/externs/shaka/ads.js +24 -1
  47. package/externs/shaka/manifest.js +6 -1
  48. package/externs/shaka/offline.js +5 -0
  49. package/externs/shaka/player.js +53 -9
  50. package/externs/shaka/text.js +10 -10
  51. package/externs/texttrack.js +3 -0
  52. package/karma.conf.js +1 -0
  53. package/lib/ads/ad_manager.js +16 -15
  54. package/lib/ads/client_side_ad_manager.js +52 -88
  55. package/lib/ads/server_side_ad_manager.js +26 -12
  56. package/lib/cast/cast_proxy.js +11 -2
  57. package/lib/cast/cast_receiver.js +2 -1
  58. package/lib/cast/cast_sender.js +2 -2
  59. package/lib/cast/cast_utils.js +6 -1
  60. package/lib/cea/cea608_data_channel.js +56 -56
  61. package/lib/cea/cea608_memory.js +33 -33
  62. package/lib/cea/cea708_service.js +43 -43
  63. package/lib/cea/cea708_window.js +38 -38
  64. package/lib/cea/cea_decoder.js +13 -14
  65. package/lib/cea/cea_utils.js +23 -23
  66. package/lib/cea/dtvcc_packet_builder.js +7 -7
  67. package/lib/cea/i_caption_decoder.js +2 -3
  68. package/lib/cea/i_cea_parser.js +2 -2
  69. package/lib/cea/mp4_cea_parser.js +6 -6
  70. package/lib/dash/dash_parser.js +98 -2
  71. package/lib/dash/segment_list.js +1 -1
  72. package/lib/dash/segment_template.js +1 -1
  73. package/lib/hls/hls_parser.js +159 -29
  74. package/lib/media/closed_caption_parser.js +1 -2
  75. package/lib/media/drm_engine.js +169 -192
  76. package/lib/media/gap_jumping_controller.js +4 -2
  77. package/lib/media/media_source_engine.js +1 -2
  78. package/lib/media/segment_index.js +3 -1
  79. package/lib/media/segment_reference.js +19 -2
  80. package/lib/media/streaming_engine.js +8 -7
  81. package/lib/net/networking_engine.js +3 -1
  82. package/lib/offline/download_manager.js +1 -2
  83. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  84. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  85. package/lib/offline/manifest_converter.js +3 -1
  86. package/lib/offline/storage.js +12 -14
  87. package/lib/player.js +437 -167
  88. package/lib/polyfill/aria.js +82 -0
  89. package/lib/polyfill/media_capabilities.js +7 -1
  90. package/lib/polyfill/mediasource.js +6 -0
  91. package/lib/polyfill/orientation.js +1 -1
  92. package/lib/polyfill/patchedmediakeys_apple.js +4 -4
  93. package/lib/polyfill/patchedmediakeys_ms.js +4 -4
  94. package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
  95. package/lib/routing/walker.js +2 -3
  96. package/lib/text/mp4_ttml_parser.js +3 -0
  97. package/lib/text/srt_text_parser.js +4 -4
  98. package/lib/text/text_engine.js +16 -4
  99. package/lib/text/ttml_text_parser.js +5 -0
  100. package/lib/text/ui_text_displayer.js +85 -37
  101. package/lib/text/vtt_text_parser.js +2 -2
  102. package/lib/text/web_vtt_generator.js +55 -12
  103. package/lib/util/error.js +6 -0
  104. package/lib/util/fake_event.js +53 -7
  105. package/lib/util/manifest_parser_utils.js +1 -0
  106. package/lib/util/mp4_box_parsers.js +20 -20
  107. package/lib/util/multi_map.js +8 -0
  108. package/lib/util/periods.js +4 -1
  109. package/lib/util/platform.js +13 -1
  110. package/lib/util/player_configuration.js +13 -1
  111. package/lib/util/stream_utils.js +153 -85
  112. package/lib/util/xml_utils.js +31 -12
  113. package/package.json +1 -1
  114. package/roadmap.md +24 -22
  115. package/shaka-player.uncompiled.js +1 -0
  116. package/test/cast/cast_proxy_unit.js +12 -6
  117. package/test/cast/cast_utils_unit.js +2 -1
  118. package/test/cea/cea608_memory_unit.js +1 -1
  119. package/test/cea/cea708_service_unit.js +8 -8
  120. package/test/cea/cea708_window_unit.js +6 -6
  121. package/test/cea/cea_decoder_unit.js +1 -1
  122. package/test/cea/dtvcc_packet_builder_unit.js +2 -2
  123. package/test/dash/dash_parser_manifest_unit.js +230 -2
  124. package/test/hls/hls_parser_unit.js +255 -1
  125. package/test/media/closed_caption_parser_unit.js +6 -1
  126. package/test/media/drm_engine_integration.js +86 -12
  127. package/test/media/drm_engine_unit.js +353 -450
  128. package/test/offline/manifest_convert_unit.js +2 -0
  129. package/test/offline/storage_integration.js +9 -19
  130. package/test/player_integration.js +90 -0
  131. package/test/player_src_equals_integration.js +52 -0
  132. package/test/player_unit.js +11 -33
  133. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  134. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  135. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  136. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  137. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  138. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  139. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  140. package/test/test/assets/3675/dash_0.mpd +30 -0
  141. package/test/test/assets/3675/dash_1.mpd +30 -0
  142. package/test/test/assets/3675/dash_2.mpd +30 -0
  143. package/test/test/assets/3675/dash_3.mpd +30 -0
  144. package/test/test/assets/3675/dash_4.mpd +30 -0
  145. package/test/test/assets/3675/dash_5.mpd +26 -0
  146. package/test/test/assets/3675/init-stream0.m4s +0 -0
  147. package/test/test/assets/chapters.srt +11 -0
  148. package/test/test/assets/chapters.vtt +10 -0
  149. package/test/test/util/cea_utils.js +12 -12
  150. package/test/test/util/fake_ad_manager.js +8 -1
  151. package/test/test/util/manifest_generator.js +2 -0
  152. package/test/test/util/manifest_parser_util.js +3 -1
  153. package/test/text/ttml_text_parser_unit.js +9 -0
  154. package/test/text/ui_text_displayer_unit.js +29 -17
  155. package/test/text/web_vtt_generator_unit.js +81 -7
  156. package/test/ui/localization_unit.js +15 -14
  157. package/test/ui/text_displayer_layout_unit.js +13 -1
  158. package/test/util/stream_utils_unit.js +153 -10
  159. package/ui/airplay_button.js +1 -1
  160. package/ui/audio_language_selection.js +2 -5
  161. package/ui/cast_button.js +6 -9
  162. package/ui/constants.js +0 -3
  163. package/ui/controls.js +4 -6
  164. package/ui/fast_forward_button.js +2 -3
  165. package/ui/fullscreen_button.js +1 -3
  166. package/ui/language_utils.js +1 -1
  167. package/ui/less/containers.less +3 -7
  168. package/ui/locales/ru.json +6 -6
  169. package/ui/localization.js +28 -51
  170. package/ui/loop_button.js +1 -3
  171. package/ui/mute_button.js +1 -3
  172. package/ui/overflow_menu.js +2 -3
  173. package/ui/pip_button.js +7 -10
  174. package/ui/playback_rate_selection.js +3 -6
  175. package/ui/presentation_time.js +1 -3
  176. package/ui/resolution_selection.js +4 -7
  177. package/ui/rewind_button.js +2 -3
  178. package/ui/seek_bar.js +2 -4
  179. package/ui/spacer.js +1 -1
  180. package/ui/text_selection.js +8 -11
  181. package/ui/ui_utils.js +1 -1
  182. package/ui/volume_bar.js +1 -3
@@ -19,7 +19,6 @@ goog.require('shaka.util.FakeEvent');
19
19
  goog.require('shaka.util.IDestroyable');
20
20
  goog.require('shaka.util.Iterables');
21
21
  goog.require('shaka.util.Lazy');
22
- goog.require('shaka.util.ManifestParserUtils');
23
22
  goog.require('shaka.util.MapUtils');
24
23
  goog.require('shaka.util.MimeUtils');
25
24
  goog.require('shaka.util.Platform');
@@ -213,10 +212,9 @@ shaka.media.DrmEngine = class {
213
212
  * @param {boolean} usePersistentLicenses
214
213
  * Whether or not persistent licenses should be requested and stored for
215
214
  * |manifest|.
216
- * @param {boolean=} useMediaCapabilities
217
215
  * @return {!Promise}
218
216
  */
219
- initForStorage(variants, usePersistentLicenses, useMediaCapabilities) {
217
+ initForStorage(variants, usePersistentLicenses) {
220
218
  this.initializedForStorage_ = true;
221
219
  // There are two cases for this call:
222
220
  // 1. We are about to store a manifest - in that case, there are no offline
@@ -230,7 +228,7 @@ shaka.media.DrmEngine = class {
230
228
  // persistent licenses.
231
229
  this.usePersistentLicenses_ = usePersistentLicenses;
232
230
 
233
- return this.init_(variants, !!useMediaCapabilities);
231
+ return this.init_(variants);
234
232
  }
235
233
 
236
234
  /**
@@ -239,14 +237,13 @@ shaka.media.DrmEngine = class {
239
237
  * @param {!Array.<shaka.extern.Variant>} variants
240
238
  * The variants that we want to support playing.
241
239
  * @param {!Array.<string>} offlineSessionIds
242
- * @param {boolean=} useMediaCapabilities
243
240
  * @return {!Promise}
244
241
  */
245
- initForPlayback(variants, offlineSessionIds, useMediaCapabilities) {
242
+ initForPlayback(variants, offlineSessionIds) {
246
243
  this.offlineSessionIds_ = offlineSessionIds;
247
244
  this.usePersistentLicenses_ = offlineSessionIds.length > 0;
248
245
 
249
- return this.init_(variants, !!useMediaCapabilities);
246
+ return this.init_(variants);
250
247
  }
251
248
 
252
249
  /**
@@ -285,14 +282,14 @@ shaka.media.DrmEngine = class {
285
282
  audioRobustness: '', // Not required by queryMediaKeys_
286
283
  videoRobustness: '', // Same
287
284
  serverCertificate: serverCertificate,
285
+ serverCertificateUri: '',
288
286
  initData: null,
289
287
  keyIds: null,
290
288
  }];
291
289
 
292
290
  configsByKeySystem.set(keySystem, config);
293
291
  return this.queryMediaKeys_(configsByKeySystem,
294
- /* variants= */ [],
295
- /* useMediaCapabilities= */ false);
292
+ /* variants= */ []);
296
293
  }
297
294
 
298
295
  /**
@@ -303,11 +300,10 @@ shaka.media.DrmEngine = class {
303
300
  * @param {!Array.<shaka.extern.Variant>} variants
304
301
  * The variants that we expect to operate with during the drm engine's
305
302
  * lifespan of the drm engine.
306
- * @param {boolean} useMediaCapabilities
307
303
  * @return {!Promise} Resolved if/when a key system has been chosen.
308
304
  * @private
309
305
  */
310
- async init_(variants, useMediaCapabilities) {
306
+ async init_(variants) {
311
307
  goog.asserts.assert(this.config_,
312
308
  'DrmEngine configure() must be called before init()!');
313
309
 
@@ -365,13 +361,8 @@ shaka.media.DrmEngine = class {
365
361
 
366
362
  // We should get the decodingInfo results for the variants after we filling
367
363
  // in the drm infos, and before queryMediaKeys_().
368
- if (useMediaCapabilities) {
369
- await shaka.util.StreamUtils.getDecodingInfosForVariants(variants,
370
- this.usePersistentLicenses_, this.srcEquals_);
371
- } else {
372
- configsByKeySystem =
373
- this.prepareMediaKeyConfigsForVariants_(variants);
374
- }
364
+ await shaka.util.StreamUtils.getDecodingInfosForVariants(variants,
365
+ this.usePersistentLicenses_, this.srcEquals_);
375
366
 
376
367
  const hasDrmInfo = hadDrmInfo || Object.keys(this.config_.servers).length;
377
368
  // An unencrypted content is initialized.
@@ -380,8 +371,7 @@ shaka.media.DrmEngine = class {
380
371
  return Promise.resolve();
381
372
  }
382
373
 
383
- const p = this.queryMediaKeys_(configsByKeySystem, variants,
384
- useMediaCapabilities);
374
+ const p = this.queryMediaKeys_(configsByKeySystem, variants);
385
375
 
386
376
  // TODO(vaage): Look into the assertion below. If we do not have any drm
387
377
  // info, we create drm info so that content can play if it has drm info
@@ -463,26 +453,63 @@ shaka.media.DrmEngine = class {
463
453
  goog.asserts.assert(this.initialized_,
464
454
  'Must call init() before setServerCertificate');
465
455
 
466
- if (this.mediaKeys_ &&
467
- this.currentDrmInfo_ &&
468
- this.currentDrmInfo_.serverCertificate &&
469
- this.currentDrmInfo_.serverCertificate.length) {
456
+ if (!this.mediaKeys_ || !this.currentDrmInfo_) {
457
+ return;
458
+ }
459
+
460
+ if (this.currentDrmInfo_.serverCertificateUri &&
461
+ (!this.currentDrmInfo_.serverCertificate ||
462
+ !this.currentDrmInfo_.serverCertificate.length)) {
463
+ const request = shaka.net.NetworkingEngine.makeRequest(
464
+ [this.currentDrmInfo_.serverCertificateUri],
465
+ this.config_.retryParameters);
466
+
470
467
  try {
471
- const supported = await this.mediaKeys_.setServerCertificate(
472
- this.currentDrmInfo_.serverCertificate);
473
- if (!supported) {
474
- shaka.log.warning('Server certificates are not supported by the ' +
475
- 'key system. The server certificate has been ' +
476
- 'ignored.');
477
- }
478
- } catch (exception) {
468
+ const operation = this.playerInterface_.netEngine.request(
469
+ shaka.net.NetworkingEngine.RequestType.SERVER_CERTIFICATE,
470
+ request);
471
+ const response = await operation.promise;
472
+
473
+ this.currentDrmInfo_.serverCertificate =
474
+ shaka.util.BufferUtils.toUint8(response.data);
475
+ } catch (error) {
476
+ // Request failed!
477
+ goog.asserts.assert(error instanceof shaka.util.Error,
478
+ 'Wrong NetworkingEngine error type!');
479
+
479
480
  throw new shaka.util.Error(
480
481
  shaka.util.Error.Severity.CRITICAL,
481
482
  shaka.util.Error.Category.DRM,
482
- shaka.util.Error.Code.INVALID_SERVER_CERTIFICATE,
483
- exception.message);
483
+ shaka.util.Error.Code.SERVER_CERTIFICATE_REQUEST_FAILED,
484
+ error);
485
+ }
486
+
487
+ if (this.destroyer_.destroyed()) {
488
+ return;
484
489
  }
485
490
  }
491
+
492
+ if (!this.currentDrmInfo_.serverCertificate ||
493
+ !this.currentDrmInfo_.serverCertificate.length) {
494
+ return;
495
+ }
496
+
497
+ try {
498
+ const supported = await this.mediaKeys_.setServerCertificate(
499
+ this.currentDrmInfo_.serverCertificate);
500
+
501
+ if (!supported) {
502
+ shaka.log.warning('Server certificates are not supported by the ' +
503
+ 'key system. The server certificate has been ' +
504
+ 'ignored.');
505
+ }
506
+ } catch (exception) {
507
+ throw new shaka.util.Error(
508
+ shaka.util.Error.Severity.CRITICAL,
509
+ shaka.util.Error.Category.DRM,
510
+ shaka.util.Error.Code.INVALID_SERVER_CERTIFICATE,
511
+ exception.message);
512
+ }
486
513
  }
487
514
 
488
515
  /**
@@ -578,7 +605,8 @@ shaka.media.DrmEngine = class {
578
605
  }
579
606
  }
580
607
 
581
- this.createTemporarySession_(initDataType, initData);
608
+ this.createSession(initDataType, initData,
609
+ this.currentDrmInfo_.sessionType);
582
610
  }
583
611
 
584
612
  /** @return {boolean} */
@@ -604,6 +632,17 @@ shaka.media.DrmEngine = class {
604
632
  return false;
605
633
  }
606
634
 
635
+ /**
636
+ * @param {?string} keySystem
637
+ * @return {boolean} */
638
+ static isFairPlayKeySystem(keySystem) {
639
+ if (keySystem) {
640
+ return !!keySystem.match(/^com\.apple\.fps/);
641
+ }
642
+
643
+ return false;
644
+ }
645
+
607
646
  /**
608
647
  * Check if DrmEngine (as initialized) will likely be able to support the
609
648
  * given content type.
@@ -707,149 +746,15 @@ shaka.media.DrmEngine = class {
707
746
  }
708
747
 
709
748
  /**
710
- * @param {!Array.<shaka.extern.Variant>} variants
711
- * @see https://bit.ly/EmeConfig for MediaKeySystemConfiguration spec
712
- * @return {!Map.<string, MediaKeySystemConfiguration>}
713
- * @private
749
+ * Returns the current media key sessions.
750
+ *
751
+ * @return {!Array.<MediaKeySession>}
714
752
  */
715
- prepareMediaKeyConfigsForVariants_(variants) {
716
- const ContentType = shaka.util.ManifestParserUtils.ContentType;
717
-
718
- // Get all the drm info so that we can avoid using nested loops when we just
719
- // need the drm info.
720
- const allDrmInfo = new Set();
721
- for (const variant of variants) {
722
- const drmInfos = this.getVariantDrmInfos_(variant);
723
- for (const info of drmInfos) {
724
- allDrmInfo.add(info);
725
- }
726
- }
727
-
728
- // Make sure all the drm infos are valid and filled in correctly.
729
- for (const info of allDrmInfo) {
730
- shaka.media.DrmEngine.fillInDrmInfoDefaults_(
731
- info,
732
- shaka.util.MapUtils.asMap(this.config_.servers),
733
- shaka.util.MapUtils.asMap(this.config_.advanced || {}));
734
- }
735
-
736
- const persistentState =
737
- this.usePersistentLicenses_ ? 'required' : 'optional';
738
- const sessionTypes =
739
- this.usePersistentLicenses_ ? ['persistent-license'] : ['temporary'];
740
-
741
- const configs = new Map();
742
-
743
- // Create a config entry for each key system.
744
- for (const info of allDrmInfo) {
745
- const config = {
746
- initDataTypes: ['cenc'],
747
- audioCapabilities: [],
748
- videoCapabilities: [],
749
- distinctiveIdentifier: 'optional',
750
- persistentState: persistentState,
751
- sessionTypes: sessionTypes,
752
- label: info.keySystem, // Tracked by us, ignored by EME.
753
- };
754
- // TODO: refactor, don't stick drmInfos onto MediaKeySystemConfiguration
755
- config['drmInfos'] = []; // Non-standard attribute, ignored by EME.
756
-
757
- // Multiple calls to |set| will still respect the insertion order of the
758
- // first call to |set| for a given key.
759
- configs.set(info.keySystem, config);
760
- }
761
-
762
- // Connect each key system with each stream using it.
763
- for (const variant of variants) {
764
- /** @type {?shaka.extern.Stream} */
765
- const audio = variant.audio;
766
- /** @type {?shaka.extern.Stream} */
767
- const video = variant.video;
768
-
769
- // Add the last bit of information to each config;
770
- for (const stream of [audio, video]) {
771
- if (!stream) {
772
- continue;
773
- }
774
-
775
- const mimeType = shaka.media.DrmEngine.computeMimeType_(stream);
776
- let fallbackMimeType = null;
777
-
778
- if (stream.codecs.toLowerCase() == 'ac-3' &&
779
- shaka.util.Platform.isTizen()) {
780
- // Some Tizen devices seem to misreport AC-3 support, but correctly
781
- // report EC-3 support. So query EC-3 as a fallback for AC-3.
782
- // See https://github.com/google/shaka-player/issues/2989 for details.
783
- fallbackMimeType = shaka.media.DrmEngine.computeMimeType_(stream,
784
- 'ec-3');
785
- }
786
-
787
- for (const info of stream.drmInfos) {
788
- const config = configs.get(info.keySystem);
789
- goog.asserts.assert(
790
- config,
791
- 'Any missing configs should have be filled in before.');
792
-
793
- // TODO: refactor, don't stick drmInfos onto
794
- // MediaKeySystemConfiguration
795
- config['drmInfos'].push(info);
796
-
797
- if (info.initData && info.initData.length) {
798
- config.initDataTypes = [
799
- ...new Set(
800
- info.initData.map((initData) => initData.initDataType)),
801
- ];
802
- }
803
-
804
- if (info.distinctiveIdentifierRequired) {
805
- config.distinctiveIdentifier = 'required';
806
- }
807
-
808
- if (info.persistentStateRequired) {
809
- config.persistentState = 'required';
810
- }
811
-
812
- if (info.sessionType) {
813
- config.sessionTypes = [info.sessionType];
814
- }
815
-
816
- const robustness = (stream.type == ContentType.AUDIO) ?
817
- info.audioRobustness : info.videoRobustness;
818
-
819
- /** @type {MediaKeySystemMediaCapability} */
820
- const capability = {
821
- robustness: robustness || '',
822
- contentType: mimeType,
823
- };
824
-
825
- if (stream.type == ContentType.AUDIO) {
826
- config.audioCapabilities.push(capability);
827
- } else {
828
- config.videoCapabilities.push(capability);
829
- }
830
-
831
- // This is how we work around some misbehaving platforms by adding
832
- // synthetic capability records using a fallback MIME type.
833
- if (fallbackMimeType) {
834
- /** @type {MediaKeySystemMediaCapability} */
835
- const fallbackCapability = {
836
- robustness: robustness || '',
837
- contentType: fallbackMimeType,
838
- };
839
-
840
- if (stream.type == ContentType.AUDIO) {
841
- config.audioCapabilities.push(fallbackCapability);
842
- } else {
843
- config.videoCapabilities.push(fallbackCapability);
844
- }
845
- }
846
- } // for (const info of stream.drmInfos)
847
- } // for (const stream of [audio, video])
848
- } // for (const variant of variants)
849
-
850
- return configs;
753
+ getMediaKeySessions() {
754
+ return Array.from(this.activeSessions_.keys());
851
755
  }
852
756
 
757
+
853
758
  /**
854
759
  * @param {shaka.extern.Stream} stream
855
760
  * @param {string=} codecOverride
@@ -872,14 +777,13 @@ shaka.media.DrmEngine = class {
872
777
  * A dictionary of configs, indexed by key system, with an iteration order
873
778
  * (insertion order) that reflects the preference for the application.
874
779
  * @param {!Array.<shaka.extern.Variant>} variants
875
- * @param {boolean} useMediaCapabilities
876
780
  * @return {!Promise} Resolved if/when a key system has been chosen.
877
781
  * @private
878
782
  */
879
- async queryMediaKeys_(configsByKeySystem, variants, useMediaCapabilities) {
783
+ async queryMediaKeys_(configsByKeySystem, variants) {
880
784
  const drmInfosByKeySystem = new Map();
881
785
 
882
- const mediaKeySystemAccess = useMediaCapabilities ?
786
+ const mediaKeySystemAccess = variants.length ?
883
787
  this.getKeySystemAccessFromVariants_(variants, drmInfosByKeySystem) :
884
788
  await this.getKeySystemAccessByConfigs_(configsByKeySystem);
885
789
 
@@ -918,7 +822,7 @@ shaka.media.DrmEngine = class {
918
822
  goog.asserts.assert(this.supportedTypes_.size,
919
823
  'We should get at least one supported MIME type');
920
824
 
921
- if (useMediaCapabilities) {
825
+ if (variants.length) {
922
826
  this.currentDrmInfo_ = this.createDrmInfoByInfos_(
923
827
  mediaKeySystemAccess.keySystem,
924
828
  drmInfosByKeySystem.get(mediaKeySystemAccess.keySystem));
@@ -990,6 +894,22 @@ shaka.media.DrmEngine = class {
990
894
  shaka.util.Error.Category.DRM,
991
895
  shaka.util.Error.Code.NO_RECOGNIZED_KEY_SYSTEMS);
992
896
  }
897
+
898
+ // If we have configured preferredKeySystems, choose a preferred keySystem
899
+ // if available.
900
+ for (const preferredKeySystem of this.config_.preferredKeySystems) {
901
+ for (const variant of variants) {
902
+ const decodingInfo = variant.decodingInfos.find((decodingInfo) => {
903
+ return decodingInfo.supported &&
904
+ decodingInfo.keySystemAccess != null &&
905
+ decodingInfo.keySystemAccess.keySystem == preferredKeySystem;
906
+ });
907
+ if (decodingInfo) {
908
+ return decodingInfo.keySystemAccess;
909
+ }
910
+ }
911
+ }
912
+
993
913
  // Try key systems with configured license servers first. We only have to
994
914
  // try key systems without configured license servers for diagnostic
995
915
  // reasons, so that we can differentiate between "none of these key
@@ -1045,6 +965,24 @@ shaka.media.DrmEngine = class {
1045
965
  }
1046
966
  }
1047
967
 
968
+ // If we have configured preferredKeySystems, choose the preferred one if
969
+ // available.
970
+ for (const keySystem of this.config_.preferredKeySystems) {
971
+ if (configsByKeySystem.has(keySystem)) {
972
+ const config = configsByKeySystem.get(keySystem);
973
+ try {
974
+ mediaKeySystemAccess = // eslint-disable-next-line no-await-in-loop
975
+ await navigator.requestMediaKeySystemAccess(keySystem, [config]);
976
+ return mediaKeySystemAccess;
977
+ } catch (error) {
978
+ // Suppress errors.
979
+ shaka.log.v2(
980
+ 'Requesting', keySystem, 'failed with config', config, error);
981
+ }
982
+ this.destroyer_.ensureNotDestroyed();
983
+ }
984
+ }
985
+
1048
986
  // Try key systems with configured license servers first. We only have to
1049
987
  // try key systems without configured license servers for diagnostic
1050
988
  // reasons, so that we can differentiate between "none of these key
@@ -1066,14 +1004,13 @@ shaka.media.DrmEngine = class {
1066
1004
 
1067
1005
  try {
1068
1006
  mediaKeySystemAccess = // eslint-disable-next-line no-await-in-loop
1069
- await navigator.requestMediaKeySystemAccess(
1070
- keySystem, [config]);
1007
+ await navigator.requestMediaKeySystemAccess(keySystem, [config]);
1071
1008
  return mediaKeySystemAccess;
1072
1009
  } catch (error) {
1010
+ // Suppress errors.
1073
1011
  shaka.log.v2(
1074
- 'Requesting', keySystem, 'failed with config',
1075
- config, error);
1076
- } // Suppress errors.
1012
+ 'Requesting', keySystem, 'failed with config', config, error);
1013
+ }
1077
1014
  this.destroyer_.ensureNotDestroyed();
1078
1015
  }
1079
1016
  }
@@ -1130,6 +1067,7 @@ shaka.media.DrmEngine = class {
1130
1067
  audioRobustness: '',
1131
1068
  videoRobustness: '',
1132
1069
  serverCertificate: null,
1070
+ serverCertificateUri: '',
1133
1071
  sessionType: '',
1134
1072
  initData: initDatas,
1135
1073
  keyIds: new Set(keyIds),
@@ -1214,16 +1152,14 @@ shaka.media.DrmEngine = class {
1214
1152
  /**
1215
1153
  * @param {string} initDataType
1216
1154
  * @param {!Uint8Array} initData
1217
- * @private
1155
+ * @param {string} sessionType
1218
1156
  */
1219
- createTemporarySession_(initDataType, initData) {
1157
+ createSession(initDataType, initData, sessionType) {
1220
1158
  goog.asserts.assert(this.mediaKeys_,
1221
1159
  'mediaKeys_ should be valid when creating temporary session.');
1222
1160
 
1223
1161
  let session;
1224
1162
 
1225
- const sessionType = this.currentDrmInfo_.sessionType;
1226
-
1227
1163
  try {
1228
1164
  shaka.log.info('Creating new', sessionType, 'session');
1229
1165
 
@@ -1889,9 +1825,16 @@ shaka.media.DrmEngine = class {
1889
1825
  // audio adaptations, so we shouldn't have to worry about checking
1890
1826
  // robustness.
1891
1827
  if (drm1.keySystem == drm2.keySystem) {
1828
+ /** @type {Array<shaka.extern.InitDataOverride>} */
1892
1829
  let initData = [];
1893
1830
  initData = initData.concat(drm1.initData || []);
1894
1831
  initData = initData.concat(drm2.initData || []);
1832
+ initData = initData.filter((d, i) => {
1833
+ return d.keyId === undefined || i === initData.findIndex((d2) => {
1834
+ return d2.keyId === d.keyId;
1835
+ });
1836
+ });
1837
+
1895
1838
  const keyIds = drm1.keyIds && drm2.keyIds ?
1896
1839
  new Set([...drm1.keyIds, ...drm2.keyIds]) :
1897
1840
  drm1.keyIds || drm2.keyIds;
@@ -1905,6 +1848,8 @@ shaka.media.DrmEngine = class {
1905
1848
  videoRobustness: drm1.videoRobustness || drm2.videoRobustness,
1906
1849
  audioRobustness: drm1.audioRobustness || drm2.audioRobustness,
1907
1850
  serverCertificate: drm1.serverCertificate || drm2.serverCertificate,
1851
+ serverCertificateUri: drm1.serverCertificateUri ||
1852
+ drm2.serverCertificateUri,
1908
1853
  initData,
1909
1854
  keyIds,
1910
1855
  };
@@ -1979,6 +1924,7 @@ shaka.media.DrmEngine = class {
1979
1924
  audioRobustness: '',
1980
1925
  videoRobustness: '',
1981
1926
  serverCertificate: null,
1927
+ serverCertificateUri: '',
1982
1928
  initData: [],
1983
1929
  keyIds: new Set(),
1984
1930
  });
@@ -2009,6 +1955,9 @@ shaka.media.DrmEngine = class {
2009
1955
  /** @type {!Array.<string>} */
2010
1956
  const licenseServers = [];
2011
1957
 
1958
+ /** @type {!Array.<string>} */
1959
+ const serverCertificateUris = [];
1960
+
2012
1961
  /** @type {!Array.<!Uint8Array>} */
2013
1962
  const serverCerts = [];
2014
1963
 
@@ -2018,8 +1967,9 @@ shaka.media.DrmEngine = class {
2018
1967
  /** @type {!Set.<string>} */
2019
1968
  const keyIds = new Set();
2020
1969
 
2021
- shaka.media.DrmEngine.processDrmInfos_(drmInfos, licenseServers,
2022
- serverCerts, initDatas, keyIds);
1970
+ shaka.media.DrmEngine.processDrmInfos_(
1971
+ drmInfos, licenseServers, serverCerts,
1972
+ serverCertificateUris, initDatas, keyIds);
2023
1973
 
2024
1974
  if (serverCerts.length > 1) {
2025
1975
  shaka.log.warning('Multiple unique server certificates found! ' +
@@ -2031,6 +1981,11 @@ shaka.media.DrmEngine = class {
2031
1981
  'Only the first will be used.');
2032
1982
  }
2033
1983
 
1984
+ if (serverCertificateUris.length > 1) {
1985
+ shaka.log.warning('Multiple unique server certificate URIs found! ' +
1986
+ 'Only the first will be used.');
1987
+ }
1988
+
2034
1989
  const defaultSessionType =
2035
1990
  this.usePersistentLicenses_ ? 'persistent-license' : 'temporary';
2036
1991
 
@@ -2044,6 +1999,7 @@ shaka.media.DrmEngine = class {
2044
1999
  audioRobustness: drmInfos[0].audioRobustness || '',
2045
2000
  videoRobustness: drmInfos[0].videoRobustness || '',
2046
2001
  serverCertificate: serverCerts[0],
2002
+ serverCertificateUri: serverCertificateUris[0],
2047
2003
  initData: initDatas,
2048
2004
  keyIds,
2049
2005
  };
@@ -2075,6 +2031,9 @@ shaka.media.DrmEngine = class {
2075
2031
  /** @type {!Array.<string>} */
2076
2032
  const licenseServers = [];
2077
2033
 
2034
+ /** @type {!Array.<string>} */
2035
+ const serverCertificateUris = [];
2036
+
2078
2037
  /** @type {!Array.<!Uint8Array>} */
2079
2038
  const serverCerts = [];
2080
2039
 
@@ -2086,13 +2045,19 @@ shaka.media.DrmEngine = class {
2086
2045
 
2087
2046
  // TODO: refactor, don't stick drmInfos onto MediaKeySystemConfiguration
2088
2047
  shaka.media.DrmEngine.processDrmInfos_(
2089
- config['drmInfos'], licenseServers, serverCerts, initDatas, keyIds);
2048
+ config['drmInfos'], licenseServers, serverCerts,
2049
+ serverCertificateUris, initDatas, keyIds);
2090
2050
 
2091
2051
  if (serverCerts.length > 1) {
2092
2052
  shaka.log.warning('Multiple unique server certificates found! ' +
2093
2053
  'Only the first will be used.');
2094
2054
  }
2095
2055
 
2056
+ if (serverCertificateUris.length > 1) {
2057
+ shaka.log.warning('Multiple unique server certificate URIs found! ' +
2058
+ 'Only the first will be used.');
2059
+ }
2060
+
2096
2061
  if (licenseServers.length > 1) {
2097
2062
  shaka.log.warning('Multiple unique license server URIs found! ' +
2098
2063
  'Only the first will be used.');
@@ -2114,6 +2079,7 @@ shaka.media.DrmEngine = class {
2114
2079
  audioRobustness: audioRobustness || '',
2115
2080
  videoRobustness: videoRobustness || '',
2116
2081
  serverCertificate: serverCerts[0],
2082
+ serverCertificateUri: serverCertificateUris[0],
2117
2083
  initData: initDatas,
2118
2084
  keyIds,
2119
2085
  };
@@ -2126,12 +2092,14 @@ shaka.media.DrmEngine = class {
2126
2092
  * @param {!Array.<shaka.extern.DrmInfo>} drmInfos
2127
2093
  * @param {!Array.<string>} licenseServers
2128
2094
  * @param {!Array.<!Uint8Array>} serverCerts
2095
+ * @param {!Array.<string>} serverCertificateUris
2129
2096
  * @param {!Array.<!shaka.extern.InitDataOverride>} initDatas
2130
2097
  * @param {!Set.<string>} keyIds
2131
2098
  * @private
2132
2099
  */
2133
2100
  static processDrmInfos_(
2134
- drmInfos, licenseServers, serverCerts, initDatas, keyIds) {
2101
+ drmInfos, licenseServers, serverCerts,
2102
+ serverCertificateUris, initDatas, keyIds) {
2135
2103
  /** @type {function(shaka.extern.InitDataOverride,
2136
2104
  * shaka.extern.InitDataOverride):boolean} */
2137
2105
  const initDataOverrideEqual = (a, b) => {
@@ -2150,6 +2118,11 @@ shaka.media.DrmEngine = class {
2150
2118
  licenseServers.push(drmInfo.licenseServerUri);
2151
2119
  }
2152
2120
 
2121
+ // Build an array of unique license servers.
2122
+ if (!serverCertificateUris.includes(drmInfo.serverCertificateUri)) {
2123
+ serverCertificateUris.push(drmInfo.serverCertificateUri);
2124
+ }
2125
+
2153
2126
  // Build an array of unique server certs.
2154
2127
  if (drmInfo.serverCertificate) {
2155
2128
  const found = serverCerts.some(
@@ -2262,6 +2235,10 @@ shaka.media.DrmEngine = class {
2262
2235
  if (advancedConfig.sessionType) {
2263
2236
  drmInfo.sessionType = advancedConfig.sessionType;
2264
2237
  }
2238
+
2239
+ if (!drmInfo.serverCertificateUri) {
2240
+ drmInfo.serverCertificateUri = advancedConfig.serverCertificateUri;
2241
+ }
2265
2242
  }
2266
2243
 
2267
2244
  // Chromecast has a variant of PlayReady that uses a different key
@@ -217,8 +217,10 @@ shaka.media.GapJumpingController = class {
217
217
  this.didFireLargeGap_ = true;
218
218
 
219
219
  // Event firing is synchronous.
220
- const event = new shaka.util.FakeEvent(
221
- 'largegap', {'currentTime': currentTime, 'gapSize': jumpSize});
220
+ const data = new Map()
221
+ .set('currentTime', currentTime)
222
+ .set('gapSize', jumpSize);
223
+ const event = new shaka.util.FakeEvent('largegap', data);
222
224
  event.cancelable = true;
223
225
  this.onEvent_(event);
224
226
 
@@ -48,8 +48,7 @@ shaka.media.MediaSourceEngine = class {
48
48
  * @param {!function(!Array.<shaka.extern.ID3Metadata>, number, ?number)=}
49
49
  * onMetadata
50
50
  */
51
- constructor(video, closedCaptionParser, textDisplayer,
52
- onMetadata) {
51
+ constructor(video, closedCaptionParser, textDisplayer, onMetadata) {
53
52
  /** @private {HTMLMediaElement} */
54
53
  this.video_ = video;
55
54
 
@@ -345,7 +345,9 @@ shaka.media.SegmentIndex = class {
345
345
  lastReference.initSegmentReference,
346
346
  lastReference.timestampOffset,
347
347
  lastReference.appendWindowStart,
348
- lastReference.appendWindowEnd);
348
+ lastReference.appendWindowEnd,
349
+ lastReference.partialReferences,
350
+ lastReference.tilesLayout);
349
351
  }
350
352
 
351
353