shaka-player 4.4.3 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/.github/workflows/release-please.yaml +2 -27
  2. package/CHANGELOG.md +64 -45
  3. package/README.md +16 -10
  4. package/demo/asset_card.js +18 -21
  5. package/demo/cast_receiver/index.html +0 -1
  6. package/demo/close_button.js +0 -3
  7. package/demo/common/asset.js +22 -5
  8. package/demo/common/assets.js +132 -49
  9. package/demo/config.js +192 -253
  10. package/demo/custom.js +39 -98
  11. package/demo/front.js +7 -10
  12. package/demo/index.html +19 -22
  13. package/demo/input.js +6 -11
  14. package/demo/input_container.js +8 -9
  15. package/demo/main.js +51 -123
  16. package/demo/search.js +22 -34
  17. package/demo/service_worker.js +0 -3
  18. package/demo/tooltip.js +3 -5
  19. package/demo/visualizer.js +3 -5
  20. package/demo/visualizer_button.js +1 -20
  21. package/dist/demo.compiled.debug.js +152 -178
  22. package/dist/demo.compiled.debug.map +4 -4
  23. package/dist/demo.compiled.js +152 -178
  24. package/dist/demo.compiled.map +4 -4
  25. package/dist/deps.js +27 -24
  26. package/dist/locales.js +31 -31
  27. package/dist/receiver.compiled.debug.js +22 -43
  28. package/dist/receiver.compiled.debug.map +4 -4
  29. package/dist/receiver.compiled.js +22 -43
  30. package/dist/receiver.compiled.map +4 -4
  31. package/dist/shaka-player.compiled.d.ts +507 -365
  32. package/dist/shaka-player.compiled.debug.d.ts +507 -365
  33. package/dist/shaka-player.compiled.debug.externs.js +205 -51
  34. package/dist/shaka-player.compiled.debug.js +541 -450
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +205 -51
  37. package/dist/shaka-player.compiled.js +1120 -1066
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +562 -410
  40. package/dist/shaka-player.ui.debug.d.ts +562 -410
  41. package/dist/shaka-player.ui.debug.externs.js +226 -51
  42. package/dist/shaka-player.ui.debug.js +606 -506
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +226 -51
  45. package/dist/shaka-player.ui.js +1266 -1207
  46. package/dist/shaka-player.ui.map +4 -4
  47. package/docs/design/lcevc-integration.md +14 -14
  48. package/docs/tutorials/faq.md +27 -55
  49. package/docs/tutorials/index.json +2 -1
  50. package/docs/tutorials/lcevc.md +118 -0
  51. package/docs/tutorials/ui-customization.md +4 -0
  52. package/externs/css_style_declaration.js +19 -0
  53. package/externs/lcevc.js +37 -13
  54. package/externs/media_remote.js +68 -0
  55. package/externs/mediatailor.js +193 -0
  56. package/externs/pictureinpicture.js +11 -0
  57. package/externs/shaka/ads.js +27 -0
  58. package/externs/shaka/manifest.js +10 -5
  59. package/externs/shaka/manifest_parser.js +7 -1
  60. package/externs/shaka/offline.js +4 -0
  61. package/externs/shaka/player.js +12 -1
  62. package/karma.conf.js +7 -3
  63. package/lib/abr/simple_abr_manager.js +43 -3
  64. package/lib/ads/ad_manager.js +104 -50
  65. package/lib/ads/media_tailor_ad.js +297 -0
  66. package/lib/ads/media_tailor_ad_manager.js +828 -0
  67. package/lib/cea/ts_cea_parser.js +15 -2
  68. package/lib/config/codec_switching_strategy.js +24 -0
  69. package/lib/dash/content_protection.js +120 -2
  70. package/lib/dash/dash_parser.js +75 -12
  71. package/lib/dash/mpd_utils.js +10 -6
  72. package/lib/dash/segment_base.js +13 -5
  73. package/lib/dash/segment_list.js +13 -5
  74. package/lib/dash/segment_template.js +43 -85
  75. package/lib/dependencies/all.js +8 -7
  76. package/lib/hls/hls_parser.js +44 -16
  77. package/lib/lcevc/lcevc_dec.js +220 -0
  78. package/lib/media/adaptation_set.js +22 -11
  79. package/lib/media/adaptation_set_criteria.js +25 -7
  80. package/lib/media/media_source_engine.js +215 -27
  81. package/lib/media/segment_index.js +1 -1
  82. package/lib/media/segment_reference.js +7 -7
  83. package/lib/media/streaming_engine.js +33 -18
  84. package/lib/mss/mss_parser.js +1 -0
  85. package/lib/net/networking_engine.js +1 -0
  86. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  87. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  88. package/lib/offline/manifest_converter.js +1 -0
  89. package/lib/offline/storage.js +3 -0
  90. package/lib/player.js +142 -72
  91. package/lib/routing/payload.js +5 -1
  92. package/lib/text/cue.js +15 -0
  93. package/lib/text/ttml_text_parser.js +17 -0
  94. package/lib/text/ui_text_displayer.js +4 -0
  95. package/lib/text/vtt_text_parser.js +33 -20
  96. package/lib/transmuxer/h265.js +862 -0
  97. package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
  98. package/lib/transmuxer/ts_transmuxer.js +160 -15
  99. package/lib/util/error.js +28 -9
  100. package/lib/util/exp_golomb.js +30 -2
  101. package/lib/util/fake_event.js +3 -0
  102. package/lib/util/mp4_generator.js +4 -4
  103. package/lib/util/periods.js +2 -0
  104. package/lib/util/platform.js +40 -0
  105. package/lib/util/player_configuration.js +8 -0
  106. package/lib/util/state_history.js +6 -2
  107. package/lib/util/stream_utils.js +133 -217
  108. package/lib/util/ts_parser.js +226 -40
  109. package/maintained-branches.md +3 -2
  110. package/package.json +4 -6
  111. package/roadmap.md +15 -5
  112. package/shaka-player.uncompiled.js +2 -1
  113. package/support.html +0 -1
  114. package/test/cast/cast_receiver_integration.js +47 -0
  115. package/test/codec_switching/codec_switching_integration.js +181 -0
  116. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  117. package/test/dash/dash_parser_integration.js +73 -0
  118. package/test/dash/dash_parser_live_unit.js +2 -0
  119. package/test/dash/dash_parser_manifest_unit.js +42 -0
  120. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  121. package/test/dash/dash_parser_segment_list_unit.js +2 -0
  122. package/test/dash/dash_parser_segment_template_unit.js +2 -0
  123. package/test/demo/demo_unit.js +0 -16
  124. package/test/hls/hls_live_unit.js +2 -0
  125. package/test/hls/hls_parser_unit.js +8 -6
  126. package/test/media/adaptation_set_criteria_unit.js +118 -0
  127. package/test/media/adaptation_set_unit.js +1 -0
  128. package/test/media/media_source_engine_unit.js +165 -1
  129. package/test/media/segment_index_unit.js +4 -4
  130. package/test/media/segment_prefetch_unit.js +1 -1
  131. package/test/media/streaming_engine_unit.js +17 -17
  132. package/test/mss/mss_parser_unit.js +2 -0
  133. package/test/offline/manifest_convert_unit.js +5 -0
  134. package/test/offline/storage_integration.js +1 -4
  135. package/test/player_unit.js +102 -131
  136. package/test/routing/walker_unit.js +1 -0
  137. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  138. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  139. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  140. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  141. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  142. package/test/test/assets/dash-aes-128/dash.mpd +18 -0
  143. package/test/test/assets/dash-aes-128/license +1 -0
  144. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  145. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  146. package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
  147. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  148. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  149. package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
  150. package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
  151. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  152. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  153. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
  154. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
  155. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  156. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  157. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  158. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  159. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  160. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  161. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  162. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  163. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  164. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  165. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
  166. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
  167. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  168. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  169. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  170. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  171. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  172. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  173. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  174. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  175. package/test/test/util/dash_parser_util.js +4 -0
  176. package/test/test/util/fake_ad_manager.js +20 -0
  177. package/test/test/util/fake_media_source_engine.js +8 -2
  178. package/test/test/util/manifest_generator.js +7 -3
  179. package/test/test/util/mss_parser_util.js +4 -0
  180. package/test/test/util/offline_utils.js +1 -0
  181. package/test/test/util/streaming_engine_util.js +7 -4
  182. package/test/text/ttml_text_parser_unit.js +52 -0
  183. package/test/text/vtt_text_parser_unit.js +103 -31
  184. package/test/transmuxer/transmuxer_integration.js +117 -0
  185. package/test/ui/ui_unit.js +3 -10
  186. package/test/util/stream_utils_unit.js +208 -74
  187. package/ui/controls.js +125 -0
  188. package/ui/externs/ui.js +8 -1
  189. package/ui/pip_button.js +22 -120
  190. package/ui/remote_button.js +201 -0
  191. package/ui/ui.js +5 -2
  192. package/demo/common/message_ids.js +0 -309
  193. package/demo/locales/en.json +0 -288
  194. package/demo/locales/source.json +0 -1146
  195. package/externs/mux.js +0 -69
  196. package/lib/lcevc/lcevc_dil.js +0 -152
  197. package/lib/transmuxer/muxjs_transmuxer.js +0 -242
  198. package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
@@ -49,10 +49,23 @@ shaka.cea.TsCeaParser = class {
49
49
  return captionPackets;
50
50
  }
51
51
  const tsParser = new shaka.util.TsParser().parse(uint8ArrayData);
52
+ const codecs = tsParser.getCodecs();
52
53
  const videoNalus = tsParser.getVideoNalus();
54
+ const validNaluTypes = [];
55
+ switch (codecs.video) {
56
+ case 'avc':
57
+ validNaluTypes.push(CeaUtils.H264_NALU_TYPE_SEI);
58
+ break;
59
+ case 'hvc':
60
+ validNaluTypes.push(CeaUtils.H265_PREFIX_NALU_TYPE_SEI);
61
+ validNaluTypes.push(CeaUtils.H265_SUFFIX_NALU_TYPE_SEI);
62
+ break;
63
+ }
64
+ if (!validNaluTypes.length) {
65
+ return captionPackets;
66
+ }
53
67
  for (const nalu of videoNalus) {
54
- if (nalu.type == CeaUtils.H264_NALU_TYPE_SEI &&
55
- nalu.time != null) {
68
+ if (validNaluTypes.includes(nalu.type) && nalu.time != null) {
56
69
  for (const packet of this.seiProcessor_.process(nalu.data)) {
57
70
  captionPackets.push({
58
71
  packet: packet,
@@ -0,0 +1,24 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ goog.provide('shaka.config.CodecSwitchingStrategy');
8
+
9
+ /**
10
+ * @enum {string}
11
+ * @export
12
+ */
13
+ shaka.config.CodecSwitchingStrategy = {
14
+ // Allow codec switching which will always involve reloading the
15
+ // `MediaSource`.
16
+ RELOAD: 'reload',
17
+ // Allow codec switching; determine if `SourceBuffer.changeType` is available
18
+ // and attempt to use this first, but fall back to reloading `MediaSource` if
19
+ // not available.
20
+ //
21
+ // Note: Some devices that support `SourceBuffer.changeType` can become stuck
22
+ // in a pause state.
23
+ SMOOTH: 'smooth',
24
+ };
@@ -39,6 +39,8 @@ shaka.dash.ContentProtection = class {
39
39
  /** @type {!Array.<shaka.extern.DrmInfo>} */
40
40
  let drmInfos = [];
41
41
  let parsedNonCenc = [];
42
+ /** @type {?shaka.dash.ContentProtection.Aes128Info} */
43
+ let aes128Info = null;
42
44
 
43
45
  // Get the default key ID; if there are multiple, they must all match.
44
46
  const keyIds = new Set(parsed.map((element) => element.keyId));
@@ -53,6 +55,21 @@ shaka.dash.ContentProtection = class {
53
55
  }
54
56
 
55
57
  if (!ignoreDrmInfo) {
58
+ const aes128Elements = parsed.filter((elem) => {
59
+ return elem.schemeUri == ContentProtection.Aes128Protection_;
60
+ });
61
+
62
+ if (aes128Elements.length > 1) {
63
+ throw new shaka.util.Error(
64
+ shaka.util.Error.Severity.CRITICAL,
65
+ shaka.util.Error.Category.MANIFEST,
66
+ shaka.util.Error.Code.DASH_CONFLICTING_AES_128);
67
+ }
68
+
69
+ if (aes128Elements.length) {
70
+ aes128Info = ContentProtection.parseAes128_(aes128Elements[0]);
71
+ }
72
+
56
73
  // Find the default key ID and init data. Create a new array of all the
57
74
  // non-CENC elements.
58
75
  parsedNonCenc = parsed.filter((elem) => {
@@ -62,7 +79,7 @@ shaka.dash.ContentProtection = class {
62
79
  defaultInit = elem.init || defaultInit;
63
80
  return false;
64
81
  } else {
65
- return true;
82
+ return elem.schemeUri != ContentProtection.Aes128Protection_;
66
83
  }
67
84
  });
68
85
 
@@ -80,7 +97,8 @@ shaka.dash.ContentProtection = class {
80
97
 
81
98
  // If there are only CENC element(s) or ignoreDrmInfo flag is set, assume
82
99
  // all key-systems are supported.
83
- if (parsed.length && (ignoreDrmInfo || !parsedNonCenc.length)) {
100
+ if (parsed.length && !aes128Info &&
101
+ (ignoreDrmInfo || !parsedNonCenc.length)) {
84
102
  drmInfos = [];
85
103
 
86
104
  for (const keySystem of Object.values(keySystemsByURI)) {
@@ -110,6 +128,7 @@ shaka.dash.ContentProtection = class {
110
128
  defaultKeyId: defaultKeyId,
111
129
  defaultInit: defaultInit,
112
130
  drmInfos: drmInfos,
131
+ aes128Info: aes128Info,
113
132
  firstRepresentation: true,
114
133
  };
115
134
  }
@@ -551,6 +570,79 @@ shaka.dash.ContentProtection = class {
551
570
  init: (init.length > 0 ? init : null),
552
571
  };
553
572
  }
573
+
574
+ /**
575
+ * Parses the given AES-128 ContentProtection element.
576
+ *
577
+ * @param {shaka.dash.ContentProtection.Element} element
578
+ * @return {?shaka.dash.ContentProtection.Aes128Info}
579
+ * @private
580
+ */
581
+ static parseAes128_(element) {
582
+ // Check if the Web Crypto API is available.
583
+ if (!window.crypto || !window.crypto.subtle) {
584
+ shaka.log.alwaysWarn('Web Crypto API is not available to decrypt ' +
585
+ 'AES-128. (Web Crypto only exists in secure origins like https)');
586
+ throw new shaka.util.Error(
587
+ shaka.util.Error.Severity.CRITICAL,
588
+ shaka.util.Error.Category.MANIFEST,
589
+ shaka.util.Error.Code.NO_WEB_CRYPTO_API);
590
+ }
591
+
592
+ const namespace = 'urn:mpeg:dash:schema:sea:2012';
593
+ const segmentEncryption = shaka.util.XmlUtils.findChildNS(
594
+ element.node, namespace, 'SegmentEncryption');
595
+
596
+ if (!segmentEncryption) {
597
+ throw new shaka.util.Error(
598
+ shaka.util.Error.Severity.CRITICAL,
599
+ shaka.util.Error.Category.MANIFEST,
600
+ shaka.util.Error.Code.DASH_UNSUPPORTED_AES_128);
601
+ }
602
+
603
+ const aesSchemeIdUri = 'urn:mpeg:dash:sea:aes128-cbc:2013';
604
+ const segmentEncryptionSchemeIdUri =
605
+ segmentEncryption.getAttribute('schemeIdUri');
606
+ if (segmentEncryptionSchemeIdUri != aesSchemeIdUri) {
607
+ throw new shaka.util.Error(
608
+ shaka.util.Error.Severity.CRITICAL,
609
+ shaka.util.Error.Category.MANIFEST,
610
+ shaka.util.Error.Code.DASH_UNSUPPORTED_AES_128);
611
+ }
612
+
613
+ const cryptoPeriod = shaka.util.XmlUtils.findChildNS(
614
+ element.node, namespace, 'CryptoPeriod');
615
+
616
+ if (!cryptoPeriod) {
617
+ throw new shaka.util.Error(
618
+ shaka.util.Error.Severity.CRITICAL,
619
+ shaka.util.Error.Category.MANIFEST,
620
+ shaka.util.Error.Code.DASH_UNSUPPORTED_AES_128);
621
+ }
622
+
623
+ const ivHex = cryptoPeriod.getAttribute('IV');
624
+ const keyUri = cryptoPeriod.getAttribute('keyUriTemplate');
625
+ if (!ivHex || !keyUri) {
626
+ throw new shaka.util.Error(
627
+ shaka.util.Error.Severity.CRITICAL,
628
+ shaka.util.Error.Category.MANIFEST,
629
+ shaka.util.Error.Code.DASH_UNSUPPORTED_AES_128);
630
+ }
631
+
632
+ // Exclude 0x at the start of string.
633
+ const iv = shaka.util.Uint8ArrayUtils.fromHex(ivHex.substr(2));
634
+ if (iv.byteLength != 16) {
635
+ throw new shaka.util.Error(
636
+ shaka.util.Error.Severity.CRITICAL,
637
+ shaka.util.Error.Category.MANIFEST,
638
+ shaka.util.Error.Code.AES_128_INVALID_IV_LENGTH);
639
+ }
640
+
641
+ return {
642
+ keyUri,
643
+ iv,
644
+ };
645
+ }
554
646
  };
555
647
 
556
648
  /**
@@ -584,6 +676,7 @@ shaka.dash.ContentProtection.PLAYREADY_RECORD_TYPES = {
584
676
  * defaultKeyId: ?string,
585
677
  * defaultInit: Array.<shaka.extern.InitDataOverride>,
586
678
  * drmInfos: !Array.<shaka.extern.DrmInfo>,
679
+ * aes128Info: ?shaka.dash.ContentProtection.Aes128Info,
587
680
  * firstRepresentation: boolean
588
681
  * }}
589
682
  *
@@ -599,6 +692,8 @@ shaka.dash.ContentProtection.PLAYREADY_RECORD_TYPES = {
599
692
  * is no default.
600
693
  * @property {!Array.<shaka.extern.DrmInfo>} drmInfos
601
694
  * The DrmInfo objects.
695
+ * @property {?shaka.dash.ContentProtection.Aes128Info} aes128Info
696
+ * The AES-128 key info.
602
697
  * @property {boolean} firstRepresentation
603
698
  * True when first parsed; changed to false after the first call to
604
699
  * parseKeyIds. This is used to determine if a dummy key-system should be
@@ -607,6 +702,22 @@ shaka.dash.ContentProtection.PLAYREADY_RECORD_TYPES = {
607
702
  */
608
703
  shaka.dash.ContentProtection.Context;
609
704
 
705
+ /**
706
+ * @typedef {{
707
+ * keyUri: string,
708
+ * iv: !Uint8Array
709
+ * }}
710
+ *
711
+ * @description
712
+ * Contains information about the AES-128 keyUri and IV found at the
713
+ * AdaptationSet level.
714
+ *
715
+ * @property {string} method
716
+ * The keyUri in the manifest.
717
+ * @property {!Uint8Array} iv
718
+ * The IV in the manifest.
719
+ */
720
+ shaka.dash.ContentProtection.Aes128Info;
610
721
 
611
722
  /**
612
723
  * @typedef {{
@@ -658,6 +769,13 @@ shaka.dash.ContentProtection.licenseUrlParsers_ = new Map()
658
769
  shaka.dash.ContentProtection.MP4Protection_ =
659
770
  'urn:mpeg:dash:mp4protection:2011';
660
771
 
772
+ /**
773
+ * @const {string}
774
+ * @private
775
+ */
776
+ shaka.dash.ContentProtection.Aes128Protection_ =
777
+ 'urn:mpeg:dash:sea:2012';
778
+
661
779
 
662
780
  /**
663
781
  * @const {string}
@@ -224,12 +224,10 @@ shaka.dash.DashParser = class {
224
224
  const type = shaka.net.NetworkingEngine.AdvancedRequestType.MPD;
225
225
  const request = shaka.net.NetworkingEngine.makeRequest(
226
226
  this.manifestUris_, this.config_.retryParameters);
227
- const networkingEngine = this.playerInterface_.networkingEngine;
228
227
  const startTime = Date.now();
229
- const operation = networkingEngine.request(requestType, request, {type});
230
- this.operationManager_.manage(operation);
231
228
 
232
- const response = await operation.promise;
229
+ const response = await this.makeNetworkRequest_(
230
+ request, requestType, {type});
233
231
 
234
232
  // Detect calls to stop().
235
233
  if (!this.playerInterface_) {
@@ -1169,6 +1167,9 @@ shaka.dash.DashParser = class {
1169
1167
  }
1170
1168
  }
1171
1169
 
1170
+ const adaptationId = context.adaptationSet.id ||
1171
+ ('__fake__' + this.globalId_++);
1172
+
1172
1173
  for (const stream of streams) {
1173
1174
  // Some DRM license providers require that we have a default
1174
1175
  // key ID from the manifest in the wrapped license request.
@@ -1178,6 +1179,9 @@ shaka.dash.DashParser = class {
1178
1179
  new Set([...drmInfo.keyIds, ...stream.keyIds]) :
1179
1180
  drmInfo.keyIds || stream.keyIds;
1180
1181
  }
1182
+ if (this.config_.dash.enableAudioGroups) {
1183
+ stream.groupId = adaptationId;
1184
+ }
1181
1185
  }
1182
1186
 
1183
1187
  const repIds = representations
@@ -1185,7 +1189,7 @@ shaka.dash.DashParser = class {
1185
1189
  .filter(shaka.util.Functional.isNotNull);
1186
1190
 
1187
1191
  return {
1188
- id: context.adaptationSet.id || ('__fake__' + this.globalId_++),
1192
+ id: adaptationId,
1189
1193
  contentType: context.adaptationSet.contentType,
1190
1194
  language: language,
1191
1195
  main: main,
@@ -1250,21 +1254,61 @@ shaka.dash.DashParser = class {
1250
1254
  const isImage = contentType == ContentType.IMAGE;
1251
1255
 
1252
1256
  try {
1257
+ /** @type {shaka.extern.aes128Key|undefined} */
1258
+ let aes128Key = undefined;
1259
+ if (contentProtection.aes128Info) {
1260
+ const baseUris = context.representation.baseUris;
1261
+ const uris = shaka.util.ManifestParserUtils.resolveUris(
1262
+ baseUris, [contentProtection.aes128Info.keyUri]);
1263
+ const requestType = shaka.net.NetworkingEngine.RequestType.KEY;
1264
+ const request = shaka.net.NetworkingEngine.makeRequest(
1265
+ uris, this.config_.retryParameters);
1266
+
1267
+ aes128Key = {
1268
+ method: 'AES-128',
1269
+ iv: contentProtection.aes128Info.iv,
1270
+ firstMediaSequenceNumber: 0,
1271
+ };
1272
+
1273
+ // Don't download the key object until the segment is parsed, to
1274
+ // avoid a startup delay for long manifests with lots of keys.
1275
+ aes128Key.fetchKey = async () => {
1276
+ const keyResponse =
1277
+ await this.makeNetworkRequest_(request, requestType);
1278
+
1279
+ // keyResponse.status is undefined when URI is
1280
+ // "data:text/plain;base64,"
1281
+ if (!keyResponse.data || keyResponse.data.byteLength != 16) {
1282
+ throw new shaka.util.Error(
1283
+ shaka.util.Error.Severity.CRITICAL,
1284
+ shaka.util.Error.Category.MANIFEST,
1285
+ shaka.util.Error.Code.AES_128_INVALID_KEY_LENGTH);
1286
+ }
1287
+
1288
+ const algorithm = {
1289
+ name: 'AES-CBC',
1290
+ };
1291
+ aes128Key.cryptoKey = await window.crypto.subtle.importKey(
1292
+ 'raw', keyResponse.data, algorithm, true, ['decrypt']);
1293
+ aes128Key.fetchKey = undefined; // No longer needed.
1294
+ };
1295
+ }
1253
1296
  const requestSegment = (uris, startByte, endByte, isInit) => {
1254
1297
  return this.requestSegment_(uris, startByte, endByte, isInit);
1255
1298
  };
1256
1299
  if (context.representation.segmentBase) {
1257
1300
  streamInfo = shaka.dash.SegmentBase.createStreamInfo(
1258
- context, requestSegment);
1301
+ context, requestSegment, aes128Key);
1259
1302
  } else if (context.representation.segmentList) {
1260
1303
  streamInfo = shaka.dash.SegmentList.createStreamInfo(
1261
- context, this.streamMap_);
1304
+ context, this.streamMap_, aes128Key);
1262
1305
  } else if (context.representation.segmentTemplate) {
1263
1306
  const hasManifest = !!this.manifest_;
1264
1307
 
1265
1308
  streamInfo = shaka.dash.SegmentTemplate.createStreamInfo(
1266
1309
  context, requestSegment, this.streamMap_, hasManifest,
1267
- this.config_.dash.initialSegmentLimit, this.periodDurations_);
1310
+ this.config_.dash.initialSegmentLimit, this.periodDurations_,
1311
+ aes128Key);
1268
1312
  } else {
1269
1313
  goog.asserts.assert(isText,
1270
1314
  'Must have Segment* with non-text streams.');
@@ -1363,6 +1407,7 @@ shaka.dash.DashParser = class {
1363
1407
  stream = {
1364
1408
  id: this.globalId_++,
1365
1409
  originalId: context.representation.id,
1410
+ groupId: null,
1366
1411
  createSegmentIndex: () => Promise.resolve(),
1367
1412
  closeSegmentIndex: () => {
1368
1413
  if (stream.segmentIndex) {
@@ -1456,6 +1501,8 @@ shaka.dash.DashParser = class {
1456
1501
  return;
1457
1502
  }
1458
1503
 
1504
+ this.playerInterface_.onManifestUpdated();
1505
+
1459
1506
  this.setUpdateTimer_(updateDelay);
1460
1507
  }
1461
1508
 
@@ -1929,10 +1976,8 @@ shaka.dash.DashParser = class {
1929
1976
  endByte,
1930
1977
  this.config_.retryParameters);
1931
1978
 
1932
- const networkingEngine = this.playerInterface_.networkingEngine;
1933
- const operation = networkingEngine.request(requestType, request, {type});
1934
- this.operationManager_.manage(operation);
1935
- const response = await operation.promise;
1979
+ const response = await this.makeNetworkRequest_(
1980
+ request, requestType, {type});
1936
1981
  return response.data;
1937
1982
  }
1938
1983
 
@@ -1958,6 +2003,24 @@ shaka.dash.DashParser = class {
1958
2003
  // types well.
1959
2004
  return mimeType.split('/')[0];
1960
2005
  }
2006
+
2007
+
2008
+ /**
2009
+ * Create a networking request. This will manage the request using the
2010
+ * parser's operation manager.
2011
+ *
2012
+ * @param {shaka.extern.Request} request
2013
+ * @param {shaka.net.NetworkingEngine.RequestType} type
2014
+ * @param {shaka.extern.RequestContext=} context
2015
+ * @return {!Promise.<shaka.extern.Response>}
2016
+ * @private
2017
+ */
2018
+ makeNetworkRequest_(request, type, context) {
2019
+ const op = this.playerInterface_.networkingEngine.request(
2020
+ type, request, context);
2021
+ this.operationManager_.manage(op);
2022
+ return op.promise;
2023
+ }
1961
2024
  };
1962
2025
 
1963
2026
 
@@ -30,7 +30,7 @@ shaka.dash.MpdUtils = class {
30
30
  * @param {?string} representationId
31
31
  * @param {?number} number
32
32
  * @param {?number} bandwidth
33
- * @param {?number} time
33
+ * @param {?(number|bigint)} time
34
34
  * @return {string} A URI string.
35
35
  * @see ISO/IEC 23009-1:2014 section 5.3.9.4.4
36
36
  */
@@ -71,11 +71,15 @@ shaka.dash.MpdUtils = class {
71
71
  }
72
72
 
73
73
  if (name == 'Time') {
74
- goog.asserts.assert(typeof value == 'number',
75
- 'Time value should be a number!');
76
- goog.asserts.assert(Math.abs(value - Math.round(value)) < 0.2,
77
- 'Calculated $Time$ values must be close to integers');
78
- value = Math.round(value);
74
+ if (typeof value != 'bigint') {
75
+ goog.asserts.assert(typeof value == 'number',
76
+ 'Time value should be a number or bigint!');
77
+ if (Math.abs(value - Math.round(value)) >= 0.2) {
78
+ shaka.log.alwaysWarn(
79
+ 'Calculated $Time$ values must be close to integers');
80
+ }
81
+ value = Math.round(value);
82
+ }
79
83
  }
80
84
 
81
85
  /** @type {string} */
@@ -31,9 +31,10 @@ shaka.dash.SegmentBase = class {
31
31
  *
32
32
  * @param {shaka.dash.DashParser.Context} context
33
33
  * @param {function(?shaka.dash.DashParser.InheritanceFrame):Element} callback
34
+ * @param {shaka.extern.aes128Key|undefined} aes128Key
34
35
  * @return {shaka.media.InitSegmentReference}
35
36
  */
36
- static createInitSegment(context, callback) {
37
+ static createInitSegment(context, callback, aes128Key) {
37
38
  const MpdUtils = shaka.dash.MpdUtils;
38
39
  const XmlUtils = shaka.util.XmlUtils;
39
40
  const ManifestParserUtils = shaka.util.ManifestParserUtils;
@@ -63,7 +64,13 @@ shaka.dash.SegmentBase = class {
63
64
  const getUris = () => resolvedUris;
64
65
  const qualityInfo = shaka.dash.SegmentBase.createQualityInfo(context);
65
66
  return new shaka.media.InitSegmentReference(
66
- getUris, startByte, endByte, qualityInfo);
67
+ getUris,
68
+ startByte,
69
+ endByte,
70
+ qualityInfo,
71
+ /* timescale= */ null,
72
+ /* segmentData= */ null,
73
+ aes128Key);
67
74
  }
68
75
 
69
76
  /**
@@ -71,9 +78,10 @@ shaka.dash.SegmentBase = class {
71
78
  *
72
79
  * @param {shaka.dash.DashParser.Context} context
73
80
  * @param {shaka.dash.DashParser.RequestSegmentCallback} requestSegment
81
+ * @param {shaka.extern.aes128Key|undefined} aes128Key
74
82
  * @return {shaka.dash.DashParser.StreamInfo}
75
83
  */
76
- static createStreamInfo(context, requestSegment) {
84
+ static createStreamInfo(context, requestSegment, aes128Key) {
77
85
  goog.asserts.assert(context.representation.segmentBase,
78
86
  'Should only be called with SegmentBase');
79
87
  // Since SegmentBase does not need updates, simply treat any call as
@@ -95,8 +103,8 @@ shaka.dash.SegmentBase = class {
95
103
  const scaledPresentationTimeOffset =
96
104
  (unscaledPresentationTimeOffset / timescale) || 0;
97
105
 
98
- const initSegmentReference =
99
- SegmentBase.createInitSegment(context, SegmentBase.fromInheritance_);
106
+ const initSegmentReference = SegmentBase.createInitSegment(
107
+ context, SegmentBase.fromInheritance_, aes128Key);
100
108
 
101
109
  // Throws an immediate error if the format is unsupported.
102
110
  SegmentBase.checkSegmentIndexRangeSupport_(context, initSegmentReference);
@@ -31,15 +31,16 @@ shaka.dash.SegmentList = class {
31
31
  *
32
32
  * @param {shaka.dash.DashParser.Context} context
33
33
  * @param {!Object.<string, !shaka.extern.Stream>} streamMap
34
+ * @param {shaka.extern.aes128Key|undefined} aes128Key
34
35
  * @return {shaka.dash.DashParser.StreamInfo}
35
36
  */
36
- static createStreamInfo(context, streamMap) {
37
+ static createStreamInfo(context, streamMap, aes128Key) {
37
38
  goog.asserts.assert(context.representation.segmentList,
38
39
  'Should only be called with SegmentList');
39
40
  const SegmentList = shaka.dash.SegmentList;
40
41
 
41
42
  const initSegmentReference = shaka.dash.SegmentBase.createInitSegment(
42
- context, SegmentList.fromInheritance_);
43
+ context, SegmentList.fromInheritance_, aes128Key);
43
44
  const info = SegmentList.parseSegmentListInfo_(context);
44
45
 
45
46
  SegmentList.checkSegmentListInfo_(context, info);
@@ -59,7 +60,7 @@ shaka.dash.SegmentList = class {
59
60
  const references = SegmentList.createSegmentReferences_(
60
61
  context.periodInfo.start, context.periodInfo.duration,
61
62
  info.startNumber, context.representation.baseUris, info,
62
- initSegmentReference);
63
+ initSegmentReference, aes128Key);
63
64
 
64
65
  const isNew = !segmentIndex;
65
66
  if (segmentIndex) {
@@ -197,12 +198,13 @@ shaka.dash.SegmentList = class {
197
198
  * @param {!Array.<string>} baseUris
198
199
  * @param {shaka.dash.SegmentList.SegmentListInfo} info
199
200
  * @param {shaka.media.InitSegmentReference} initSegmentReference
201
+ * @param {shaka.extern.aes128Key|undefined} aes128Key
200
202
  * @return {!Array.<!shaka.media.SegmentReference>}
201
203
  * @private
202
204
  */
203
205
  static createSegmentReferences_(
204
206
  periodStart, periodDuration, startNumber, baseUris, info,
205
- initSegmentReference) {
207
+ initSegmentReference, aes128Key) {
206
208
  const ManifestParserUtils = shaka.util.ManifestParserUtils;
207
209
 
208
210
  let max = info.mediaSegments.length;
@@ -257,7 +259,13 @@ shaka.dash.SegmentList = class {
257
259
  segment.end,
258
260
  initSegmentReference,
259
261
  timestampOffset,
260
- appendWindowStart, appendWindowEnd));
262
+ appendWindowStart, appendWindowEnd,
263
+ /* partialReferences= */ [],
264
+ /* tilesLayout= */ '',
265
+ /* tileDuration= */ null,
266
+ /* syncTime= */ null,
267
+ shaka.media.SegmentReference.Status.AVAILABLE,
268
+ aes128Key));
261
269
  prevEndTime = endTime;
262
270
  }
263
271