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.
- package/AUTHORS +1 -0
- package/CONTRIBUTORS +4 -0
- package/README.md +22 -21
- package/cspell.config.yaml +18 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +29 -24
- package/dist/locales.js +33 -33
- package/dist/shaka-player.compiled.d.ts +138 -36
- package/dist/shaka-player.compiled.debug.d.ts +138 -36
- package/dist/shaka-player.compiled.debug.externs.js +367 -107
- package/dist/shaka-player.compiled.debug.js +828 -765
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +367 -107
- package/dist/shaka-player.compiled.js +1451 -1416
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +172 -38
- package/dist/shaka-player.ui.debug.d.ts +172 -38
- package/dist/shaka-player.ui.debug.externs.js +406 -113
- package/dist/shaka-player.ui.debug.js +842 -766
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +406 -113
- package/dist/shaka-player.ui.js +1670 -1628
- package/dist/shaka-player.ui.map +4 -4
- package/eslint.config.mjs +343 -0
- package/externs/airplay.js +1 -1
- package/externs/audiotrack.js +1 -1
- package/externs/awesomplete.js +1 -1
- package/externs/cast-sdk-v2.js +2 -2
- package/externs/cmcd.js +16 -1
- package/externs/device_sensor_event.js +1 -1
- package/externs/ima.js +8 -8
- package/externs/isoboxer.js +31 -31
- package/externs/jwk_set.js +1 -1
- package/externs/lcevc.js +8 -8
- package/externs/mediakeys.js +1 -1
- package/externs/mediasession.js +3 -2
- package/externs/mediatailor.js +18 -18
- package/externs/pictureinpicture.js +41 -1
- package/externs/playstation.js +2 -2
- package/externs/prefixed_eme.js +1 -1
- package/externs/shaka/abortable.js +4 -4
- package/externs/shaka/abr_manager.js +1 -1
- package/externs/shaka/ads.js +45 -6
- package/externs/shaka/cea.js +2 -2
- package/externs/shaka/codecs.js +4 -4
- package/externs/shaka/drm_info.js +6 -6
- package/externs/shaka/error.js +5 -5
- package/externs/shaka/manifest.js +51 -56
- package/externs/shaka/manifest_parser.js +3 -9
- package/externs/shaka/net.js +23 -20
- package/externs/shaka/offline.js +37 -37
- package/externs/shaka/offline_compat_v1.js +10 -10
- package/externs/shaka/offline_compat_v2.js +10 -10
- package/externs/shaka/player.js +139 -109
- package/externs/shaka/text.js +10 -3
- package/externs/shaka/transmuxer.js +1 -1
- package/externs/videotrack.js +1 -1
- package/lib/abr/ewma.js +1 -1
- package/lib/abr/simple_abr_manager.js +70 -22
- package/lib/ads/ad_manager.js +43 -18
- package/lib/ads/ad_utils.js +160 -58
- package/lib/ads/ads_stats.js +1 -1
- package/lib/ads/client_side_ad_manager.js +2 -2
- package/lib/ads/interstitial_ad.js +16 -11
- package/lib/ads/interstitial_ad_manager.js +419 -72
- package/lib/ads/interstitial_static_ad.js +299 -0
- package/lib/ads/media_tailor_ad.js +1 -0
- package/lib/ads/media_tailor_ad_manager.js +37 -36
- package/lib/ads/server_side_ad_manager.js +7 -6
- package/lib/cast/cast_receiver.js +5 -3
- package/lib/cast/cast_sender.js +2 -2
- package/lib/cast/cast_utils.js +20 -13
- package/lib/cea/cea608_data_channel.js +53 -53
- package/lib/cea/cea708_service.js +42 -40
- package/lib/cea/cea708_window.js +5 -2
- package/lib/cea/cea_decoder.js +5 -7
- package/lib/cea/mp4_cea_parser.js +1 -1
- package/lib/cea/sei_processor.js +1 -1
- package/lib/dash/content_protection.js +62 -192
- package/lib/dash/dash_parser.js +119 -119
- package/lib/dash/mpd_utils.js +14 -13
- package/lib/dash/segment_base.js +5 -5
- package/lib/dash/segment_list.js +10 -10
- package/lib/dash/segment_template.js +55 -53
- package/lib/debug/log.js +2 -2
- package/lib/dependencies/all.js +2 -1
- package/lib/{media → drm}/drm_engine.js +274 -143
- package/lib/{util → drm}/drm_utils.js +20 -11
- package/lib/drm/playready.js +233 -0
- package/lib/hls/hls_classes.js +14 -14
- package/lib/hls/hls_parser.js +257 -196
- package/lib/hls/hls_utils.js +14 -14
- package/lib/hls/manifest_text_parser.js +10 -10
- package/lib/media/adaptation_set.js +6 -5
- package/lib/media/adaptation_set_criteria.js +51 -379
- package/lib/media/buffering_observer.js +5 -4
- package/lib/media/closed_caption_parser.js +2 -2
- package/lib/media/content_workarounds.js +2 -2
- package/lib/media/example_based_criteria.js +69 -0
- package/lib/media/gap_jumping_controller.js +14 -1
- package/lib/media/manifest_filterer.js +8 -8
- package/lib/media/manifest_parser.js +2 -2
- package/lib/media/media_source_capabilities.js +20 -1
- package/lib/media/media_source_engine.js +84 -35
- package/lib/media/mp4_segment_index_parser.js +5 -5
- package/lib/media/playhead.js +2 -8
- package/lib/media/playhead_observer.js +1 -1
- package/lib/media/preference_based_criteria.js +333 -0
- package/lib/media/preload_manager.js +53 -37
- package/lib/media/presentation_timeline.js +2 -2
- package/lib/media/quality_observer.js +35 -35
- package/lib/media/region_observer.js +2 -2
- package/lib/media/region_timeline.js +3 -3
- package/lib/media/segment_index.js +14 -14
- package/lib/media/segment_prefetch.js +17 -13
- package/lib/media/segment_reference.js +7 -7
- package/lib/media/segment_utils.js +9 -9
- package/lib/media/streaming_engine.js +77 -38
- package/lib/media/time_ranges_utils.js +1 -1
- package/lib/media/video_wrapper.js +1 -1
- package/lib/media/webm_segment_index_parser.js +4 -4
- package/lib/mss/content_protection.js +17 -222
- package/lib/mss/mss_parser.js +23 -24
- package/lib/net/data_uri_plugin.js +1 -0
- package/lib/net/http_fetch_plugin.js +8 -7
- package/lib/net/http_plugin_utils.js +5 -2
- package/lib/net/http_xhr_plugin.js +4 -3
- package/lib/net/networking_engine.js +72 -17
- package/lib/net/networking_utils.js +5 -2
- package/lib/offline/download_info.js +5 -1
- package/lib/offline/download_manager.js +15 -4
- package/lib/offline/download_progress_estimator.js +1 -1
- package/lib/offline/indexeddb/base_storage_cell.js +9 -9
- package/lib/offline/indexeddb/db_connection.js +1 -1
- package/lib/offline/indexeddb/db_operation.js +2 -2
- package/lib/offline/indexeddb/eme_session_storage_cell.js +1 -1
- package/lib/offline/indexeddb/storage_mechanism.js +1 -1
- package/lib/offline/indexeddb/v1_storage_cell.js +3 -3
- package/lib/offline/indexeddb/v2_storage_cell.js +2 -2
- package/lib/offline/manifest_converter.js +11 -12
- package/lib/offline/offline_scheme.js +8 -4
- package/lib/offline/session_deleter.js +11 -11
- package/lib/offline/storage.js +137 -88
- package/lib/offline/storage_muxer.js +8 -8
- package/lib/offline/stored_content_utils.js +3 -3
- package/lib/offline/stream_bandwidth_estimator.js +1 -1
- package/lib/player.js +291 -207
- package/lib/polyfill/all.js +1 -1
- package/lib/polyfill/media_capabilities.js +5 -5
- package/lib/polyfill/patchedmediakeys_apple.js +6 -6
- package/lib/polyfill/patchedmediakeys_webkit.js +8 -8
- package/lib/polyfill/video_play_promise.js +0 -1
- package/lib/text/cue.js +3 -2
- package/lib/text/lrc_text_parser.js +1 -1
- package/lib/text/mp4_ttml_parser.js +1 -1
- package/lib/text/mp4_vtt_parser.js +3 -3
- package/lib/text/sbv_text_parser.js +1 -1
- package/lib/text/simple_text_displayer.js +37 -10
- package/lib/text/ssa_text_parser.js +3 -1
- package/lib/text/stub_text_displayer.js +12 -5
- package/lib/text/text_engine.js +5 -4
- package/lib/text/text_utils.js +4 -4
- package/lib/text/ttml_text_parser.js +21 -20
- package/lib/text/ui_text_displayer.js +20 -13
- package/lib/text/vtt_text_parser.js +10 -10
- package/lib/text/web_vtt_generator.js +2 -2
- package/lib/transmuxer/aac_transmuxer.js +2 -2
- package/lib/transmuxer/ac3_transmuxer.js +2 -2
- package/lib/transmuxer/adts.js +2 -0
- package/lib/transmuxer/ec3.js +3 -3
- package/lib/transmuxer/ec3_transmuxer.js +2 -2
- package/lib/transmuxer/h264.js +5 -5
- package/lib/transmuxer/h265.js +3 -3
- package/lib/transmuxer/mp3_transmuxer.js +2 -2
- package/lib/transmuxer/mpeg_audio.js +6 -6
- package/lib/transmuxer/mss_transmuxer.js +2 -0
- package/lib/transmuxer/transmuxer_engine.js +1 -1
- package/lib/transmuxer/ts_transmuxer.js +10 -10
- package/lib/util/abortable_operation.js +10 -10
- package/lib/util/array_utils.js +6 -6
- package/lib/util/cmcd_manager.js +149 -18
- package/lib/util/cmsd_manager.js +11 -11
- package/lib/util/config_utils.js +3 -3
- package/lib/util/content_steering_manager.js +17 -17
- package/lib/util/data_view_reader.js +3 -3
- package/lib/util/ebml_parser.js +1 -1
- package/lib/util/error.js +11 -6
- package/lib/util/event_manager.js +1 -1
- package/lib/util/exp_golomb.js +1 -1
- package/lib/util/fairplay_utils.js +6 -1
- package/lib/util/fake_event.js +3 -2
- package/lib/util/fake_event_target.js +1 -1
- package/lib/util/functional.js +8 -8
- package/lib/util/id3_utils.js +1 -1
- package/lib/util/iterables.js +6 -6
- package/lib/util/language_utils.js +17 -17
- package/lib/util/manifest_parser_utils.js +13 -13
- package/lib/util/map_utils.js +6 -6
- package/lib/util/media_ready_state_utils.js +1 -1
- package/lib/util/mime_utils.js +15 -4
- package/lib/util/mp4_box_parsers.js +5 -5
- package/lib/util/mp4_generator.js +31 -30
- package/lib/util/mp4_parser.js +2 -2
- package/lib/util/multi_map.js +5 -5
- package/lib/util/mutex.js +1 -1
- package/lib/util/networking.js +1 -1
- package/lib/util/object_utils.js +5 -1
- package/lib/util/operation_manager.js +1 -1
- package/lib/util/periods.js +24 -24
- package/lib/util/platform.js +8 -4
- package/lib/util/player_configuration.js +50 -17
- package/lib/util/pssh.js +34 -6
- package/lib/util/public_promise.js +2 -2
- package/lib/util/state_history.js +2 -2
- package/lib/util/stream_utils.js +138 -120
- package/lib/util/string_utils.js +4 -3
- package/lib/util/switch_history.js +2 -2
- package/lib/util/tXml.js +22 -17
- package/lib/util/text_parser.js +2 -2
- package/lib/util/timer.js +1 -1
- package/lib/util/ts_parser.js +22 -22
- package/lib/util/xml_utils.js +1 -0
- package/package.json +7 -4
- package/project-words.txt +485 -0
- package/shaka-player.uncompiled.js +1 -1
- package/third_party/closure-uri/uri.js +2 -2
- package/third_party/closure-uri/utils.js +2 -2
- package/third_party/language-mapping-list/language-mapping-list.js +1 -1
- package/ui/ad_statistics_button.js +9 -5
- package/ui/airplay_button.js +1 -0
- package/ui/audio_language_selection.js +2 -1
- package/ui/context_menu.js +2 -2
- package/ui/controls.js +7 -7
- package/ui/externs/ui.js +29 -21
- package/ui/externs/watermark.js +64 -0
- package/ui/fast_forward_button.js +1 -1
- package/ui/gl_matrix/matrix_4x4.js +11 -5
- package/ui/hidden_fast_forward_button.js +1 -1
- package/ui/hidden_seek_button.js +1 -1
- package/ui/language_utils.js +27 -26
- package/ui/less/buttons.less +2 -2
- package/ui/localization.js +21 -21
- package/ui/loop_button.js +2 -2
- package/ui/overflow_menu.js +2 -2
- package/ui/playback_rate_selection.js +1 -1
- package/ui/presentation_time.js +4 -1
- package/ui/range_element.js +2 -2
- package/ui/resolution_selection.js +42 -6
- package/ui/rewind_button.js +1 -1
- package/ui/seek_bar.js +5 -5
- package/ui/statistics_button.js +8 -4
- package/ui/text_selection.js +3 -2
- package/ui/ui.js +32 -2
- package/ui/vr_manager.js +3 -3
- package/ui/vr_utils.js +14 -14
- package/ui/vr_webgl.js +5 -5
- package/ui/watermark.js +313 -0
- package/.eslintignore +0 -4
- package/.eslintrc.js +0 -310
- 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.
|
|
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.
|
|
36
|
+
shaka.drm.DrmEngine = class {
|
|
37
37
|
/**
|
|
38
|
-
* @param {shaka.
|
|
38
|
+
* @param {shaka.drm.DrmEngine.PlayerInterface} playerInterface
|
|
39
39
|
*/
|
|
40
40
|
constructor(playerInterface) {
|
|
41
|
-
/** @private {?shaka.
|
|
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
|
|
67
|
-
* shaka.
|
|
66
|
+
* @private {!Map<MediaKeySession,
|
|
67
|
+
* shaka.drm.DrmEngine.SessionMetaData>}
|
|
68
68
|
*/
|
|
69
69
|
this.activeSessions_ = new Map();
|
|
70
70
|
|
|
71
|
-
/** @private {!Array
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
273
|
+
* @param {!Array<shaka.extern.Variant>} variants
|
|
274
274
|
* The variants that we want to support playing.
|
|
275
|
-
* @param {!Array
|
|
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
|
|
306
|
-
* @param {!Array
|
|
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
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
1005
|
-
* @param {!Map
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
2002
|
+
const TIMEOUT_FOR_CHECK_ACCESS_IN_SECONDS = 1;
|
|
1927
2003
|
const access =
|
|
1928
2004
|
await shaka.util.Functional.promiseWithTimeout(
|
|
1929
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
|
2151
|
-
* @param {!Map
|
|
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
|
|
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
|
|
2303
|
+
/** @type {!Array<string>} */
|
|
2195
2304
|
const encryptionSchemes = [];
|
|
2196
2305
|
|
|
2197
|
-
/** @type {!Array
|
|
2306
|
+
/** @type {!Array<string>} */
|
|
2198
2307
|
const licenseServers = [];
|
|
2199
2308
|
|
|
2200
|
-
/** @type {!Array
|
|
2309
|
+
/** @type {!Array<string>} */
|
|
2201
2310
|
const serverCertificateUris = [];
|
|
2202
2311
|
|
|
2203
|
-
/** @type {!Array
|
|
2312
|
+
/** @type {!Array<!Uint8Array>} */
|
|
2204
2313
|
const serverCerts = [];
|
|
2205
2314
|
|
|
2206
|
-
/** @type {!Array
|
|
2315
|
+
/** @type {!Array<!shaka.extern.InitDataOverride>} */
|
|
2207
2316
|
const initDatas = [];
|
|
2208
2317
|
|
|
2209
|
-
/** @type {!Set
|
|
2318
|
+
/** @type {!Set<string>} */
|
|
2210
2319
|
const keyIds = new Set();
|
|
2211
2320
|
|
|
2212
|
-
/** @type {!Set
|
|
2321
|
+
/** @type {!Set<string>} */
|
|
2213
2322
|
const keySystemUris = new Set();
|
|
2214
2323
|
|
|
2215
|
-
shaka.
|
|
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
|
|
2395
|
+
/** @type {!Array<string>} */
|
|
2287
2396
|
const encryptionSchemes = [];
|
|
2288
2397
|
|
|
2289
|
-
/** @type {!Array
|
|
2398
|
+
/** @type {!Array<string>} */
|
|
2290
2399
|
const licenseServers = [];
|
|
2291
2400
|
|
|
2292
|
-
/** @type {!Array
|
|
2401
|
+
/** @type {!Array<string>} */
|
|
2293
2402
|
const serverCertificateUris = [];
|
|
2294
2403
|
|
|
2295
|
-
/** @type {!Array
|
|
2404
|
+
/** @type {!Array<!Uint8Array>} */
|
|
2296
2405
|
const serverCerts = [];
|
|
2297
2406
|
|
|
2298
|
-
/** @type {!Array
|
|
2407
|
+
/** @type {!Array<!shaka.extern.InitDataOverride>} */
|
|
2299
2408
|
const initDatas = [];
|
|
2300
2409
|
|
|
2301
|
-
/** @type {!Set
|
|
2410
|
+
/** @type {!Set<string>} */
|
|
2302
2411
|
const keyIds = new Set();
|
|
2303
2412
|
|
|
2304
2413
|
// TODO: refactor, don't stick drmInfos onto MediaKeySystemConfiguration
|
|
2305
|
-
shaka.
|
|
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
|
|
2357
|
-
* @param {!Array
|
|
2358
|
-
* @param {!Array
|
|
2359
|
-
* @param {!Array
|
|
2360
|
-
* @param {!Array
|
|
2361
|
-
* @param {!Array
|
|
2362
|
-
* @param {!Set
|
|
2363
|
-
* @param {!Set
|
|
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
|
-
/**
|
|
2370
|
-
*
|
|
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
|
|
2465
|
-
* @param {!Map
|
|
2466
|
-
*
|
|
2467
|
-
* @param {!Object
|
|
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
|
|
2526
|
-
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
2790
|
+
shaka.drm.DrmEngine.PlayerInterface;
|
|
2660
2791
|
|
|
2661
2792
|
/**
|
|
2662
2793
|
* @typedef {{
|
|
2663
|
-
* kids: !Array
|
|
2794
|
+
* kids: !Array<string>,
|
|
2664
2795
|
* type: string
|
|
2665
2796
|
* }}
|
|
2666
2797
|
*
|
|
2667
|
-
* @property {!Array
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
2829
|
+
shaka.drm.DrmEngine.KEY_STATUS_BATCH_TIME = 0.5;
|