shaka-player 4.12.8 → 4.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/AUTHORS +1 -0
  2. package/CONTRIBUTORS +4 -0
  3. package/README.md +22 -21
  4. package/cspell.config.yaml +18 -0
  5. package/dist/controls.css +1 -1
  6. package/dist/controls.css.map +1 -1
  7. package/dist/deps.js +29 -24
  8. package/dist/locales.js +33 -33
  9. package/dist/shaka-player.compiled.d.ts +138 -36
  10. package/dist/shaka-player.compiled.debug.d.ts +138 -36
  11. package/dist/shaka-player.compiled.debug.externs.js +367 -107
  12. package/dist/shaka-player.compiled.debug.js +828 -765
  13. package/dist/shaka-player.compiled.debug.map +4 -4
  14. package/dist/shaka-player.compiled.externs.js +367 -107
  15. package/dist/shaka-player.compiled.js +1451 -1416
  16. package/dist/shaka-player.compiled.map +4 -4
  17. package/dist/shaka-player.ui.d.ts +172 -38
  18. package/dist/shaka-player.ui.debug.d.ts +172 -38
  19. package/dist/shaka-player.ui.debug.externs.js +406 -113
  20. package/dist/shaka-player.ui.debug.js +842 -766
  21. package/dist/shaka-player.ui.debug.map +4 -4
  22. package/dist/shaka-player.ui.externs.js +406 -113
  23. package/dist/shaka-player.ui.js +1670 -1628
  24. package/dist/shaka-player.ui.map +4 -4
  25. package/eslint.config.mjs +343 -0
  26. package/externs/airplay.js +1 -1
  27. package/externs/audiotrack.js +1 -1
  28. package/externs/awesomplete.js +1 -1
  29. package/externs/cast-sdk-v2.js +2 -2
  30. package/externs/cmcd.js +16 -1
  31. package/externs/device_sensor_event.js +1 -1
  32. package/externs/ima.js +8 -8
  33. package/externs/isoboxer.js +31 -31
  34. package/externs/jwk_set.js +1 -1
  35. package/externs/lcevc.js +8 -8
  36. package/externs/mediakeys.js +1 -1
  37. package/externs/mediasession.js +3 -2
  38. package/externs/mediatailor.js +18 -18
  39. package/externs/pictureinpicture.js +41 -1
  40. package/externs/playstation.js +2 -2
  41. package/externs/prefixed_eme.js +1 -1
  42. package/externs/shaka/abortable.js +4 -4
  43. package/externs/shaka/abr_manager.js +1 -1
  44. package/externs/shaka/ads.js +45 -6
  45. package/externs/shaka/cea.js +2 -2
  46. package/externs/shaka/codecs.js +4 -4
  47. package/externs/shaka/drm_info.js +6 -6
  48. package/externs/shaka/error.js +5 -5
  49. package/externs/shaka/manifest.js +51 -56
  50. package/externs/shaka/manifest_parser.js +3 -9
  51. package/externs/shaka/net.js +23 -20
  52. package/externs/shaka/offline.js +37 -37
  53. package/externs/shaka/offline_compat_v1.js +10 -10
  54. package/externs/shaka/offline_compat_v2.js +10 -10
  55. package/externs/shaka/player.js +139 -109
  56. package/externs/shaka/text.js +10 -3
  57. package/externs/shaka/transmuxer.js +1 -1
  58. package/externs/videotrack.js +1 -1
  59. package/lib/abr/ewma.js +1 -1
  60. package/lib/abr/simple_abr_manager.js +70 -22
  61. package/lib/ads/ad_manager.js +43 -18
  62. package/lib/ads/ad_utils.js +160 -58
  63. package/lib/ads/ads_stats.js +1 -1
  64. package/lib/ads/client_side_ad_manager.js +2 -2
  65. package/lib/ads/interstitial_ad.js +16 -11
  66. package/lib/ads/interstitial_ad_manager.js +419 -72
  67. package/lib/ads/interstitial_static_ad.js +299 -0
  68. package/lib/ads/media_tailor_ad.js +1 -0
  69. package/lib/ads/media_tailor_ad_manager.js +37 -36
  70. package/lib/ads/server_side_ad_manager.js +7 -6
  71. package/lib/cast/cast_receiver.js +5 -3
  72. package/lib/cast/cast_sender.js +2 -2
  73. package/lib/cast/cast_utils.js +20 -13
  74. package/lib/cea/cea608_data_channel.js +53 -53
  75. package/lib/cea/cea708_service.js +42 -40
  76. package/lib/cea/cea708_window.js +5 -2
  77. package/lib/cea/cea_decoder.js +5 -7
  78. package/lib/cea/mp4_cea_parser.js +1 -1
  79. package/lib/cea/sei_processor.js +1 -1
  80. package/lib/dash/content_protection.js +62 -192
  81. package/lib/dash/dash_parser.js +119 -119
  82. package/lib/dash/mpd_utils.js +14 -13
  83. package/lib/dash/segment_base.js +5 -5
  84. package/lib/dash/segment_list.js +10 -10
  85. package/lib/dash/segment_template.js +55 -53
  86. package/lib/debug/log.js +2 -2
  87. package/lib/dependencies/all.js +2 -1
  88. package/lib/{media → drm}/drm_engine.js +274 -143
  89. package/lib/{util → drm}/drm_utils.js +20 -11
  90. package/lib/drm/playready.js +233 -0
  91. package/lib/hls/hls_classes.js +14 -14
  92. package/lib/hls/hls_parser.js +257 -196
  93. package/lib/hls/hls_utils.js +14 -14
  94. package/lib/hls/manifest_text_parser.js +10 -10
  95. package/lib/media/adaptation_set.js +6 -5
  96. package/lib/media/adaptation_set_criteria.js +51 -379
  97. package/lib/media/buffering_observer.js +5 -4
  98. package/lib/media/closed_caption_parser.js +2 -2
  99. package/lib/media/content_workarounds.js +2 -2
  100. package/lib/media/example_based_criteria.js +69 -0
  101. package/lib/media/gap_jumping_controller.js +14 -1
  102. package/lib/media/manifest_filterer.js +8 -8
  103. package/lib/media/manifest_parser.js +2 -2
  104. package/lib/media/media_source_capabilities.js +20 -1
  105. package/lib/media/media_source_engine.js +84 -35
  106. package/lib/media/mp4_segment_index_parser.js +5 -5
  107. package/lib/media/playhead.js +2 -8
  108. package/lib/media/playhead_observer.js +1 -1
  109. package/lib/media/preference_based_criteria.js +333 -0
  110. package/lib/media/preload_manager.js +53 -37
  111. package/lib/media/presentation_timeline.js +2 -2
  112. package/lib/media/quality_observer.js +35 -35
  113. package/lib/media/region_observer.js +2 -2
  114. package/lib/media/region_timeline.js +3 -3
  115. package/lib/media/segment_index.js +14 -14
  116. package/lib/media/segment_prefetch.js +17 -13
  117. package/lib/media/segment_reference.js +7 -7
  118. package/lib/media/segment_utils.js +9 -9
  119. package/lib/media/streaming_engine.js +77 -38
  120. package/lib/media/time_ranges_utils.js +1 -1
  121. package/lib/media/video_wrapper.js +1 -1
  122. package/lib/media/webm_segment_index_parser.js +4 -4
  123. package/lib/mss/content_protection.js +17 -222
  124. package/lib/mss/mss_parser.js +23 -24
  125. package/lib/net/data_uri_plugin.js +1 -0
  126. package/lib/net/http_fetch_plugin.js +8 -7
  127. package/lib/net/http_plugin_utils.js +5 -2
  128. package/lib/net/http_xhr_plugin.js +4 -3
  129. package/lib/net/networking_engine.js +72 -17
  130. package/lib/net/networking_utils.js +5 -2
  131. package/lib/offline/download_info.js +5 -1
  132. package/lib/offline/download_manager.js +15 -4
  133. package/lib/offline/download_progress_estimator.js +1 -1
  134. package/lib/offline/indexeddb/base_storage_cell.js +9 -9
  135. package/lib/offline/indexeddb/db_connection.js +1 -1
  136. package/lib/offline/indexeddb/db_operation.js +2 -2
  137. package/lib/offline/indexeddb/eme_session_storage_cell.js +1 -1
  138. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  139. package/lib/offline/indexeddb/v1_storage_cell.js +3 -3
  140. package/lib/offline/indexeddb/v2_storage_cell.js +2 -2
  141. package/lib/offline/manifest_converter.js +11 -12
  142. package/lib/offline/offline_scheme.js +8 -4
  143. package/lib/offline/session_deleter.js +11 -11
  144. package/lib/offline/storage.js +137 -88
  145. package/lib/offline/storage_muxer.js +8 -8
  146. package/lib/offline/stored_content_utils.js +3 -3
  147. package/lib/offline/stream_bandwidth_estimator.js +1 -1
  148. package/lib/player.js +291 -207
  149. package/lib/polyfill/all.js +1 -1
  150. package/lib/polyfill/media_capabilities.js +5 -5
  151. package/lib/polyfill/patchedmediakeys_apple.js +6 -6
  152. package/lib/polyfill/patchedmediakeys_webkit.js +8 -8
  153. package/lib/polyfill/video_play_promise.js +0 -1
  154. package/lib/text/cue.js +3 -2
  155. package/lib/text/lrc_text_parser.js +1 -1
  156. package/lib/text/mp4_ttml_parser.js +1 -1
  157. package/lib/text/mp4_vtt_parser.js +3 -3
  158. package/lib/text/sbv_text_parser.js +1 -1
  159. package/lib/text/simple_text_displayer.js +37 -10
  160. package/lib/text/ssa_text_parser.js +3 -1
  161. package/lib/text/stub_text_displayer.js +12 -5
  162. package/lib/text/text_engine.js +5 -4
  163. package/lib/text/text_utils.js +4 -4
  164. package/lib/text/ttml_text_parser.js +21 -20
  165. package/lib/text/ui_text_displayer.js +20 -13
  166. package/lib/text/vtt_text_parser.js +10 -10
  167. package/lib/text/web_vtt_generator.js +2 -2
  168. package/lib/transmuxer/aac_transmuxer.js +2 -2
  169. package/lib/transmuxer/ac3_transmuxer.js +2 -2
  170. package/lib/transmuxer/adts.js +2 -0
  171. package/lib/transmuxer/ec3.js +3 -3
  172. package/lib/transmuxer/ec3_transmuxer.js +2 -2
  173. package/lib/transmuxer/h264.js +5 -5
  174. package/lib/transmuxer/h265.js +3 -3
  175. package/lib/transmuxer/mp3_transmuxer.js +2 -2
  176. package/lib/transmuxer/mpeg_audio.js +6 -6
  177. package/lib/transmuxer/mss_transmuxer.js +2 -0
  178. package/lib/transmuxer/transmuxer_engine.js +1 -1
  179. package/lib/transmuxer/ts_transmuxer.js +10 -10
  180. package/lib/util/abortable_operation.js +10 -10
  181. package/lib/util/array_utils.js +6 -6
  182. package/lib/util/cmcd_manager.js +149 -18
  183. package/lib/util/cmsd_manager.js +11 -11
  184. package/lib/util/config_utils.js +3 -3
  185. package/lib/util/content_steering_manager.js +17 -17
  186. package/lib/util/data_view_reader.js +3 -3
  187. package/lib/util/ebml_parser.js +1 -1
  188. package/lib/util/error.js +11 -6
  189. package/lib/util/event_manager.js +1 -1
  190. package/lib/util/exp_golomb.js +1 -1
  191. package/lib/util/fairplay_utils.js +6 -1
  192. package/lib/util/fake_event.js +3 -2
  193. package/lib/util/fake_event_target.js +1 -1
  194. package/lib/util/functional.js +8 -8
  195. package/lib/util/id3_utils.js +1 -1
  196. package/lib/util/iterables.js +6 -6
  197. package/lib/util/language_utils.js +17 -17
  198. package/lib/util/manifest_parser_utils.js +13 -13
  199. package/lib/util/map_utils.js +6 -6
  200. package/lib/util/media_ready_state_utils.js +1 -1
  201. package/lib/util/mime_utils.js +15 -4
  202. package/lib/util/mp4_box_parsers.js +5 -5
  203. package/lib/util/mp4_generator.js +31 -30
  204. package/lib/util/mp4_parser.js +2 -2
  205. package/lib/util/multi_map.js +5 -5
  206. package/lib/util/mutex.js +1 -1
  207. package/lib/util/networking.js +1 -1
  208. package/lib/util/object_utils.js +5 -1
  209. package/lib/util/operation_manager.js +1 -1
  210. package/lib/util/periods.js +24 -24
  211. package/lib/util/platform.js +8 -4
  212. package/lib/util/player_configuration.js +50 -17
  213. package/lib/util/pssh.js +34 -6
  214. package/lib/util/public_promise.js +2 -2
  215. package/lib/util/state_history.js +2 -2
  216. package/lib/util/stream_utils.js +138 -120
  217. package/lib/util/string_utils.js +4 -3
  218. package/lib/util/switch_history.js +2 -2
  219. package/lib/util/tXml.js +22 -17
  220. package/lib/util/text_parser.js +2 -2
  221. package/lib/util/timer.js +1 -1
  222. package/lib/util/ts_parser.js +22 -22
  223. package/lib/util/xml_utils.js +1 -0
  224. package/package.json +7 -4
  225. package/project-words.txt +485 -0
  226. package/shaka-player.uncompiled.js +1 -1
  227. package/third_party/closure-uri/uri.js +2 -2
  228. package/third_party/closure-uri/utils.js +2 -2
  229. package/third_party/language-mapping-list/language-mapping-list.js +1 -1
  230. package/ui/ad_statistics_button.js +9 -5
  231. package/ui/airplay_button.js +1 -0
  232. package/ui/audio_language_selection.js +2 -1
  233. package/ui/context_menu.js +2 -2
  234. package/ui/controls.js +7 -7
  235. package/ui/externs/ui.js +29 -21
  236. package/ui/externs/watermark.js +64 -0
  237. package/ui/fast_forward_button.js +1 -1
  238. package/ui/gl_matrix/matrix_4x4.js +11 -5
  239. package/ui/hidden_fast_forward_button.js +1 -1
  240. package/ui/hidden_seek_button.js +1 -1
  241. package/ui/language_utils.js +27 -26
  242. package/ui/less/buttons.less +2 -2
  243. package/ui/localization.js +21 -21
  244. package/ui/loop_button.js +2 -2
  245. package/ui/overflow_menu.js +2 -2
  246. package/ui/playback_rate_selection.js +1 -1
  247. package/ui/presentation_time.js +4 -1
  248. package/ui/range_element.js +2 -2
  249. package/ui/resolution_selection.js +42 -6
  250. package/ui/rewind_button.js +1 -1
  251. package/ui/seek_bar.js +5 -5
  252. package/ui/statistics_button.js +8 -4
  253. package/ui/text_selection.js +3 -2
  254. package/ui/ui.js +32 -2
  255. package/ui/vr_manager.js +3 -3
  256. package/ui/vr_utils.js +14 -14
  257. package/ui/vr_webgl.js +5 -5
  258. package/ui/watermark.js +313 -0
  259. package/.eslintignore +0 -4
  260. package/.eslintrc.js +0 -310
  261. package/lib/polyfill/patchedmediakeys_nop.js +0 -148
@@ -4,15 +4,15 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- goog.provide('shaka.media.DrmEngine');
7
+ goog.provide('shaka.drm.DrmEngine');
8
8
 
9
9
  goog.require('goog.asserts');
10
10
  goog.require('shaka.log');
11
+ goog.require('shaka.drm.DrmUtils');
11
12
  goog.require('shaka.net.NetworkingEngine');
12
13
  goog.require('shaka.util.ArrayUtils');
13
14
  goog.require('shaka.util.BufferUtils');
14
15
  goog.require('shaka.util.Destroyer');
15
- goog.require('shaka.util.DrmUtils');
16
16
  goog.require('shaka.util.Error');
17
17
  goog.require('shaka.util.EventManager');
18
18
  goog.require('shaka.util.FakeEvent');
@@ -33,12 +33,12 @@ goog.require('shaka.util.Uint8ArrayUtils');
33
33
 
34
34
 
35
35
  /** @implements {shaka.util.IDestroyable} */
36
- shaka.media.DrmEngine = class {
36
+ shaka.drm.DrmEngine = class {
37
37
  /**
38
- * @param {shaka.media.DrmEngine.PlayerInterface} playerInterface
38
+ * @param {shaka.drm.DrmEngine.PlayerInterface} playerInterface
39
39
  */
40
40
  constructor(playerInterface) {
41
- /** @private {?shaka.media.DrmEngine.PlayerInterface} */
41
+ /** @private {?shaka.drm.DrmEngine.PlayerInterface} */
42
42
  this.playerInterface_ = playerInterface;
43
43
 
44
44
  /** @private {MediaKeys} */
@@ -63,12 +63,12 @@ shaka.media.DrmEngine = class {
63
63
  this.eventManager_ = new shaka.util.EventManager();
64
64
 
65
65
  /**
66
- * @private {!Map.<MediaKeySession,
67
- * shaka.media.DrmEngine.SessionMetaData>}
66
+ * @private {!Map<MediaKeySession,
67
+ * shaka.drm.DrmEngine.SessionMetaData>}
68
68
  */
69
69
  this.activeSessions_ = new Map();
70
70
 
71
- /** @private {!Array.<!shaka.net.NetworkingEngine.PendingRequest>} */
71
+ /** @private {!Array<!shaka.net.NetworkingEngine.PendingRequest>} */
72
72
  this.activeRequests_ = [];
73
73
 
74
74
  /**
@@ -100,7 +100,7 @@ shaka.media.DrmEngine = class {
100
100
  * We may not have announced this information to the outside world yet,
101
101
  * which we delay to batch up changes and avoid spurious "missing key"
102
102
  * errors.
103
- * @private {!Map.<string, string>}
103
+ * @private {!Map<string, string>}
104
104
  */
105
105
  this.keyStatusByKeyId_ = new Map();
106
106
 
@@ -108,7 +108,7 @@ shaka.media.DrmEngine = class {
108
108
  * The key statuses most recently announced to other classes.
109
109
  * We may have more up-to-date information being collected in
110
110
  * this.keyStatusByKeyId_, which has not been batched up and released yet.
111
- * @private {!Map.<string, string>}
111
+ * @private {!Map<string, string>}
112
112
  */
113
113
  this.announcedKeyStatusByKeyId_ = new Map();
114
114
 
@@ -119,7 +119,7 @@ shaka.media.DrmEngine = class {
119
119
  /** @private {boolean} */
120
120
  this.usePersistentLicenses_ = false;
121
121
 
122
- /** @private {!Array.<!MediaKeyMessageEvent>} */
122
+ /** @private {!Array<!MediaKeyMessageEvent>} */
123
123
  this.mediaKeyMessageEvents_ = [];
124
124
 
125
125
  /** @private {boolean} */
@@ -243,7 +243,7 @@ shaka.media.DrmEngine = class {
243
243
  /**
244
244
  * Initialize the drm engine for storing and deleting stored content.
245
245
  *
246
- * @param {!Array.<shaka.extern.Variant>} variants
246
+ * @param {!Array<shaka.extern.Variant>} variants
247
247
  * The variants that are going to be stored.
248
248
  * @param {boolean} usePersistentLicenses
249
249
  * Whether or not persistent licenses should be requested and stored for
@@ -270,9 +270,9 @@ shaka.media.DrmEngine = class {
270
270
  /**
271
271
  * Initialize the drm engine for playback operations.
272
272
  *
273
- * @param {!Array.<shaka.extern.Variant>} variants
273
+ * @param {!Array<shaka.extern.Variant>} variants
274
274
  * The variants that we want to support playing.
275
- * @param {!Array.<string>} offlineSessionIds
275
+ * @param {!Array<string>} offlineSessionIds
276
276
  * @return {!Promise}
277
277
  */
278
278
  initForPlayback(variants, offlineSessionIds) {
@@ -302,13 +302,13 @@ shaka.media.DrmEngine = class {
302
302
  * @param {string} keySystem
303
303
  * @param {string} licenseServerUri
304
304
  * @param {Uint8Array} serverCertificate
305
- * @param {!Array.<MediaKeySystemMediaCapability>} audioCapabilities
306
- * @param {!Array.<MediaKeySystemMediaCapability>} videoCapabilities
305
+ * @param {!Array<MediaKeySystemMediaCapability>} audioCapabilities
306
+ * @param {!Array<MediaKeySystemMediaCapability>} videoCapabilities
307
307
  * @return {!Promise}
308
308
  */
309
309
  initForRemoval(keySystem, licenseServerUri, serverCertificate,
310
310
  audioCapabilities, videoCapabilities) {
311
- /** @type {!Map.<string, MediaKeySystemConfiguration>} */
311
+ /** @type {!Map<string, MediaKeySystemConfiguration>} */
312
312
  const configsByKeySystem = new Map();
313
313
 
314
314
  /** @type {MediaKeySystemConfiguration} */
@@ -345,7 +345,7 @@ shaka.media.DrmEngine = class {
345
345
  * This will assume that both |usePersistentLicences_| and
346
346
  * |storedPersistentSessions_| have been properly set.
347
347
  *
348
- * @param {!Array.<shaka.extern.Variant>} variants
348
+ * @param {!Array<shaka.extern.Variant>} variants
349
349
  * The variants that we expect to operate with during the drm engine's
350
350
  * lifespan of the drm engine.
351
351
  * @return {!Promise} Resolved if/when a key system has been chosen.
@@ -355,21 +355,7 @@ shaka.media.DrmEngine = class {
355
355
  goog.asserts.assert(this.config_,
356
356
  'DrmEngine configure() must be called before init()!');
357
357
 
358
- // ClearKey config overrides the manifest DrmInfo if present. The variants
359
- // are modified so that filtering in Player still works.
360
- // This comes before hadDrmInfo because it influences the value of that.
361
- /** @type {?shaka.extern.DrmInfo} */
362
- const clearKeyDrmInfo = this.configureClearKey_();
363
- if (clearKeyDrmInfo) {
364
- for (const variant of variants) {
365
- if (variant.video) {
366
- variant.video.drmInfos = [clearKeyDrmInfo];
367
- }
368
- if (variant.audio) {
369
- variant.audio.drmInfos = [clearKeyDrmInfo];
370
- }
371
- }
372
- }
358
+ shaka.drm.DrmEngine.configureClearKey(this.config_.clearKeys, variants);
373
359
 
374
360
  const hadDrmInfo = variants.some((variant) => {
375
361
  if (variant.video && variant.video.drmInfos.length) {
@@ -390,7 +376,7 @@ shaka.media.DrmEngine = class {
390
376
  // systems as possible so that we will be ready.
391
377
  if (!hadDrmInfo) {
392
378
  const servers = shaka.util.MapUtils.asMap(this.config_.servers);
393
- shaka.media.DrmEngine.replaceDrmInfo_(variants, servers);
379
+ shaka.drm.DrmEngine.replaceDrmInfo_(variants, servers);
394
380
  }
395
381
 
396
382
  /** @type {!Set<shaka.extern.DrmInfo>} */
@@ -403,16 +389,79 @@ shaka.media.DrmEngine = class {
403
389
  }
404
390
 
405
391
  for (const info of drmInfos) {
406
- shaka.media.DrmEngine.fillInDrmInfoDefaults_(
392
+ shaka.drm.DrmEngine.fillInDrmInfoDefaults_(
407
393
  info,
408
394
  shaka.util.MapUtils.asMap(this.config_.servers),
409
395
  shaka.util.MapUtils.asMap(this.config_.advanced || {}),
410
396
  this.config_.keySystemsMapping);
411
397
  }
412
398
 
413
- /** @type {!Map.<string, MediaKeySystemConfiguration>} */
399
+ /** @type {!Map<string, MediaKeySystemConfiguration>} */
414
400
  let configsByKeySystem;
415
401
 
402
+ /**
403
+ * Expand robustness into multiple drm infos if multiple video robustness
404
+ * levels were provided.
405
+ *
406
+ * robustness can be either a single item as a string or multiple items as
407
+ * an array of strings.
408
+ *
409
+ * @param {!Array<shaka.extern.DrmInfo>} drmInfos
410
+ * @param {string} robustnessType
411
+ * @return {!Array<shaka.extern.DrmInfo>}
412
+ */
413
+ const expandRobustness = (drmInfos, robustnessType) => {
414
+ const newDrmInfos = [];
415
+ for (const drmInfo of drmInfos) {
416
+ let items = drmInfo[robustnessType] ||
417
+ (this.config_.advanced &&
418
+ this.config_.advanced[drmInfo.keySystem] &&
419
+ this.config_.advanced[drmInfo.keySystem][robustnessType]) || '';
420
+ if (items == '' &&
421
+ shaka.drm.DrmUtils.isWidevineKeySystem(drmInfo.keySystem)) {
422
+ if (robustnessType == 'audioRobustness') {
423
+ items = [this.config_.defaultAudioRobustnessForWidevine];
424
+ } else if (robustnessType == 'videoRobustness') {
425
+ items = [this.config_.defaultVideoRobustnessForWidevine];
426
+ }
427
+ }
428
+ if (typeof items === 'string') {
429
+ // if drmInfo's robustness has already been expanded,
430
+ // use the drmInfo directly.
431
+ newDrmInfos.push(drmInfo);
432
+ } else if (Array.isArray(items)) {
433
+ if (items.length === 0) {
434
+ items = [''];
435
+ }
436
+ for (const item of items) {
437
+ newDrmInfos.push(
438
+ Object.assign({}, drmInfo, {[robustnessType]: item}),
439
+ );
440
+ }
441
+ }
442
+ }
443
+ return newDrmInfos;
444
+ };
445
+
446
+ for (const variant of variants) {
447
+ if (variant.video) {
448
+ variant.video.drmInfos =
449
+ expandRobustness(variant.video.drmInfos,
450
+ 'videoRobustness');
451
+ variant.video.drmInfos =
452
+ expandRobustness(variant.video.drmInfos,
453
+ 'audioRobustness');
454
+ }
455
+ if (variant.audio) {
456
+ variant.audio.drmInfos =
457
+ expandRobustness(variant.audio.drmInfos,
458
+ 'videoRobustness');
459
+ variant.audio.drmInfos =
460
+ expandRobustness(variant.audio.drmInfos,
461
+ 'audioRobustness');
462
+ }
463
+ }
464
+
416
465
  // We should get the decodingInfo results for the variants after we filling
417
466
  // in the drm infos, and before queryMediaKeys_().
418
467
  await shaka.util.StreamUtils.getDecodingInfosForVariants(variants,
@@ -560,7 +609,7 @@ shaka.media.DrmEngine = class {
560
609
 
561
610
  // Explicit init data for any one stream or an offline session is
562
611
  // sufficient to suppress 'encrypted' events for all streams.
563
- // Also suppress 'encrypted' events when parsing in-band ppsh
612
+ // Also suppress 'encrypted' events when parsing in-band pssh
564
613
  // from media segments because that serves the same purpose as the
565
614
  // 'encrypted' events.
566
615
  if (!this.manifestInitData_ && !this.storedPersistentSessions_.size &&
@@ -781,7 +830,7 @@ shaka.media.DrmEngine = class {
781
830
 
782
831
  // If there are pre-existing sessions that have all been loaded
783
832
  // then reset the allSessionsLoaded_ promise, which can now be
784
- // used to wait for new sesssions to be loaded
833
+ // used to wait for new sessions to be loaded
785
834
  if (this.activeSessions_.size > 0 && this.areAllSessionsLoaded_()) {
786
835
  this.allSessionsLoaded_.resolve();
787
836
  this.hasInitData_ = false;
@@ -800,7 +849,7 @@ shaka.media.DrmEngine = class {
800
849
  /**
801
850
  * Returns the ID of the sessions currently active.
802
851
  *
803
- * @return {!Array.<string>}
852
+ * @return {!Array<string>}
804
853
  */
805
854
  getSessionIds() {
806
855
  const sessions = this.activeSessions_.keys();
@@ -813,7 +862,7 @@ shaka.media.DrmEngine = class {
813
862
  /**
814
863
  * Returns the active sessions metadata
815
864
  *
816
- * @return {!Array.<shaka.extern.DrmSessionMetadata>}
865
+ * @return {!Array<shaka.extern.DrmSessionMetadata>}
817
866
  */
818
867
  getActiveSessionsMetadata() {
819
868
  const sessions = this.activeSessions_.keys();
@@ -882,7 +931,7 @@ shaka.media.DrmEngine = class {
882
931
  /**
883
932
  * Returns the current key statuses.
884
933
  *
885
- * @return {!Object.<string, string>}
934
+ * @return {!Object<string, string>}
886
935
  */
887
936
  getKeyStatuses() {
888
937
  return shaka.util.MapUtils.asObject(this.announcedKeyStatusByKeyId_);
@@ -891,17 +940,17 @@ shaka.media.DrmEngine = class {
891
940
  /**
892
941
  * Returns the current media key sessions.
893
942
  *
894
- * @return {!Array.<MediaKeySession>}
943
+ * @return {!Array<MediaKeySession>}
895
944
  */
896
945
  getMediaKeySessions() {
897
946
  return Array.from(this.activeSessions_.keys());
898
947
  }
899
948
 
900
949
  /**
901
- * @param {!Map.<string, MediaKeySystemConfiguration>} configsByKeySystem
950
+ * @param {!Map<string, MediaKeySystemConfiguration>} configsByKeySystem
902
951
  * A dictionary of configs, indexed by key system, with an iteration order
903
952
  * (insertion order) that reflects the preference for the application.
904
- * @param {!Array.<shaka.extern.Variant>} variants
953
+ * @param {!Array<shaka.extern.Variant>} variants
905
954
  * @return {!Promise} Resolved if/when a key system has been chosen.
906
955
  * @private
907
956
  */
@@ -913,6 +962,12 @@ shaka.media.DrmEngine = class {
913
962
  await this.getKeySystemAccessByConfigs_(configsByKeySystem);
914
963
 
915
964
  if (!mediaKeySystemAccess) {
965
+ if (!navigator.requestMediaKeySystemAccess) {
966
+ throw new shaka.util.Error(
967
+ shaka.util.Error.Severity.CRITICAL,
968
+ shaka.util.Error.Category.DRM,
969
+ shaka.util.Error.Code.MISSING_EME_SUPPORT);
970
+ }
916
971
  throw new shaka.util.Error(
917
972
  shaka.util.Error.Severity.CRITICAL,
918
973
  shaka.util.Error.Category.DRM,
@@ -936,7 +991,7 @@ shaka.media.DrmEngine = class {
936
991
  this.currentDrmInfo_ = this.createDrmInfoByInfos_(
937
992
  keySystem, drmInfosByKeySystem.get(keySystem));
938
993
  } else {
939
- this.currentDrmInfo_ = shaka.media.DrmEngine.createDrmInfoByConfigs_(
994
+ this.currentDrmInfo_ = shaka.drm.DrmEngine.createDrmInfoByConfigs_(
940
995
  keySystem, configsByKeySystem.get(keySystem));
941
996
  }
942
997
  if (!this.currentDrmInfo_.licenseServerUri) {
@@ -1001,8 +1056,8 @@ shaka.media.DrmEngine = class {
1001
1056
 
1002
1057
  /**
1003
1058
  * Get the MediaKeySystemAccess from the decodingInfos of the variants.
1004
- * @param {!Array.<shaka.extern.Variant>} variants
1005
- * @param {!Map.<string, !Array.<shaka.extern.DrmInfo>>} drmInfosByKeySystem
1059
+ * @param {!Array<shaka.extern.Variant>} variants
1060
+ * @param {!Map<string, !Array<shaka.extern.DrmInfo>>} drmInfosByKeySystem
1006
1061
  * A dictionary of drmInfos, indexed by key system.
1007
1062
  * @return {MediaKeySystemAccess}
1008
1063
  * @private
@@ -1071,10 +1126,10 @@ shaka.media.DrmEngine = class {
1071
1126
 
1072
1127
  /**
1073
1128
  * Get the MediaKeySystemAccess by querying requestMediaKeySystemAccess.
1074
- * @param {!Map.<string, MediaKeySystemConfiguration>} configsByKeySystem
1129
+ * @param {!Map<string, MediaKeySystemConfiguration>} configsByKeySystem
1075
1130
  * A dictionary of configs, indexed by key system, with an iteration order
1076
1131
  * (insertion order) that reflects the preference for the application.
1077
- * @return {!Promise.<MediaKeySystemAccess>} Resolved if/when a
1132
+ * @return {!Promise<MediaKeySystemAccess>} Resolved if/when a
1078
1133
  * mediaKeySystemAccess has been chosen.
1079
1134
  * @private
1080
1135
  */
@@ -1152,23 +1207,6 @@ shaka.media.DrmEngine = class {
1152
1207
  return mediaKeySystemAccess;
1153
1208
  }
1154
1209
 
1155
- /**
1156
- * Create a DrmInfo using configured clear keys.
1157
- * The server URI will be a data URI which decodes to a clearkey license.
1158
- * @return {?shaka.extern.DrmInfo} or null if clear keys are not configured.
1159
- * @private
1160
- * @see https://bit.ly/2K8gOnv for the spec on the clearkey license format.
1161
- */
1162
- configureClearKey_() {
1163
- const clearKeys = shaka.util.MapUtils.asMap(this.config_.clearKeys);
1164
- if (clearKeys.size == 0) {
1165
- return null;
1166
- }
1167
-
1168
- const ManifestParserUtils = shaka.util.ManifestParserUtils;
1169
- return ManifestParserUtils.createDrmInfoFromClearKeys(clearKeys);
1170
- }
1171
-
1172
1210
  /**
1173
1211
  * Resolves the allSessionsLoaded_ promise when all the sessions are loaded
1174
1212
  *
@@ -1184,7 +1222,7 @@ shaka.media.DrmEngine = class {
1184
1222
  * In case there are no key statuses, consider this session loaded
1185
1223
  * after a reasonable timeout. It should definitely not take 5
1186
1224
  * seconds to process a license.
1187
- * @param {!shaka.media.DrmEngine.SessionMetaData} metadata
1225
+ * @param {!shaka.drm.DrmEngine.SessionMetaData} metadata
1188
1226
  * @private
1189
1227
  */
1190
1228
  setLoadSessionTimeoutTimer_(metadata) {
@@ -1194,13 +1232,13 @@ shaka.media.DrmEngine = class {
1194
1232
  });
1195
1233
 
1196
1234
  timer.tickAfter(
1197
- /* seconds= */ shaka.media.DrmEngine.SESSION_LOAD_TIMEOUT_);
1235
+ /* seconds= */ shaka.drm.DrmEngine.SESSION_LOAD_TIMEOUT_);
1198
1236
  }
1199
1237
 
1200
1238
  /**
1201
1239
  * @param {string} sessionId
1202
1240
  * @param {{initData: ?Uint8Array, initDataType: ?string}} sessionMetadata
1203
- * @return {!Promise.<MediaKeySession>}
1241
+ * @return {!Promise<MediaKeySession>}
1204
1242
  * @private
1205
1243
  */
1206
1244
  async loadOfflineSession_(sessionId, sessionMetadata) {
@@ -1456,12 +1494,12 @@ shaka.media.DrmEngine = class {
1456
1494
  }
1457
1495
  // NOTE: allowCrossSiteCredentials can be set in a request filter.
1458
1496
 
1459
- if (shaka.util.DrmUtils.isClearKeySystem(
1497
+ if (shaka.drm.DrmUtils.isClearKeySystem(
1460
1498
  this.currentDrmInfo_.keySystem)) {
1461
1499
  this.fixClearKeyRequest_(request, this.currentDrmInfo_);
1462
1500
  }
1463
1501
 
1464
- if (shaka.util.DrmUtils.isPlayReadyKeySystem(
1502
+ if (shaka.drm.DrmUtils.isPlayReadyKeySystem(
1465
1503
  this.currentDrmInfo_.keySystem)) {
1466
1504
  this.unpackPlayReadyRequest_(request);
1467
1505
  }
@@ -1611,7 +1649,7 @@ shaka.media.DrmEngine = class {
1611
1649
  goog.asserts.assert(challenge.attributes['encoding'] == 'base64encoded',
1612
1650
  'Unexpected PlayReady challenge encoding!');
1613
1651
  request.body = shaka.util.Uint8ArrayUtils.fromBase64(
1614
- /** @type{string} */(shaka.util.TXml.getTextContents(challenge)));
1652
+ /** @type {string} */(shaka.util.TXml.getTextContents(challenge)));
1615
1653
  }
1616
1654
 
1617
1655
  /**
@@ -1626,7 +1664,7 @@ shaka.media.DrmEngine = class {
1626
1664
  const body = shaka.util.StringUtils.fromBytesAutoDetect(request.body);
1627
1665
  if (body) {
1628
1666
  const licenseBody =
1629
- /** @type {shaka.media.DrmEngine.ClearKeyLicenceRequestFormat} */ (
1667
+ /** @type {shaka.drm.DrmEngine.ClearKeyLicenceRequestFormat} */ (
1630
1668
  JSON.parse(body));
1631
1669
  if (!licenseBody.type) {
1632
1670
  licenseBody.type = drmInfo.sessionType;
@@ -1673,7 +1711,7 @@ shaka.media.DrmEngine = class {
1673
1711
  // NOTE that we skip this if byteLength != 16. This is used for Edge
1674
1712
  // which uses single-byte dummy key IDs.
1675
1713
  // However, unlike Edge and Chromecast, Tizen doesn't have this problem.
1676
- if (shaka.util.DrmUtils.isPlayReadyKeySystem(
1714
+ if (shaka.drm.DrmUtils.isPlayReadyKeySystem(
1677
1715
  this.currentDrmInfo_.keySystem) &&
1678
1716
  keyId.byteLength == 16 &&
1679
1717
  (shaka.util.Platform.isEdge() || shaka.util.Platform.isPS4())) {
@@ -1719,7 +1757,7 @@ shaka.media.DrmEngine = class {
1719
1757
  if (found && !found.updatePromise) {
1720
1758
  shaka.log.debug('Session has expired', session.sessionId);
1721
1759
  this.activeSessions_.delete(session);
1722
- session.close().catch(() => {}); // Silence uncaught rejection errors
1760
+ this.closeSession_(session);
1723
1761
  }
1724
1762
  }
1725
1763
 
@@ -1737,7 +1775,7 @@ shaka.media.DrmEngine = class {
1737
1775
  // each of them. By batching these up, we only send one status change event
1738
1776
  // and at most one EXPIRED error on expiration.
1739
1777
  this.keyStatusTimer_.tickAfter(
1740
- /* seconds= */ shaka.media.DrmEngine.KEY_STATUS_BATCH_TIME);
1778
+ /* seconds= */ shaka.drm.DrmEngine.KEY_STATUS_BATCH_TIME);
1741
1779
  }
1742
1780
 
1743
1781
  /** @private */
@@ -1768,12 +1806,9 @@ shaka.media.DrmEngine = class {
1768
1806
  /**
1769
1807
  * Returns a Promise to a map of EME support for well-known key systems.
1770
1808
  *
1771
- * @return {!Promise.<!Object.<string, ?shaka.extern.DrmSupportType>>}
1809
+ * @return {!Promise<!Object<string, ?shaka.extern.DrmSupportType>>}
1772
1810
  */
1773
1811
  static async probeSupport() {
1774
- goog.asserts.assert(shaka.util.DrmUtils.isBrowserSupported(),
1775
- 'Must have basic EME support');
1776
-
1777
1812
  const testKeySystems = [
1778
1813
  'org.w3.clearkey',
1779
1814
  'com.widevine.alpha',
@@ -1784,6 +1819,27 @@ shaka.media.DrmEngine = class {
1784
1819
  'com.chromecast.playready',
1785
1820
  'com.apple.fps.1_0',
1786
1821
  'com.apple.fps',
1822
+ 'com.huawei.wiseplay',
1823
+ ];
1824
+
1825
+ if (!shaka.drm.DrmUtils.isBrowserSupported()) {
1826
+ const result = {};
1827
+ for (const keySystem of testKeySystems) {
1828
+ result[keySystem] = null;
1829
+ }
1830
+ return result;
1831
+ }
1832
+
1833
+ const hdcpVersions = [
1834
+ '1.0',
1835
+ '1.1',
1836
+ '1.2',
1837
+ '1.3',
1838
+ '1.4',
1839
+ '2.0',
1840
+ '2.1',
1841
+ '2.2',
1842
+ '2.3',
1787
1843
  ];
1788
1844
 
1789
1845
  const widevineRobustness = [
@@ -1829,7 +1885,7 @@ shaka.media.DrmEngine = class {
1829
1885
  'cbcs-1-9',
1830
1886
  ];
1831
1887
 
1832
- /** @type {!Map.<string, ?shaka.extern.DrmSupportType>} */
1888
+ /** @type {!Map<string, ?shaka.extern.DrmSupportType>} */
1833
1889
  const support = new Map();
1834
1890
 
1835
1891
  /**
@@ -1838,8 +1894,9 @@ shaka.media.DrmEngine = class {
1838
1894
  * @return {!Promise}
1839
1895
  */
1840
1896
  const processMediaKeySystemAccess = async (keySystem, access) => {
1897
+ let mediaKeys;
1841
1898
  try {
1842
- await access.createMediaKeys();
1899
+ mediaKeys = await access.createMediaKeys();
1843
1900
  } catch (error) {
1844
1901
  // In some cases, we can get a successful access object but fail to
1845
1902
  // create a MediaKeys instance. When this happens, don't update the
@@ -1869,6 +1926,7 @@ shaka.media.DrmEngine = class {
1869
1926
  encryptionSchemes: [],
1870
1927
  videoRobustnessLevels: [],
1871
1928
  audioRobustnessLevels: [],
1929
+ minHdcpVersions: [],
1872
1930
  };
1873
1931
  if (support.has(keySystem) && support.get(keySystem)) {
1874
1932
  // Update the existing non-null value.
@@ -1898,6 +1956,24 @@ shaka.media.DrmEngine = class {
1898
1956
  !supportValue.audioRobustnessLevels.includes(audioRobustness)) {
1899
1957
  supportValue.audioRobustnessLevels.push(audioRobustness);
1900
1958
  }
1959
+
1960
+ if ('getStatusForPolicy' in mediaKeys) {
1961
+ const promises = [];
1962
+ for (const hdcpVersion of hdcpVersions) {
1963
+ if (supportValue.minHdcpVersions.includes(hdcpVersion)) {
1964
+ continue;
1965
+ }
1966
+ promises.push(mediaKeys.getStatusForPolicy({
1967
+ minHdcpVersion: hdcpVersion,
1968
+ }).then((status) => {
1969
+ if (status == 'usable' &&
1970
+ !supportValue.minHdcpVersions.includes(hdcpVersion)) {
1971
+ supportValue.minHdcpVersions.push(hdcpVersion);
1972
+ }
1973
+ }));
1974
+ }
1975
+ await Promise.all(promises);
1976
+ }
1901
1977
  };
1902
1978
 
1903
1979
  const testSystemEme = async (keySystem, encryptionScheme,
@@ -1923,10 +1999,10 @@ shaka.media.DrmEngine = class {
1923
1999
  // requestMediaKeySystemAccess will
1924
2000
  // not resolve or reject, at least if RESOURCE_PROTECTED_MEDIA_ID
1925
2001
  // is not set. This is a workaround for that issue.
1926
- const TIMEOUT_FOR_CHECKACCESS_IN_SECONDS = 1;
2002
+ const TIMEOUT_FOR_CHECK_ACCESS_IN_SECONDS = 1;
1927
2003
  const access =
1928
2004
  await shaka.util.Functional.promiseWithTimeout(
1929
- TIMEOUT_FOR_CHECKACCESS_IN_SECONDS,
2005
+ TIMEOUT_FOR_CHECK_ACCESS_IN_SECONDS,
1930
2006
  navigator.requestMediaKeySystemAccess(keySystem, configs),
1931
2007
  );
1932
2008
  await processMediaKeySystemAccess(keySystem, access);
@@ -1986,17 +2062,47 @@ shaka.media.DrmEngine = class {
1986
2062
  support.set(keySystem, null);
1987
2063
  }
1988
2064
 
2065
+ const checkKeySystem = (keySystem) => {
2066
+ // Our Polyfill will reject anything apart com.apple.fps key systems.
2067
+ // It seems the Safari modern EME API will allow to request a
2068
+ // MediaKeySystemAccess for the ClearKey CDM, create and update a key
2069
+ // session but playback will never start
2070
+ // Safari bug: https://bugs.webkit.org/show_bug.cgi?id=231006
2071
+ if (shaka.drm.DrmUtils.isClearKeySystem(keySystem) &&
2072
+ shaka.util.Platform.isSafari()) {
2073
+ return false;
2074
+ }
2075
+ // FairPlay is a proprietary DRM from Apple and will never work on
2076
+ // Windows.
2077
+ if (shaka.drm.DrmUtils.isFairPlayKeySystem(keySystem) &&
2078
+ shaka.util.Platform.isWindows()) {
2079
+ return false;
2080
+ }
2081
+ // PlayReady is a proprietary DRM from Microsoft and will never work on
2082
+ // Apple platforms
2083
+ if (shaka.drm.DrmUtils.isPlayReadyKeySystem(keySystem) &&
2084
+ (shaka.util.Platform.isMac() || shaka.util.Platform.isApple())) {
2085
+ return false;
2086
+ }
2087
+ // Mozilla has no intention of supporting PlayReady according to
2088
+ // comments posted on Bugzilla.
2089
+ if (shaka.drm.DrmUtils.isPlayReadyKeySystem(keySystem) &&
2090
+ shaka.util.Platform.isFirefox()) {
2091
+ return false;
2092
+ }
2093
+ // We are sure that WisePlay is not supported on Windows or macOS.
2094
+ if (shaka.drm.DrmUtils.isWisePlayKeySystem(keySystem) &&
2095
+ (shaka.util.Platform.isWindows() || shaka.util.Platform.isMac())) {
2096
+ return false;
2097
+ }
2098
+ return true;
2099
+ };
2100
+
1989
2101
  // Test each key system and encryption scheme.
1990
2102
  const tests = [];
1991
2103
  for (const encryptionScheme of testEncryptionSchemes) {
1992
2104
  for (const keySystem of testKeySystems) {
1993
- // Our Polyfill will reject anything apart com.apple.fps key systems.
1994
- // It seems the Safari modern EME API will allow to request a
1995
- // MediaKeySystemAccess for the ClearKey CDM, create and update a key
1996
- // session but playback will never start
1997
- // Safari bug: https://bugs.webkit.org/show_bug.cgi?id=231006
1998
- if (keySystem === 'org.w3.clearkey' &&
1999
- shaka.util.Platform.isSafari()) {
2105
+ if (!checkKeySystem(keySystem)) {
2000
2106
  continue;
2001
2107
  }
2002
2108
  tests.push(testSystemEme(keySystem, encryptionScheme, '', ''));
@@ -2006,6 +2112,9 @@ shaka.media.DrmEngine = class {
2006
2112
 
2007
2113
  for (const keySystem of testKeySystems) {
2008
2114
  for (const robustness of (testRobustness[keySystem] || [])) {
2115
+ if (!checkKeySystem(keySystem)) {
2116
+ continue;
2117
+ }
2009
2118
  tests.push(testSystemEme(keySystem, null, robustness, ''));
2010
2119
  tests.push(testSystemEme(keySystem, null, '', robustness));
2011
2120
  tests.push(testSystemMcap(keySystem, null, robustness, ''));
@@ -2039,8 +2148,8 @@ shaka.media.DrmEngine = class {
2039
2148
  async closeSession_(session) {
2040
2149
  try {
2041
2150
  await shaka.util.Functional.promiseWithTimeout(
2042
- shaka.media.DrmEngine.CLOSE_TIMEOUT_,
2043
- Promise.all([session.close(), session.closed]));
2151
+ shaka.drm.DrmEngine.CLOSE_TIMEOUT_,
2152
+ Promise.all([session.close().catch(() => {}), session.closed]));
2044
2153
  } catch (e) {
2045
2154
  shaka.log.warning('Timeout waiting for session close');
2046
2155
  }
@@ -2085,7 +2194,7 @@ shaka.media.DrmEngine = class {
2085
2194
  /**
2086
2195
  * Concat the audio and video drmInfos in a variant.
2087
2196
  * @param {shaka.extern.Variant} variant
2088
- * @return {!Array.<!shaka.extern.DrmInfo>}
2197
+ * @return {!Array<!shaka.extern.DrmInfo>}
2089
2198
  * @private
2090
2199
  */
2091
2200
  getVariantDrmInfos_(variant) {
@@ -2147,8 +2256,8 @@ shaka.media.DrmEngine = class {
2147
2256
  * Replace the drm info used in each variant in |variants| to reflect each
2148
2257
  * key service in |keySystems|.
2149
2258
  *
2150
- * @param {!Array.<shaka.extern.Variant>} variants
2151
- * @param {!Map.<string, string>} keySystems
2259
+ * @param {!Array<shaka.extern.Variant>} variants
2260
+ * @param {!Map<string, string>} keySystems
2152
2261
  * @private
2153
2262
  */
2154
2263
  static replaceDrmInfo_(variants, keySystems) {
@@ -2185,34 +2294,34 @@ shaka.media.DrmEngine = class {
2185
2294
  * engine.
2186
2295
  *
2187
2296
  * @param {string} keySystem
2188
- * @param {!Array.<shaka.extern.DrmInfo>} drmInfos
2297
+ * @param {!Array<shaka.extern.DrmInfo>} drmInfos
2189
2298
  * @return {shaka.extern.DrmInfo}
2190
2299
  *
2191
2300
  * @private
2192
2301
  */
2193
2302
  createDrmInfoByInfos_(keySystem, drmInfos) {
2194
- /** @type {!Array.<string>} */
2303
+ /** @type {!Array<string>} */
2195
2304
  const encryptionSchemes = [];
2196
2305
 
2197
- /** @type {!Array.<string>} */
2306
+ /** @type {!Array<string>} */
2198
2307
  const licenseServers = [];
2199
2308
 
2200
- /** @type {!Array.<string>} */
2309
+ /** @type {!Array<string>} */
2201
2310
  const serverCertificateUris = [];
2202
2311
 
2203
- /** @type {!Array.<!Uint8Array>} */
2312
+ /** @type {!Array<!Uint8Array>} */
2204
2313
  const serverCerts = [];
2205
2314
 
2206
- /** @type {!Array.<!shaka.extern.InitDataOverride>} */
2315
+ /** @type {!Array<!shaka.extern.InitDataOverride>} */
2207
2316
  const initDatas = [];
2208
2317
 
2209
- /** @type {!Set.<string>} */
2318
+ /** @type {!Set<string>} */
2210
2319
  const keyIds = new Set();
2211
2320
 
2212
- /** @type {!Set.<string>} */
2321
+ /** @type {!Set<string>} */
2213
2322
  const keySystemUris = new Set();
2214
2323
 
2215
- shaka.media.DrmEngine.processDrmInfos_(
2324
+ shaka.drm.DrmEngine.processDrmInfos_(
2216
2325
  drmInfos, encryptionSchemes, licenseServers, serverCerts,
2217
2326
  serverCertificateUris, initDatas, keyIds, keySystemUris);
2218
2327
 
@@ -2283,26 +2392,26 @@ shaka.media.DrmEngine = class {
2283
2392
  * @private
2284
2393
  */
2285
2394
  static createDrmInfoByConfigs_(keySystem, config) {
2286
- /** @type {!Array.<string>} */
2395
+ /** @type {!Array<string>} */
2287
2396
  const encryptionSchemes = [];
2288
2397
 
2289
- /** @type {!Array.<string>} */
2398
+ /** @type {!Array<string>} */
2290
2399
  const licenseServers = [];
2291
2400
 
2292
- /** @type {!Array.<string>} */
2401
+ /** @type {!Array<string>} */
2293
2402
  const serverCertificateUris = [];
2294
2403
 
2295
- /** @type {!Array.<!Uint8Array>} */
2404
+ /** @type {!Array<!Uint8Array>} */
2296
2405
  const serverCerts = [];
2297
2406
 
2298
- /** @type {!Array.<!shaka.extern.InitDataOverride>} */
2407
+ /** @type {!Array<!shaka.extern.InitDataOverride>} */
2299
2408
  const initDatas = [];
2300
2409
 
2301
- /** @type {!Set.<string>} */
2410
+ /** @type {!Set<string>} */
2302
2411
  const keyIds = new Set();
2303
2412
 
2304
2413
  // TODO: refactor, don't stick drmInfos onto MediaKeySystemConfiguration
2305
- shaka.media.DrmEngine.processDrmInfos_(
2414
+ shaka.drm.DrmEngine.processDrmInfos_(
2306
2415
  config['drmInfos'], encryptionSchemes, licenseServers, serverCerts,
2307
2416
  serverCertificateUris, initDatas, keyIds);
2308
2417
 
@@ -2353,21 +2462,23 @@ shaka.media.DrmEngine = class {
2353
2462
  * Extract license server, server cert, and init data from |drmInfos|, taking
2354
2463
  * care to eliminate duplicates.
2355
2464
  *
2356
- * @param {!Array.<shaka.extern.DrmInfo>} drmInfos
2357
- * @param {!Array.<string>} licenseServers
2358
- * @param {!Array.<string>} encryptionSchemes
2359
- * @param {!Array.<!Uint8Array>} serverCerts
2360
- * @param {!Array.<string>} serverCertificateUris
2361
- * @param {!Array.<!shaka.extern.InitDataOverride>} initDatas
2362
- * @param {!Set.<string>} keyIds
2363
- * @param {!Set.<string>} [keySystemUris]
2465
+ * @param {!Array<shaka.extern.DrmInfo>} drmInfos
2466
+ * @param {!Array<string>} encryptionSchemes
2467
+ * @param {!Array<string>} licenseServers
2468
+ * @param {!Array<!Uint8Array>} serverCerts
2469
+ * @param {!Array<string>} serverCertificateUris
2470
+ * @param {!Array<!shaka.extern.InitDataOverride>} initDatas
2471
+ * @param {!Set<string>} keyIds
2472
+ * @param {!Set<string>} [keySystemUris]
2364
2473
  * @private
2365
2474
  */
2366
2475
  static processDrmInfos_(
2367
2476
  drmInfos, encryptionSchemes, licenseServers, serverCerts,
2368
2477
  serverCertificateUris, initDatas, keyIds, keySystemUris) {
2369
- /** @type {function(shaka.extern.InitDataOverride,
2370
- * shaka.extern.InitDataOverride):boolean} */
2478
+ /**
2479
+ * @type {function(shaka.extern.InitDataOverride,
2480
+ * shaka.extern.InitDataOverride):boolean}
2481
+ */
2371
2482
  const initDataOverrideEqual = (a, b) => {
2372
2483
  if (a.keyId && a.keyId == b.keyId) {
2373
2484
  // Two initDatas with the same keyId are considered to be the same,
@@ -2461,10 +2572,10 @@ shaka.media.DrmEngine = class {
2461
2572
  * required information. Also applies the key systems mapping.
2462
2573
  *
2463
2574
  * @param {shaka.extern.DrmInfo} drmInfo
2464
- * @param {!Map.<string, string>} servers
2465
- * @param {!Map.<string, shaka.extern.AdvancedDrmConfiguration>}
2466
- * advancedConfigs
2467
- * @param {!Object.<string, string>} keySystemsMapping
2575
+ * @param {!Map<string, string>} servers
2576
+ * @param {!Map<string,
2577
+ * shaka.extern.AdvancedDrmConfiguration>} advancedConfigs
2578
+ * @param {!Object<string, string>} keySystemsMapping
2468
2579
  * @private
2469
2580
  */
2470
2581
  static fillInDrmInfoDefaults_(drmInfo, servers, advancedConfigs,
@@ -2522,13 +2633,8 @@ shaka.media.DrmEngine = class {
2522
2633
  advancedConfig.persistentStateRequired;
2523
2634
  }
2524
2635
 
2525
- if (!drmInfo.videoRobustness) {
2526
- drmInfo.videoRobustness = advancedConfig.videoRobustness;
2527
- }
2528
-
2529
- if (!drmInfo.audioRobustness) {
2530
- drmInfo.audioRobustness = advancedConfig.audioRobustness;
2531
- }
2636
+ // robustness will be filled in with defaults, if needed, in
2637
+ // expandRobustness
2532
2638
 
2533
2639
  if (!drmInfo.serverCertificate) {
2534
2640
  drmInfo.serverCertificate = advancedConfig.serverCertificate;
@@ -2597,6 +2703,31 @@ shaka.media.DrmEngine = class {
2597
2703
  this.newInitData('cenc', combinedData);
2598
2704
  return this.allSessionsLoaded_;
2599
2705
  }
2706
+
2707
+ /**
2708
+ * Create a DrmInfo using configured clear keys and assign it to each variant.
2709
+ * Only modify variants if clear keys have been set.
2710
+ * @see https://bit.ly/2K8gOnv for the spec on the clearkey license format.
2711
+ *
2712
+ * @param {!Object<string, string>} configClearKeys
2713
+ * @param {!Array<shaka.extern.Variant>} variants
2714
+ */
2715
+ static configureClearKey(configClearKeys, variants) {
2716
+ const clearKeys = shaka.util.MapUtils.asMap(configClearKeys);
2717
+ if (clearKeys.size == 0) {
2718
+ return;
2719
+ }
2720
+ const clearKeyDrmInfo =
2721
+ shaka.util.ManifestParserUtils.createDrmInfoFromClearKeys(clearKeys);
2722
+ for (const variant of variants) {
2723
+ if (variant.video) {
2724
+ variant.video.drmInfos = [clearKeyDrmInfo];
2725
+ }
2726
+ if (variant.audio) {
2727
+ variant.audio.drmInfos = [clearKeyDrmInfo];
2728
+ }
2729
+ }
2730
+ }
2600
2731
  };
2601
2732
 
2602
2733
 
@@ -2630,14 +2761,14 @@ shaka.media.DrmEngine = class {
2630
2761
  * call. This is used to track the 'license-release' message when calling
2631
2762
  * remove().
2632
2763
  */
2633
- shaka.media.DrmEngine.SessionMetaData;
2764
+ shaka.drm.DrmEngine.SessionMetaData;
2634
2765
 
2635
2766
 
2636
2767
  /**
2637
2768
  * @typedef {{
2638
2769
  * netEngine: !shaka.net.NetworkingEngine,
2639
2770
  * onError: function(!shaka.util.Error),
2640
- * onKeyStatus: function(!Object.<string,string>),
2771
+ * onKeyStatus: function(!Object<string,string>),
2641
2772
  * onExpirationUpdated: function(string,number),
2642
2773
  * onEvent: function(!Event)
2643
2774
  * }}
@@ -2648,7 +2779,7 @@ shaka.media.DrmEngine.SessionMetaData;
2648
2779
  * Called when an error occurs. If the error is recoverable (see
2649
2780
  * {@link shaka.util.Error}) then the caller may invoke either
2650
2781
  * StreamingEngine.switch*() or StreamingEngine.seeked() to attempt recovery.
2651
- * @property {function(!Object.<string,string>)} onKeyStatus
2782
+ * @property {function(!Object<string,string>)} onKeyStatus
2652
2783
  * Called when key status changes. The argument is a map of hex key IDs to
2653
2784
  * statuses.
2654
2785
  * @property {function(string,number)} onExpirationUpdated
@@ -2656,29 +2787,29 @@ shaka.media.DrmEngine.SessionMetaData;
2656
2787
  * @property {function(!Event)} onEvent
2657
2788
  * Called when an event occurs that should be sent to the app.
2658
2789
  */
2659
- shaka.media.DrmEngine.PlayerInterface;
2790
+ shaka.drm.DrmEngine.PlayerInterface;
2660
2791
 
2661
2792
  /**
2662
2793
  * @typedef {{
2663
- * kids: !Array.<string>,
2794
+ * kids: !Array<string>,
2664
2795
  * type: string
2665
2796
  * }}
2666
2797
  *
2667
- * @property {!Array.<string>} kids
2798
+ * @property {!Array<string>} kids
2668
2799
  * An array of key IDs. Each element of the array is the base64url encoding of
2669
2800
  * the octet sequence containing the key ID value.
2670
2801
  * @property {string} type
2671
2802
  * The requested MediaKeySessionType.
2672
2803
  * @see https://www.w3.org/TR/encrypted-media/#clear-key-request-format
2673
2804
  */
2674
- shaka.media.DrmEngine.ClearKeyLicenceRequestFormat;
2805
+ shaka.drm.DrmEngine.ClearKeyLicenceRequestFormat;
2675
2806
 
2676
2807
  /**
2677
2808
  * The amount of time, in seconds, we wait to consider a session closed.
2678
2809
  * This allows us to work around Chrome bug https://crbug.com/1108158.
2679
2810
  * @private {number}
2680
2811
  */
2681
- shaka.media.DrmEngine.CLOSE_TIMEOUT_ = 1;
2812
+ shaka.drm.DrmEngine.CLOSE_TIMEOUT_ = 1;
2682
2813
 
2683
2814
 
2684
2815
  /**
@@ -2687,7 +2818,7 @@ shaka.media.DrmEngine.CLOSE_TIMEOUT_ = 1;
2687
2818
  * without key statuses.
2688
2819
  * @private {number}
2689
2820
  */
2690
- shaka.media.DrmEngine.SESSION_LOAD_TIMEOUT_ = 5;
2821
+ shaka.drm.DrmEngine.SESSION_LOAD_TIMEOUT_ = 5;
2691
2822
 
2692
2823
 
2693
2824
  /**
@@ -2695,4 +2826,4 @@ shaka.media.DrmEngine.SESSION_LOAD_TIMEOUT_ = 5;
2695
2826
  * This allows us to avoid multiple expiration events in most cases.
2696
2827
  * @type {number}
2697
2828
  */
2698
- shaka.media.DrmEngine.KEY_STATUS_BATCH_TIME = 0.5;
2829
+ shaka.drm.DrmEngine.KEY_STATUS_BATCH_TIME = 0.5;