shaka-player 4.4.2 → 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 (202) hide show
  1. package/.github/workflows/release-please.yaml +2 -27
  2. package/CHANGELOG.md +67 -25
  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 +27 -5
  8. package/demo/common/assets.js +150 -52
  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 +52 -124
  16. package/demo/search.js +23 -35
  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 +187 -211
  22. package/dist/demo.compiled.debug.map +4 -4
  23. package/dist/demo.compiled.js +187 -211
  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 +42 -61
  28. package/dist/receiver.compiled.debug.map +4 -4
  29. package/dist/receiver.compiled.js +42 -61
  30. package/dist/receiver.compiled.map +4 -4
  31. package/dist/shaka-player.compiled.d.ts +728 -365
  32. package/dist/shaka-player.compiled.debug.d.ts +728 -365
  33. package/dist/shaka-player.compiled.debug.externs.js +475 -51
  34. package/dist/shaka-player.compiled.debug.js +576 -480
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +475 -51
  37. package/dist/shaka-player.compiled.js +1117 -1056
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +783 -410
  40. package/dist/shaka-player.ui.debug.d.ts +783 -410
  41. package/dist/shaka-player.ui.debug.externs.js +496 -51
  42. package/dist/shaka-player.ui.debug.js +647 -542
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +496 -51
  45. package/dist/shaka-player.ui.js +1260 -1194
  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/offline.md +1 -1
  52. package/docs/tutorials/ui-customization.md +4 -0
  53. package/externs/css_style_declaration.js +19 -0
  54. package/externs/lcevc.js +37 -13
  55. package/externs/media_remote.js +68 -0
  56. package/externs/mediatailor.js +193 -0
  57. package/externs/pictureinpicture.js +11 -0
  58. package/externs/shaka/ads.js +27 -0
  59. package/externs/shaka/manifest.js +10 -5
  60. package/externs/shaka/manifest_parser.js +7 -1
  61. package/externs/shaka/offline.js +4 -0
  62. package/externs/shaka/player.js +12 -1
  63. package/karma.conf.js +7 -3
  64. package/lib/abr/simple_abr_manager.js +43 -3
  65. package/lib/ads/ad_manager.js +104 -50
  66. package/lib/ads/media_tailor_ad.js +297 -0
  67. package/lib/ads/media_tailor_ad_manager.js +828 -0
  68. package/lib/cea/ts_cea_parser.js +15 -2
  69. package/lib/config/codec_switching_strategy.js +24 -0
  70. package/lib/dash/content_protection.js +120 -2
  71. package/lib/dash/dash_parser.js +79 -13
  72. package/lib/dash/mpd_utils.js +10 -6
  73. package/lib/dash/segment_base.js +13 -5
  74. package/lib/dash/segment_list.js +13 -5
  75. package/lib/dash/segment_template.js +43 -85
  76. package/lib/dependencies/all.js +8 -7
  77. package/lib/hls/hls_parser.js +101 -37
  78. package/lib/lcevc/lcevc_dec.js +220 -0
  79. package/lib/media/adaptation_set.js +22 -11
  80. package/lib/media/adaptation_set_criteria.js +25 -7
  81. package/lib/media/media_source_engine.js +215 -27
  82. package/lib/media/segment_index.js +5 -5
  83. package/lib/media/segment_reference.js +10 -5
  84. package/lib/media/streaming_engine.js +44 -39
  85. package/lib/mss/mss_parser.js +1 -0
  86. package/lib/net/networking_engine.js +1 -0
  87. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  88. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  89. package/lib/offline/manifest_converter.js +1 -0
  90. package/lib/offline/storage.js +3 -0
  91. package/lib/player.js +142 -72
  92. package/lib/routing/payload.js +5 -1
  93. package/lib/text/cue.js +62 -47
  94. package/lib/text/ttml_text_parser.js +17 -0
  95. package/lib/text/ui_text_displayer.js +4 -0
  96. package/lib/text/vtt_text_parser.js +35 -22
  97. package/lib/transmuxer/h265.js +862 -0
  98. package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
  99. package/lib/transmuxer/ts_transmuxer.js +160 -15
  100. package/lib/util/cmcd_manager.js +6 -1
  101. package/lib/util/error.js +28 -9
  102. package/lib/util/exp_golomb.js +30 -2
  103. package/lib/util/fake_event.js +3 -0
  104. package/lib/util/manifest_parser_utils.js +10 -4
  105. package/lib/util/mp4_generator.js +4 -4
  106. package/lib/util/periods.js +2 -0
  107. package/lib/util/platform.js +54 -0
  108. package/lib/util/player_configuration.js +8 -0
  109. package/lib/util/state_history.js +6 -2
  110. package/lib/util/stream_utils.js +133 -217
  111. package/lib/util/ts_parser.js +229 -43
  112. package/maintained-branches.md +3 -2
  113. package/package.json +4 -6
  114. package/roadmap.md +15 -5
  115. package/shaka-player.uncompiled.js +2 -1
  116. package/support.html +0 -1
  117. package/test/cast/cast_receiver_integration.js +47 -0
  118. package/test/codec_switching/codec_switching_integration.js +181 -0
  119. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  120. package/test/dash/dash_parser_integration.js +73 -0
  121. package/test/dash/dash_parser_live_unit.js +2 -0
  122. package/test/dash/dash_parser_manifest_unit.js +47 -0
  123. package/test/dash/dash_parser_segment_base_unit.js +7 -0
  124. package/test/dash/dash_parser_segment_list_unit.js +23 -17
  125. package/test/dash/dash_parser_segment_template_unit.js +49 -0
  126. package/test/demo/demo_unit.js +0 -16
  127. package/test/hls/hls_live_unit.js +35 -0
  128. package/test/hls/hls_parser_unit.js +8 -61
  129. package/test/media/adaptation_set_criteria_unit.js +118 -0
  130. package/test/media/adaptation_set_unit.js +1 -0
  131. package/test/media/media_source_engine_unit.js +165 -1
  132. package/test/media/segment_index_unit.js +4 -4
  133. package/test/media/segment_prefetch_unit.js +1 -1
  134. package/test/media/streaming_engine_unit.js +17 -17
  135. package/test/mss/mss_parser_unit.js +2 -0
  136. package/test/offline/manifest_convert_unit.js +5 -0
  137. package/test/offline/storage_integration.js +1 -4
  138. package/test/player_unit.js +102 -131
  139. package/test/routing/walker_unit.js +1 -0
  140. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  141. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  142. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  143. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  144. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  145. package/test/test/assets/dash-aes-128/dash.mpd +18 -0
  146. package/test/test/assets/dash-aes-128/license +1 -0
  147. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  148. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  149. package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
  150. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  151. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  152. package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
  153. package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
  154. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  155. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  156. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
  157. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
  158. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  159. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  160. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  161. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  162. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  163. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  164. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  165. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  166. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  167. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  168. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
  169. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
  170. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  171. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  172. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  173. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  174. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  175. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  176. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  177. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  178. package/test/test/util/dash_parser_util.js +20 -7
  179. package/test/test/util/fake_ad_manager.js +20 -0
  180. package/test/test/util/fake_media_source_engine.js +8 -2
  181. package/test/test/util/manifest_generator.js +7 -3
  182. package/test/test/util/mss_parser_util.js +4 -0
  183. package/test/test/util/offline_utils.js +1 -0
  184. package/test/test/util/streaming_engine_util.js +7 -4
  185. package/test/text/ttml_text_parser_unit.js +52 -0
  186. package/test/text/vtt_text_parser_unit.js +105 -48
  187. package/test/transmuxer/transmuxer_integration.js +121 -4
  188. package/test/ui/ui_unit.js +3 -10
  189. package/test/util/stream_utils_unit.js +208 -74
  190. package/test/util/ts_parser_unit.js +1 -1
  191. package/ui/controls.js +125 -0
  192. package/ui/externs/ui.js +8 -1
  193. package/ui/pip_button.js +22 -120
  194. package/ui/remote_button.js +201 -0
  195. package/ui/ui.js +5 -2
  196. package/demo/common/message_ids.js +0 -309
  197. package/demo/locales/en.json +0 -287
  198. package/demo/locales/source.json +0 -1142
  199. package/externs/mux.js +0 -69
  200. package/lib/lcevc/lcevc_dil.js +0 -152
  201. package/lib/transmuxer/muxjs_transmuxer.js +0 -242
  202. 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_) {
@@ -533,7 +531,10 @@ shaka.dash.DashParser = class {
533
531
  // Just update the variants and text streams, which may change as periods
534
532
  // are added or removed.
535
533
  this.manifest_.variants = this.periodCombiner_.getVariants();
536
- this.manifest_.textStreams = this.periodCombiner_.getTextStreams();
534
+ const textStreams = this.periodCombiner_.getTextStreams();
535
+ if (textStreams.length > 0) {
536
+ this.manifest_.textStreams = textStreams;
537
+ }
537
538
  this.manifest_.imageStreams = this.periodCombiner_.getImageStreams();
538
539
 
539
540
  // Re-filter the manifest. This will check any configured restrictions on
@@ -1166,6 +1167,9 @@ shaka.dash.DashParser = class {
1166
1167
  }
1167
1168
  }
1168
1169
 
1170
+ const adaptationId = context.adaptationSet.id ||
1171
+ ('__fake__' + this.globalId_++);
1172
+
1169
1173
  for (const stream of streams) {
1170
1174
  // Some DRM license providers require that we have a default
1171
1175
  // key ID from the manifest in the wrapped license request.
@@ -1175,6 +1179,9 @@ shaka.dash.DashParser = class {
1175
1179
  new Set([...drmInfo.keyIds, ...stream.keyIds]) :
1176
1180
  drmInfo.keyIds || stream.keyIds;
1177
1181
  }
1182
+ if (this.config_.dash.enableAudioGroups) {
1183
+ stream.groupId = adaptationId;
1184
+ }
1178
1185
  }
1179
1186
 
1180
1187
  const repIds = representations
@@ -1182,7 +1189,7 @@ shaka.dash.DashParser = class {
1182
1189
  .filter(shaka.util.Functional.isNotNull);
1183
1190
 
1184
1191
  return {
1185
- id: context.adaptationSet.id || ('__fake__' + this.globalId_++),
1192
+ id: adaptationId,
1186
1193
  contentType: context.adaptationSet.contentType,
1187
1194
  language: language,
1188
1195
  main: main,
@@ -1247,21 +1254,61 @@ shaka.dash.DashParser = class {
1247
1254
  const isImage = contentType == ContentType.IMAGE;
1248
1255
 
1249
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
+ }
1250
1296
  const requestSegment = (uris, startByte, endByte, isInit) => {
1251
1297
  return this.requestSegment_(uris, startByte, endByte, isInit);
1252
1298
  };
1253
1299
  if (context.representation.segmentBase) {
1254
1300
  streamInfo = shaka.dash.SegmentBase.createStreamInfo(
1255
- context, requestSegment);
1301
+ context, requestSegment, aes128Key);
1256
1302
  } else if (context.representation.segmentList) {
1257
1303
  streamInfo = shaka.dash.SegmentList.createStreamInfo(
1258
- context, this.streamMap_);
1304
+ context, this.streamMap_, aes128Key);
1259
1305
  } else if (context.representation.segmentTemplate) {
1260
1306
  const hasManifest = !!this.manifest_;
1261
1307
 
1262
1308
  streamInfo = shaka.dash.SegmentTemplate.createStreamInfo(
1263
1309
  context, requestSegment, this.streamMap_, hasManifest,
1264
- this.config_.dash.initialSegmentLimit, this.periodDurations_);
1310
+ this.config_.dash.initialSegmentLimit, this.periodDurations_,
1311
+ aes128Key);
1265
1312
  } else {
1266
1313
  goog.asserts.assert(isText,
1267
1314
  'Must have Segment* with non-text streams.');
@@ -1360,6 +1407,7 @@ shaka.dash.DashParser = class {
1360
1407
  stream = {
1361
1408
  id: this.globalId_++,
1362
1409
  originalId: context.representation.id,
1410
+ groupId: null,
1363
1411
  createSegmentIndex: () => Promise.resolve(),
1364
1412
  closeSegmentIndex: () => {
1365
1413
  if (stream.segmentIndex) {
@@ -1453,6 +1501,8 @@ shaka.dash.DashParser = class {
1453
1501
  return;
1454
1502
  }
1455
1503
 
1504
+ this.playerInterface_.onManifestUpdated();
1505
+
1456
1506
  this.setUpdateTimer_(updateDelay);
1457
1507
  }
1458
1508
 
@@ -1926,10 +1976,8 @@ shaka.dash.DashParser = class {
1926
1976
  endByte,
1927
1977
  this.config_.retryParameters);
1928
1978
 
1929
- const networkingEngine = this.playerInterface_.networkingEngine;
1930
- const operation = networkingEngine.request(requestType, request, {type});
1931
- this.operationManager_.manage(operation);
1932
- const response = await operation.promise;
1979
+ const response = await this.makeNetworkRequest_(
1980
+ request, requestType, {type});
1933
1981
  return response.data;
1934
1982
  }
1935
1983
 
@@ -1955,6 +2003,24 @@ shaka.dash.DashParser = class {
1955
2003
  // types well.
1956
2004
  return mimeType.split('/')[0];
1957
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
+ }
1958
2024
  };
1959
2025
 
1960
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