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