shaka-player 3.1.5 → 3.2.3
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/CHANGELOG.md +129 -6
- package/README.md +4 -4
- package/build/types/polyfill +1 -0
- package/demo/common/asset.js +9 -7
- package/demo/common/assets.js +10 -1
- 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/demo.compiled.debug.js +14 -14
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +14 -14
- package/dist/demo.compiled.map +2 -2
- package/dist/deps.js +21 -20
- package/dist/locales.js +30 -30
- package/dist/receiver.compiled.debug.js +8 -8
- package/dist/receiver.compiled.debug.map +2 -2
- package/dist/receiver.compiled.js +8 -8
- package/dist/receiver.compiled.map +2 -2
- package/dist/shaka-player.compiled.d.ts +63 -10
- package/dist/shaka-player.compiled.debug.d.ts +63 -10
- package/dist/shaka-player.compiled.debug.externs.js +786 -716
- package/dist/shaka-player.compiled.debug.js +563 -534
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +786 -716
- package/dist/shaka-player.compiled.js +820 -809
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +63 -10
- package/dist/shaka-player.ui.debug.d.ts +63 -10
- package/dist/shaka-player.ui.debug.externs.js +542 -472
- package/dist/shaka-player.ui.debug.js +594 -566
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +542 -472
- package/dist/shaka-player.ui.js +938 -927
- package/dist/shaka-player.ui.map +4 -4
- 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 +61 -9
- package/externs/shaka/text.js +10 -10
- package/externs/texttrack.js +3 -0
- package/lib/ads/ad_manager.js +16 -15
- package/lib/ads/client_side_ad_manager.js +6 -2
- package/lib/ads/server_side_ad_manager.js +19 -2
- package/lib/cast/cast_proxy.js +8 -0
- 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 +5 -0
- package/lib/hls/hls_parser.js +159 -12
- package/lib/media/closed_caption_parser.js +1 -2
- package/lib/media/drm_engine.js +162 -192
- package/lib/media/segment_index.js +4 -1
- package/lib/media/segment_reference.js +37 -2
- package/lib/media/streaming_engine.js +6 -6
- package/lib/net/networking_engine.js +1 -0
- 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 +426 -149
- package/lib/polyfill/aria.js +82 -0
- package/lib/routing/walker.js +2 -3
- package/lib/text/srt_text_parser.js +4 -4
- package/lib/text/text_engine.js +2 -2
- 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/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/player_configuration.js +13 -1
- package/lib/util/stream_utils.js +168 -88
- 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_utils_unit.js +1 -0
- 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 +43 -1
- package/test/hls/hls_parser_unit.js +250 -0
- package/test/media/drm_engine_integration.js +86 -12
- package/test/media/drm_engine_unit.js +310 -450
- package/test/offline/manifest_convert_unit.js +2 -0
- package/test/offline/storage_integration.js +9 -19
- package/test/player_integration.js +85 -0
- package/test/player_src_equals_integration.js +85 -0
- package/test/player_unit.js +25 -37
- package/test/test/assets/chapters.srt +11 -0
- package/test/test/assets/chapters.vtt +10 -0
- package/test/test/assets/chapters2.vtt +10 -0
- package/test/test/util/cea_utils.js +12 -12
- package/test/test/util/fake_ad_manager.js +7 -0
- package/test/test/util/manifest_generator.js +2 -0
- package/test/test/util/manifest_parser_util.js +3 -1
- package/test/text/web_vtt_generator_unit.js +81 -7
- package/test/util/stream_utils_unit.js +118 -10
- package/ui/airplay_button.js +1 -1
- package/ui/audio_language_selection.js +2 -5
- package/ui/cast_button.js +4 -6
- package/ui/constants.js +0 -3
- package/ui/fast_forward_button.js +2 -3
- package/ui/fullscreen_button.js +1 -3
- package/ui/language_utils.js +1 -1
- 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 +5 -7
- 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
|
|
|
@@ -1912,6 +1848,8 @@ shaka.media.DrmEngine = class {
|
|
|
1912
1848
|
videoRobustness: drm1.videoRobustness || drm2.videoRobustness,
|
|
1913
1849
|
audioRobustness: drm1.audioRobustness || drm2.audioRobustness,
|
|
1914
1850
|
serverCertificate: drm1.serverCertificate || drm2.serverCertificate,
|
|
1851
|
+
serverCertificateUri: drm1.serverCertificateUri ||
|
|
1852
|
+
drm2.serverCertificateUri,
|
|
1915
1853
|
initData,
|
|
1916
1854
|
keyIds,
|
|
1917
1855
|
};
|
|
@@ -1986,6 +1924,7 @@ shaka.media.DrmEngine = class {
|
|
|
1986
1924
|
audioRobustness: '',
|
|
1987
1925
|
videoRobustness: '',
|
|
1988
1926
|
serverCertificate: null,
|
|
1927
|
+
serverCertificateUri: '',
|
|
1989
1928
|
initData: [],
|
|
1990
1929
|
keyIds: new Set(),
|
|
1991
1930
|
});
|
|
@@ -2016,6 +1955,9 @@ shaka.media.DrmEngine = class {
|
|
|
2016
1955
|
/** @type {!Array.<string>} */
|
|
2017
1956
|
const licenseServers = [];
|
|
2018
1957
|
|
|
1958
|
+
/** @type {!Array.<string>} */
|
|
1959
|
+
const serverCertificateUris = [];
|
|
1960
|
+
|
|
2019
1961
|
/** @type {!Array.<!Uint8Array>} */
|
|
2020
1962
|
const serverCerts = [];
|
|
2021
1963
|
|
|
@@ -2025,8 +1967,9 @@ shaka.media.DrmEngine = class {
|
|
|
2025
1967
|
/** @type {!Set.<string>} */
|
|
2026
1968
|
const keyIds = new Set();
|
|
2027
1969
|
|
|
2028
|
-
shaka.media.DrmEngine.processDrmInfos_(
|
|
2029
|
-
|
|
1970
|
+
shaka.media.DrmEngine.processDrmInfos_(
|
|
1971
|
+
drmInfos, licenseServers, serverCerts,
|
|
1972
|
+
serverCertificateUris, initDatas, keyIds);
|
|
2030
1973
|
|
|
2031
1974
|
if (serverCerts.length > 1) {
|
|
2032
1975
|
shaka.log.warning('Multiple unique server certificates found! ' +
|
|
@@ -2038,6 +1981,11 @@ shaka.media.DrmEngine = class {
|
|
|
2038
1981
|
'Only the first will be used.');
|
|
2039
1982
|
}
|
|
2040
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
|
+
|
|
2041
1989
|
const defaultSessionType =
|
|
2042
1990
|
this.usePersistentLicenses_ ? 'persistent-license' : 'temporary';
|
|
2043
1991
|
|
|
@@ -2051,6 +1999,7 @@ shaka.media.DrmEngine = class {
|
|
|
2051
1999
|
audioRobustness: drmInfos[0].audioRobustness || '',
|
|
2052
2000
|
videoRobustness: drmInfos[0].videoRobustness || '',
|
|
2053
2001
|
serverCertificate: serverCerts[0],
|
|
2002
|
+
serverCertificateUri: serverCertificateUris[0],
|
|
2054
2003
|
initData: initDatas,
|
|
2055
2004
|
keyIds,
|
|
2056
2005
|
};
|
|
@@ -2082,6 +2031,9 @@ shaka.media.DrmEngine = class {
|
|
|
2082
2031
|
/** @type {!Array.<string>} */
|
|
2083
2032
|
const licenseServers = [];
|
|
2084
2033
|
|
|
2034
|
+
/** @type {!Array.<string>} */
|
|
2035
|
+
const serverCertificateUris = [];
|
|
2036
|
+
|
|
2085
2037
|
/** @type {!Array.<!Uint8Array>} */
|
|
2086
2038
|
const serverCerts = [];
|
|
2087
2039
|
|
|
@@ -2093,13 +2045,19 @@ shaka.media.DrmEngine = class {
|
|
|
2093
2045
|
|
|
2094
2046
|
// TODO: refactor, don't stick drmInfos onto MediaKeySystemConfiguration
|
|
2095
2047
|
shaka.media.DrmEngine.processDrmInfos_(
|
|
2096
|
-
config['drmInfos'], licenseServers, serverCerts,
|
|
2048
|
+
config['drmInfos'], licenseServers, serverCerts,
|
|
2049
|
+
serverCertificateUris, initDatas, keyIds);
|
|
2097
2050
|
|
|
2098
2051
|
if (serverCerts.length > 1) {
|
|
2099
2052
|
shaka.log.warning('Multiple unique server certificates found! ' +
|
|
2100
2053
|
'Only the first will be used.');
|
|
2101
2054
|
}
|
|
2102
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
|
+
|
|
2103
2061
|
if (licenseServers.length > 1) {
|
|
2104
2062
|
shaka.log.warning('Multiple unique license server URIs found! ' +
|
|
2105
2063
|
'Only the first will be used.');
|
|
@@ -2121,6 +2079,7 @@ shaka.media.DrmEngine = class {
|
|
|
2121
2079
|
audioRobustness: audioRobustness || '',
|
|
2122
2080
|
videoRobustness: videoRobustness || '',
|
|
2123
2081
|
serverCertificate: serverCerts[0],
|
|
2082
|
+
serverCertificateUri: serverCertificateUris[0],
|
|
2124
2083
|
initData: initDatas,
|
|
2125
2084
|
keyIds,
|
|
2126
2085
|
};
|
|
@@ -2133,12 +2092,14 @@ shaka.media.DrmEngine = class {
|
|
|
2133
2092
|
* @param {!Array.<shaka.extern.DrmInfo>} drmInfos
|
|
2134
2093
|
* @param {!Array.<string>} licenseServers
|
|
2135
2094
|
* @param {!Array.<!Uint8Array>} serverCerts
|
|
2095
|
+
* @param {!Array.<string>} serverCertificateUris
|
|
2136
2096
|
* @param {!Array.<!shaka.extern.InitDataOverride>} initDatas
|
|
2137
2097
|
* @param {!Set.<string>} keyIds
|
|
2138
2098
|
* @private
|
|
2139
2099
|
*/
|
|
2140
2100
|
static processDrmInfos_(
|
|
2141
|
-
drmInfos, licenseServers, serverCerts,
|
|
2101
|
+
drmInfos, licenseServers, serverCerts,
|
|
2102
|
+
serverCertificateUris, initDatas, keyIds) {
|
|
2142
2103
|
/** @type {function(shaka.extern.InitDataOverride,
|
|
2143
2104
|
* shaka.extern.InitDataOverride):boolean} */
|
|
2144
2105
|
const initDataOverrideEqual = (a, b) => {
|
|
@@ -2157,6 +2118,11 @@ shaka.media.DrmEngine = class {
|
|
|
2157
2118
|
licenseServers.push(drmInfo.licenseServerUri);
|
|
2158
2119
|
}
|
|
2159
2120
|
|
|
2121
|
+
// Build an array of unique license servers.
|
|
2122
|
+
if (!serverCertificateUris.includes(drmInfo.serverCertificateUri)) {
|
|
2123
|
+
serverCertificateUris.push(drmInfo.serverCertificateUri);
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2160
2126
|
// Build an array of unique server certs.
|
|
2161
2127
|
if (drmInfo.serverCertificate) {
|
|
2162
2128
|
const found = serverCerts.some(
|
|
@@ -2269,6 +2235,10 @@ shaka.media.DrmEngine = class {
|
|
|
2269
2235
|
if (advancedConfig.sessionType) {
|
|
2270
2236
|
drmInfo.sessionType = advancedConfig.sessionType;
|
|
2271
2237
|
}
|
|
2238
|
+
|
|
2239
|
+
if (!drmInfo.serverCertificateUri) {
|
|
2240
|
+
drmInfo.serverCertificateUri = advancedConfig.serverCertificateUri;
|
|
2241
|
+
}
|
|
2272
2242
|
}
|
|
2273
2243
|
|
|
2274
2244
|
// Chromecast has a variant of PlayReady that uses a different key
|
|
@@ -345,7 +345,10 @@ 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,
|
|
351
|
+
lastReference.tileDuration);
|
|
349
352
|
}
|
|
350
353
|
|
|
351
354
|
|
|
@@ -135,12 +135,20 @@ shaka.media.SegmentReference = class {
|
|
|
135
135
|
* presentation. Any content from after this time will be removed by
|
|
136
136
|
* MediaSource.
|
|
137
137
|
* @param {!Array.<!shaka.media.SegmentReference>=} partialReferences
|
|
138
|
-
|
|
138
|
+
* A list of SegmentReferences for the partial segments.
|
|
139
|
+
* @param {?string=} tilesLayout
|
|
140
|
+
* The value is a grid-item-dimension consisting of two positive decimal
|
|
141
|
+
* integers in the format: column-x-row ('4x3'). It describes the
|
|
142
|
+
* arrangement of Images in a Grid. The minimum valid LAYOUT is '1x1'.
|
|
143
|
+
* @param {?number=} tileDuration
|
|
144
|
+
* The explicit duration of an individual tile within the tiles grid.
|
|
145
|
+
* If not provided, the duration should be automatically calculated based on
|
|
146
|
+
* the duration of the reference.
|
|
139
147
|
*/
|
|
140
148
|
constructor(
|
|
141
149
|
startTime, endTime, uris, startByte, endByte, initSegmentReference,
|
|
142
150
|
timestampOffset, appendWindowStart, appendWindowEnd,
|
|
143
|
-
partialReferences = []) {
|
|
151
|
+
partialReferences = [], tilesLayout = '', tileDuration = null) {
|
|
144
152
|
// A preload hinted Partial Segment has the same startTime and endTime.
|
|
145
153
|
goog.asserts.assert(startTime <= endTime,
|
|
146
154
|
'startTime must be less than or equal to endTime');
|
|
@@ -184,6 +192,12 @@ shaka.media.SegmentReference = class {
|
|
|
184
192
|
|
|
185
193
|
/** @type {!Array.<!shaka.media.SegmentReference>} */
|
|
186
194
|
this.partialReferences = partialReferences;
|
|
195
|
+
|
|
196
|
+
/** @type {?string} */
|
|
197
|
+
this.tilesLayout = tilesLayout;
|
|
198
|
+
|
|
199
|
+
/** @type {?number} */
|
|
200
|
+
this.tileDuration = tileDuration;
|
|
187
201
|
}
|
|
188
202
|
|
|
189
203
|
/**
|
|
@@ -258,6 +272,27 @@ shaka.media.SegmentReference = class {
|
|
|
258
272
|
hasPartialSegments() {
|
|
259
273
|
return this.partialReferences.length > 0;
|
|
260
274
|
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Returns the segment's tiles layout. Only defined in image segments.
|
|
278
|
+
*
|
|
279
|
+
* @return {?string}
|
|
280
|
+
* @export
|
|
281
|
+
*/
|
|
282
|
+
getTilesLayout() {
|
|
283
|
+
return this.tilesLayout;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Returns the segment's explicit tile duration.
|
|
288
|
+
* Only defined in image segments.
|
|
289
|
+
*
|
|
290
|
+
* @return {?number}
|
|
291
|
+
* @export
|
|
292
|
+
*/
|
|
293
|
+
getTileDuration() {
|
|
294
|
+
return this.tileDuration;
|
|
295
|
+
}
|
|
261
296
|
};
|
|
262
297
|
|
|
263
298
|
|