shaka-player 3.3.5 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/.github/config.yml +1 -0
  2. package/.github/workflows/demo-version-index.yaml +8 -0
  3. package/.github/workflows/release-please.yaml +18 -2
  4. package/.github/workflows/sync-labels.yaml +33 -0
  5. package/.github/workflows/update-issues.yaml +29 -0
  6. package/.github/workflows/validate-pr-title.yaml +35 -0
  7. package/AUTHORS +1 -0
  8. package/CHANGELOG.md +215 -41
  9. package/CONTRIBUTORS +1 -0
  10. package/README.md +14 -11
  11. package/app-engine/demo-version-index/README.md +3 -3
  12. package/app-engine/demo-version-index/app.yaml +27 -1
  13. package/app-engine/demo-version-index/generate.py +164 -0
  14. package/app-engine/demo-version-index/main.py +4 -155
  15. package/app-engine/demo-version-index/requirements.txt +0 -1
  16. package/build/checkversion.py +1 -1
  17. package/build/compiler.py +1 -1
  18. package/build/misspellings.txt +1 -0
  19. package/build/shaka-lab.yaml +0 -2
  20. package/build/types/polyfill +0 -3
  21. package/demo/common/asset.js +17 -1
  22. package/demo/common/assets.js +29 -0
  23. package/demo/common/message_ids.js +6 -3
  24. package/demo/config.js +10 -11
  25. package/demo/custom.js +39 -0
  26. package/demo/demo.less +0 -1
  27. package/demo/demo_utils.js +0 -1
  28. package/demo/locales/en.json +6 -3
  29. package/demo/locales/source.json +22 -10
  30. package/demo/main.js +9 -6
  31. package/demo/search.js +2 -1
  32. package/dist/controls.css +3 -3
  33. package/dist/controls.css.map +1 -1
  34. package/dist/demo.compiled.debug.js +71 -64
  35. package/dist/demo.compiled.debug.map +3 -3
  36. package/dist/demo.compiled.js +71 -64
  37. package/dist/demo.compiled.map +3 -3
  38. package/dist/demo.css +1 -1
  39. package/dist/demo.css.map +1 -1
  40. package/dist/deps.js +17 -20
  41. package/dist/locales.js +33 -31
  42. package/dist/receiver.compiled.debug.js +32 -28
  43. package/dist/receiver.compiled.debug.map +3 -3
  44. package/dist/receiver.compiled.js +32 -28
  45. package/dist/receiver.compiled.map +3 -3
  46. package/dist/shaka-player.compiled.d.ts +311 -314
  47. package/dist/shaka-player.compiled.debug.d.ts +311 -314
  48. package/dist/shaka-player.compiled.debug.externs.js +126 -126
  49. package/dist/shaka-player.compiled.debug.js +430 -484
  50. package/dist/shaka-player.compiled.debug.map +4 -4
  51. package/dist/shaka-player.compiled.externs.js +126 -126
  52. package/dist/shaka-player.compiled.js +829 -845
  53. package/dist/shaka-player.compiled.map +4 -4
  54. package/dist/shaka-player.ui.d.ts +357 -358
  55. package/dist/shaka-player.ui.debug.d.ts +357 -358
  56. package/dist/shaka-player.ui.debug.externs.js +134 -126
  57. package/dist/shaka-player.ui.debug.js +489 -541
  58. package/dist/shaka-player.ui.debug.map +4 -4
  59. package/dist/shaka-player.ui.externs.js +134 -126
  60. package/dist/shaka-player.ui.js +988 -1000
  61. package/dist/shaka-player.ui.map +4 -4
  62. package/docs/tutorials/config.md +0 -2
  63. package/docs/tutorials/drm-config.md +5 -0
  64. package/docs/tutorials/fairplay.md +7 -22
  65. package/docs/tutorials/faq.md +0 -11
  66. package/docs/tutorials/index.json +2 -8
  67. package/docs/tutorials/plugins.md +1 -3
  68. package/docs/tutorials/upgrade.md +85 -11
  69. package/externs/polyfill.js +15 -0
  70. package/externs/shaka/manifest.js +5 -1
  71. package/externs/shaka/net.js +12 -0
  72. package/externs/shaka/offline.js +5 -1
  73. package/externs/shaka/player.js +39 -21
  74. package/externs/shaka/text.js +12 -12
  75. package/externs/sourcebuffer.js +15 -0
  76. package/lib/abr/simple_abr_manager.js +2 -1
  77. package/lib/ads/client_side_ad.js +13 -2
  78. package/lib/ads/client_side_ad_manager.js +22 -4
  79. package/lib/cast/cast_utils.js +0 -1
  80. package/lib/dash/content_protection.js +85 -5
  81. package/lib/dash/dash_parser.js +1 -0
  82. package/lib/hls/hls_parser.js +390 -747
  83. package/lib/hls/manifest_text_parser.js +2 -3
  84. package/lib/media/drm_engine.js +105 -37
  85. package/lib/media/gap_jumping_controller.js +10 -45
  86. package/lib/media/media_source_engine.js +150 -30
  87. package/lib/media/playhead.js +2 -5
  88. package/lib/media/presentation_timeline.js +1 -2
  89. package/lib/media/segment_index.js +13 -46
  90. package/lib/media/segment_reference.js +47 -1
  91. package/lib/media/streaming_engine.js +28 -11
  92. package/lib/media/time_ranges_utils.js +4 -9
  93. package/lib/net/networking_engine.js +3 -0
  94. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  95. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  96. package/lib/offline/manifest_converter.js +1 -0
  97. package/lib/offline/storage.js +8 -41
  98. package/lib/player.js +17 -201
  99. package/lib/polyfill/media_capabilities.js +12 -6
  100. package/lib/polyfill/mediasource.js +0 -28
  101. package/lib/polyfill/patchedmediakeys_nop.js +2 -0
  102. package/lib/polyfill/patchedmediakeys_webkit.js +2 -0
  103. package/lib/text/cue.js +0 -6
  104. package/lib/text/lrc_text_parser.js +8 -0
  105. package/lib/text/mp4_ttml_parser.js +8 -0
  106. package/lib/text/mp4_vtt_parser.js +8 -0
  107. package/lib/text/sbv_text_parser.js +8 -0
  108. package/lib/text/simple_text_displayer.js +1 -7
  109. package/lib/text/srt_text_parser.js +8 -0
  110. package/lib/text/ssa_text_parser.js +8 -0
  111. package/lib/text/text_engine.js +19 -3
  112. package/lib/text/ttml_text_parser.js +8 -0
  113. package/lib/text/ui_text_displayer.js +1 -7
  114. package/lib/text/vtt_text_parser.js +27 -5
  115. package/lib/text/web_vtt_generator.js +1 -7
  116. package/lib/util/error.js +9 -13
  117. package/lib/util/fairplay_utils.js +109 -0
  118. package/lib/util/functional.js +0 -42
  119. package/lib/util/mime_utils.js +16 -5
  120. package/lib/util/platform.js +45 -0
  121. package/lib/util/player_configuration.js +17 -6
  122. package/lib/util/pssh.js +23 -4
  123. package/lib/util/stream_utils.js +92 -22
  124. package/lib/util/uint8array_utils.js +0 -16
  125. package/lib/util/xml_utils.js +1 -1
  126. package/package.json +5 -2
  127. package/roadmap.md +19 -19
  128. package/shaka-player.uncompiled.js +0 -3
  129. package/test/dash/dash_parser_content_protection_unit.js +44 -0
  130. package/test/dash/dash_parser_segment_template_unit.js +3 -4
  131. package/test/demo/demo_unit.js +2 -1
  132. package/test/hls/hls_live_unit.js +155 -230
  133. package/test/hls/hls_parser_unit.js +515 -432
  134. package/test/media/drm_engine_unit.js +86 -120
  135. package/test/media/media_source_engine_integration.js +25 -3
  136. package/test/media/media_source_engine_unit.js +3 -2
  137. package/test/media/playhead_unit.js +27 -191
  138. package/test/media/segment_index_unit.js +15 -25
  139. package/test/media/streaming_engine_integration.js +2 -39
  140. package/test/media/streaming_engine_unit.js +3 -2
  141. package/test/media/time_ranges_utils_unit.js +0 -5
  142. package/test/offline/manifest_convert_unit.js +34 -4
  143. package/test/offline/offline_manifest_parser_unit.js +1 -0
  144. package/test/offline/storage_integration.js +5 -4
  145. package/test/player_external.js +0 -6
  146. package/test/player_integration.js +16 -0
  147. package/test/player_unit.js +26 -0
  148. package/test/test/util/fake_media_source_engine.js +11 -4
  149. package/test/test/util/manifest_generator.js +3 -1
  150. package/test/test/util/manifest_parser_util.js +4 -1
  151. package/test/test/util/offline_utils.js +1 -0
  152. package/test/test/util/streaming_engine_util.js +1 -0
  153. package/test/test/util/test_scheme.js +24 -1
  154. package/test/test/util/util.js +4 -4
  155. package/test/text/cue_integration.js +2 -2
  156. package/test/text/lrc_text_parser_unit.js +6 -7
  157. package/test/text/mp4_ttml_parser_unit.js +6 -4
  158. package/test/text/mp4_vtt_parser_unit.js +6 -5
  159. package/test/text/sbv_text_parser_unit.js +5 -6
  160. package/test/text/srt_text_parser_unit.js +5 -6
  161. package/test/text/ssa_text_parser_unit.js +17 -29
  162. package/test/text/text_engine_unit.js +45 -5
  163. package/test/text/ttml_text_parser_unit.js +77 -77
  164. package/test/text/vtt_text_parser_unit.js +116 -59
  165. package/test/ui/ui_integration.js +0 -16
  166. package/test/ui/ui_unit.js +27 -0
  167. package/test/util/cmcd_manager_unit.js +3 -0
  168. package/test/util/stream_utils_unit.js +23 -7
  169. package/ui/controls.js +65 -40
  170. package/ui/fullscreen_button.js +26 -6
  171. package/ui/less/containers.less +4 -4
  172. package/ui/less/general.less +1 -1
  173. package/ui/less/range_elements.less +1 -0
  174. package/ui/locales/en.json +1 -0
  175. package/ui/locales/source.json +5 -0
  176. package/ui/resolution_selection.js +31 -33
  177. package/ui/ui.js +0 -17
  178. package/.github/pull_request_template.md +0 -10
  179. package/docs/tutorials/upgrade-v2-5.md +0 -441
  180. package/docs/tutorials/upgrade-v3.md +0 -38
  181. package/lib/polyfill/mathround.js +0 -49
  182. package/lib/polyfill/patchedmediakeys_apple.js +0 -744
  183. package/lib/polyfill/patchedmediakeys_ms.js +0 -698
  184. package/test/util/functional_unit.js +0 -82
@@ -22,6 +22,12 @@ goog.require('shaka.util.XmlUtils');
22
22
  * @export
23
23
  */
24
24
  shaka.text.VttTextParser = class {
25
+ /** Constructs a VTT parser. */
26
+ constructor() {
27
+ /** @private {boolean} */
28
+ this.sequenceMode_ = false;
29
+ }
30
+
25
31
  /**
26
32
  * @override
27
33
  * @export
@@ -30,6 +36,14 @@ shaka.text.VttTextParser = class {
30
36
  goog.asserts.assert(false, 'VTT does not have init segments');
31
37
  }
32
38
 
39
+ /**
40
+ * @override
41
+ * @export
42
+ */
43
+ setSequenceMode(sequenceMode) {
44
+ this.sequenceMode_ = sequenceMode;
45
+ }
46
+
33
47
  /**
34
48
  * @override
35
49
  * @export
@@ -48,11 +62,21 @@ shaka.text.VttTextParser = class {
48
62
  shaka.util.Error.Code.INVALID_TEXT_HEADER);
49
63
  }
50
64
 
65
+ // Depending on "segmentRelativeVttTiming" configuration,
66
+ // "vttOffset" will correspond to either "periodStart" (default)
67
+ // or "segmentStart", for segmented VTT where timings are relative
68
+ // to the beginning of each segment.
51
69
  // NOTE: "periodStart" is the timestamp offset applied via TextEngine.
52
70
  // It is no longer closely tied to periods, but the name stuck around.
53
- let offset = time.periodStart;
54
-
55
- if (blocks[0].includes('X-TIMESTAMP-MAP')) {
71
+ // NOTE: This offset and the flag choosing its meaning have no effect on
72
+ // HLS content, which should use X-TIMESTAMP-MAP and periodStart instead.
73
+ let offset = time.vttOffset;
74
+
75
+ // Only use 'X-TIMESTAMP-MAP' in sequence mode, as that is currently
76
+ // shorthand for HLS. Note that an offset based on the first video
77
+ // timestamp has already been extracted, and appears in periodStart.
78
+ // The relative offset from X-TIMESTAMP-MAP will be added to that for HLS.
79
+ if (blocks[0].includes('X-TIMESTAMP-MAP') && this.sequenceMode_) {
56
80
  // https://bit.ly/2K92l7y
57
81
  // The 'X-TIMESTAMP-MAP' header is used in HLS to align text with
58
82
  // the rest of the media.
@@ -87,8 +111,6 @@ shaka.text.VttTextParser = class {
87
111
  mpegTime += shaka.text.VttTextParser.TS_ROLLOVER_;
88
112
  }
89
113
 
90
- // Apple-encoded HLS content uses absolute timestamps, so assume the
91
- // presence of the map tag means the content uses absolute timestamps.
92
114
  offset = time.periodStart + mpegTime / mpegTimescale - cueTime;
93
115
  }
94
116
  }
@@ -6,7 +6,6 @@
6
6
 
7
7
  goog.provide('shaka.text.WebVttGenerator');
8
8
 
9
- goog.require('shaka.Deprecate');
10
9
  goog.require('shaka.text.Cue');
11
10
 
12
11
 
@@ -49,12 +48,7 @@ shaka.text.WebVttGenerator = class {
49
48
  return `${acc}</${tag}>`;
50
49
  }, '');
51
50
 
52
- if (cue.lineBreak || cue.spacer) {
53
- if (cue.spacer) {
54
- shaka.Deprecate.deprecateFeature(4,
55
- 'shaka.text.Cue',
56
- 'Please use lineBreak instead of spacer.');
57
- }
51
+ if (cue.lineBreak) {
58
52
  // This is a vertical lineBreak, so insert a newline.
59
53
  return '\n';
60
54
  } else if (cue.nestedCues.length) {
package/lib/util/error.js CHANGED
@@ -588,13 +588,7 @@ shaka.util.Error.Code = {
588
588
 
589
589
  // RETIRED: 'HLS_COULD_NOT_GUESS_MIME_TYPE': 4021,
590
590
 
591
- /**
592
- * No Master Playlist has been provided. Master playlist provides
593
- * vital information about the streams (like codecs) that is
594
- * required for MediaSource. We don't support directly providing
595
- * a Media Playlist.
596
- */
597
- 'HLS_MASTER_PLAYLIST_NOT_PROVIDED': 4022,
591
+ // RETIRED: 'HLS_MASTER_PLAYLIST_NOT_PROVIDED': 4022,
598
592
 
599
593
  /**
600
594
  * One of the required attributes was not provided, so the
@@ -634,12 +628,7 @@ shaka.util.Error.Code = {
634
628
 
635
629
  // RETIRED: 'HLS_LIVE_CONTENT_NOT_SUPPORTED': 4029,
636
630
 
637
- /**
638
- * The HLS parser was unable to parse segment start time from the media.
639
- * <br> error.data[0] is the failed media playlist URI.
640
- * <br> error.data[1] is the failed media segment URI (if any).
641
- */
642
- 'HLS_COULD_NOT_PARSE_SEGMENT_START_TIME': 4030,
631
+ // RETIRED: 'HLS_COULD_NOT_PARSE_SEGMENT_START_TIME': 4030,
643
632
 
644
633
  // RETIRED: 'HLS_MEDIA_SEQUENCE_REQUIRED_IN_LIVE_STREAMS': 4031,
645
634
 
@@ -693,6 +682,13 @@ shaka.util.Error.Code = {
693
682
  */
694
683
  'HLS_VARIABLE_NOT_FOUND': 4039,
695
684
 
685
+ /**
686
+ * We do not support playing encrypted mp2t with MSE
687
+ */
688
+ 'HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED': 4040,
689
+
690
+ // RETIRED: 'HLS_MSE_ENCRYPTED_LEGACY_APPLE_MEDIA_KEYS_NOT_SUPPORTED': 4041,
691
+
696
692
 
697
693
  // RETIRED: 'INCONSISTENT_BUFFER_STATE': 5000,
698
694
  // RETIRED: 'INVALID_SEGMENT_INDEX': 5001,
@@ -8,9 +8,11 @@ goog.provide('shaka.util.FairPlayUtils');
8
8
 
9
9
  goog.require('goog.Uri');
10
10
  goog.require('goog.asserts');
11
+ goog.require('shaka.net.NetworkingEngine');
11
12
  goog.require('shaka.util.BufferUtils');
12
13
  goog.require('shaka.util.Error');
13
14
  goog.require('shaka.util.StringUtils');
15
+ goog.require('shaka.util.Uint8ArrayUtils');
14
16
 
15
17
 
16
18
  /**
@@ -18,6 +20,29 @@ goog.require('shaka.util.StringUtils');
18
20
  * @export
19
21
  */
20
22
  shaka.util.FairPlayUtils = class {
23
+ /**
24
+ * Check if FairPlay is supported.
25
+ *
26
+ * @return {!Promise.<boolean>}
27
+ * @export
28
+ */
29
+ static async isFairPlaySupported() {
30
+ const config = {
31
+ initDataTypes: ['cenc', 'sinf', 'skd'],
32
+ videoCapabilities: [
33
+ {
34
+ contentType: 'video/mp4; codecs="avc1.42E01E"',
35
+ },
36
+ ],
37
+ };
38
+ try {
39
+ await navigator.requestMediaKeySystemAccess('com.apple.fps', [config]);
40
+ return true;
41
+ } catch (err) {
42
+ return false;
43
+ }
44
+ }
45
+
21
46
  /**
22
47
  * Using the default method, extract a content ID from the init data. This is
23
48
  * based on the FairPlay example documentation.
@@ -106,4 +131,88 @@ shaka.util.FairPlayUtils = class {
106
131
  offset == rebuiltInitData.length, 'Inconsistent init data length');
107
132
  return rebuiltInitData;
108
133
  }
134
+
135
+ /**
136
+ * SPC FairPlay request.
137
+ *
138
+ * @param {shaka.net.NetworkingEngine.RequestType} type
139
+ * @param {shaka.extern.Request} request
140
+ * @export
141
+ */
142
+ static spcFairPlayRequest(type, request) {
143
+ if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
144
+ return;
145
+ }
146
+ const body = /** @type {!(ArrayBuffer|ArrayBufferView)} */(request.body);
147
+ const originalPayload = shaka.util.BufferUtils.toUint8(body);
148
+ const base64Payload = shaka.util.Uint8ArrayUtils.toBase64(originalPayload);
149
+ request.headers['Content-Type'] = 'application/x-www-form-urlencoded';
150
+ request.body = shaka.util.StringUtils.toUTF8('spc=' + base64Payload);
151
+ }
152
+
153
+ /**
154
+ * Common FairPlay response transform for some DRMs providers.
155
+ *
156
+ * @param {shaka.net.NetworkingEngine.RequestType} type
157
+ * @param {shaka.extern.Response} response
158
+ * @export
159
+ */
160
+ static commonFairPlayResponse(type, response) {
161
+ if (type !== shaka.net.NetworkingEngine.RequestType.LICENSE) {
162
+ return;
163
+ }
164
+
165
+ // In Apple's docs, responses can be of the form:
166
+ // '\n<ckc>base64encoded</ckc>\n' or 'base64encoded'
167
+ // We have also seen responses in JSON format from some of our partners.
168
+ // In all of these text-based formats, the CKC data is base64-encoded.
169
+
170
+ let responseText;
171
+ try {
172
+ // Convert it to text for further processing.
173
+ responseText = shaka.util.StringUtils.fromUTF8(response.data);
174
+ } catch (error) {
175
+ // Assume it's not a text format of any kind and leave it alone.
176
+ return;
177
+ }
178
+
179
+ let licenseProcessing = false;
180
+
181
+ // Trim whitespace.
182
+ responseText = responseText.trim();
183
+
184
+ // Look for <ckc> wrapper and remove it.
185
+ if (responseText.substr(0, 5) === '<ckc>' &&
186
+ responseText.substr(-6) === '</ckc>') {
187
+ responseText = responseText.slice(5, -6);
188
+ licenseProcessing = true;
189
+ }
190
+
191
+ // Look for a JSON wrapper and remove it.
192
+ try {
193
+ const responseObject = /** @type {!Object} */(JSON.parse(responseText));
194
+ if (responseObject['ckc']) {
195
+ responseText = responseObject['ckc'];
196
+ licenseProcessing = true;
197
+ }
198
+ if (responseObject['CkcMessage']) {
199
+ responseText = responseObject['CkcMessage'];
200
+ licenseProcessing = true;
201
+ }
202
+ if (responseObject['License']) {
203
+ responseText = responseObject['License'];
204
+ licenseProcessing = true;
205
+ }
206
+ } catch (err) {
207
+ // It wasn't JSON. Fall through with other transformations.
208
+ }
209
+
210
+ if (licenseProcessing) {
211
+ // Decode the base64-encoded data into the format the browser expects.
212
+ // It's not clear why FairPlay license servers don't just serve this
213
+ // directly.
214
+ response.data = shaka.util.BufferUtils.toArrayBuffer(
215
+ shaka.util.Uint8ArrayUtils.fromBase64(responseText));
216
+ }
217
+ }
109
218
  };
@@ -6,9 +6,6 @@
6
6
 
7
7
  goog.provide('shaka.util.Functional');
8
8
 
9
- goog.require('shaka.Deprecate');
10
-
11
-
12
9
  /**
13
10
  * @summary A set of functional utility functions.
14
11
  */
@@ -70,43 +67,4 @@ shaka.util.Functional = class {
70
67
  static isNotNull(value) {
71
68
  return value != null;
72
69
  }
73
-
74
- /**
75
- * Calls a factory function while allowing it to be a constructor for
76
- * reverse-compatibility.
77
- *
78
- * @param {function():!T} factory
79
- * @return {!T}
80
- * @template T
81
- */
82
- static callFactory(factory) {
83
- // See https://stackoverflow.com/q/10428603/1208502
84
- // eslint-disable-next-line no-restricted-syntax
85
- const obj = Object.create(factory.prototype || Object.prototype);
86
- // If this is a constructor, call it with our newly created object to
87
- // initialize it; if this isn't a constructor, the "this" shouldn't be used
88
- // since it should be "undefined".
89
- let ret;
90
- try {
91
- ret = factory.call(obj); // eslint-disable-line no-restricted-syntax
92
-
93
- // If it didn't return anything, assume it is a constructor and return our
94
- // "this" value instead.
95
- if (!ret) {
96
- shaka.Deprecate.deprecateFeature(4,
97
- 'Factories requiring new',
98
- 'Factories should be plain functions');
99
- ret = obj;
100
- }
101
- } catch (e) {
102
- // This was an ES6 class, so it threw a TypeError because we didn't use
103
- // "new". Fall back to actually using "new".
104
- shaka.Deprecate.deprecateFeature(4,
105
- 'Factories requiring new',
106
- 'Factories should be plain functions');
107
- const FactoryAsClass = /** @type {function(new: T)} */(factory);
108
- ret = new FactoryAsClass();
109
- }
110
- return ret;
111
- }
112
70
  };
@@ -8,9 +8,11 @@ goog.provide('shaka.util.MimeUtils');
8
8
 
9
9
  goog.require('shaka.dependencies');
10
10
  goog.require('shaka.media.Transmuxer');
11
+ goog.require('shaka.util.ManifestParserUtils');
11
12
 
12
13
  /**
13
14
  * @summary A set of utility functions for dealing with MIME types.
15
+ * @export
14
16
  */
15
17
  shaka.util.MimeUtils = class {
16
18
  /**
@@ -20,6 +22,7 @@ shaka.util.MimeUtils = class {
20
22
  * @param {string} mimeType
21
23
  * @param {string=} codecs
22
24
  * @return {string}
25
+ * @export
23
26
  */
24
27
  static getFullType(mimeType, codecs) {
25
28
  let fullMimeType = mimeType;
@@ -32,6 +35,8 @@ shaka.util.MimeUtils = class {
32
35
  /**
33
36
  * Takes a MIME type and a codecs string and produces the full MIME
34
37
  * type. If it's a transport stream, convert its codecs to MP4 codecs.
38
+ * Otherwise for multiplexed content, convert the video MIME types to
39
+ * their audio equivalents if the content type is audio.
35
40
  *
36
41
  * @param {string} mimeType
37
42
  * @param {string} codecs
@@ -40,13 +45,19 @@ shaka.util.MimeUtils = class {
40
45
  */
41
46
  static getFullOrConvertedType(mimeType, codecs, contentType) {
42
47
  const fullMimeType = shaka.util.MimeUtils.getFullType(mimeType, codecs);
48
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
43
49
 
44
- if (!shaka.dependencies.muxjs() ||
45
- !shaka.media.Transmuxer.isTsContainer(fullMimeType)) {
46
- return fullMimeType;
50
+ if (shaka.media.Transmuxer.isTsContainer(fullMimeType)) {
51
+ if (shaka.dependencies.muxjs()) {
52
+ return shaka.media.Transmuxer.convertTsCodecs(
53
+ contentType, fullMimeType);
54
+ }
55
+ } else if (contentType == ContentType.AUDIO) {
56
+ // video/mp2t is the correct mime type for TS audio, so only replace the
57
+ // word "video" with "audio" for non-TS audio content.
58
+ return fullMimeType.replace('video', 'audio');
47
59
  }
48
-
49
- return shaka.media.Transmuxer.convertTsCodecs(contentType, fullMimeType);
60
+ return fullMimeType;
50
61
  }
51
62
 
52
63
 
@@ -142,6 +142,18 @@ shaka.util.Platform = class {
142
142
  return shaka.util.Platform.userAgentContains_('Web0S');
143
143
  }
144
144
 
145
+ /**
146
+ * Check if the current platform is a WebOS 3.
147
+ *
148
+ * @return {boolean}
149
+ */
150
+ static isWebOS3() {
151
+ // See: http://webostv.developer.lge.com/discover/specifications/web-engine/
152
+ return shaka.util.Platform.userAgentContains_('Web0S') &&
153
+ shaka.util.Platform.userAgentContains_(
154
+ 'Chrome/38.0.2125.122 Safari/537.36');
155
+ }
156
+
145
157
  /**
146
158
  * Check if the current platform is a Google Chromecast.
147
159
  *
@@ -151,6 +163,16 @@ shaka.util.Platform = class {
151
163
  return shaka.util.Platform.userAgentContains_('CrKey');
152
164
  }
153
165
 
166
+ /**
167
+ * Check if the current platform is a Android-based Cast devices.
168
+ *
169
+ * @return {boolean}
170
+ */
171
+ static isAndroidCastDevice() {
172
+ return shaka.util.Platform.isChromecast() &&
173
+ shaka.util.Platform.userAgentContains_('Android');
174
+ }
175
+
154
176
  /**
155
177
  * Check if the current platform is Google Chrome.
156
178
  *
@@ -228,6 +250,16 @@ shaka.util.Platform = class {
228
250
  return null;
229
251
  }
230
252
 
253
+ /**
254
+ * Check if the current platform is Apple Safari
255
+ * or Safari-based iOS browsers.
256
+ *
257
+ * @return {boolean}
258
+ */
259
+ static isSafari() {
260
+ return !!shaka.util.Platform.safariVersion();
261
+ }
262
+
231
263
  /**
232
264
  * Guesses if the platform is a mobile one (iOS or Android).
233
265
  *
@@ -318,6 +350,19 @@ shaka.util.Platform = class {
318
350
  const Platform = shaka.util.Platform;
319
351
  return Platform.isTizen() || Platform.isXboxOne();
320
352
  }
353
+
354
+ /**
355
+ * Returns true if MediaKeys is polyfilled
356
+ *
357
+ * @return {boolean}
358
+ */
359
+ static isMediaKeysPolyfilled() {
360
+ if (window.shakaMediaKeysPolyfill) {
361
+ return true;
362
+ }
363
+
364
+ return false;
365
+ }
321
366
  };
322
367
 
323
368
  /** @private {shaka.util.Timer} */
@@ -9,7 +9,6 @@ goog.provide('shaka.util.PlayerConfiguration');
9
9
  goog.require('goog.asserts');
10
10
  goog.require('shaka.abr.SimpleAbrManager');
11
11
  goog.require('shaka.log');
12
- goog.require('shaka.media.DrmEngine');
13
12
  goog.require('shaka.net.NetworkingEngine');
14
13
  goog.require('shaka.util.ConfigUtils');
15
14
  goog.require('shaka.util.LanguageUtils');
@@ -22,7 +21,10 @@ goog.require('shaka.util.Platform');
22
21
  * @export
23
22
  */
24
23
  shaka.util.PlayerConfiguration = class {
25
- /** @return {shaka.extern.PlayerConfiguration} */
24
+ /**
25
+ * @return {shaka.extern.PlayerConfiguration}
26
+ * @export
27
+ */
26
28
  static createDefault() {
27
29
  // This is a relatively safe default in the absence of clues from the
28
30
  // browser. For slower connections, the default estimate may be too high.
@@ -64,7 +66,11 @@ shaka.util.PlayerConfiguration = class {
64
66
  clearKeys: {}, // key is arbitrary key system ID, value must be string
65
67
  advanced: {}, // key is arbitrary key system ID, value is a record type
66
68
  delayLicenseRequestUntilPlayed: false,
67
- initDataTransform: shaka.media.DrmEngine.defaultInitDataTransform,
69
+ initDataTransform: (initData, initDataType, drmInfo) => {
70
+ return shaka.util.ConfigUtils.referenceParametersAndReturn(
71
+ [initData, initDataType, drmInfo],
72
+ initData);
73
+ },
68
74
  logLicenseExchange: false,
69
75
  updateExpirationTime: 1,
70
76
  preferredKeySystems: [],
@@ -78,6 +84,7 @@ shaka.util.PlayerConfiguration = class {
78
84
  disableText: false,
79
85
  disableThumbnails: false,
80
86
  defaultPresentationDelay: 0,
87
+ segmentRelativeVttTiming: false,
81
88
  dash: {
82
89
  clockSyncUri: '',
83
90
  ignoreDrmInfo: false,
@@ -92,6 +99,8 @@ shaka.util.PlayerConfiguration = class {
92
99
  keySystemsByURI: {
93
100
  'urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b':
94
101
  'org.w3.clearkey',
102
+ 'urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e':
103
+ 'org.w3.clearkey',
95
104
  'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed':
96
105
  'com.widevine.alpha',
97
106
  'urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95':
@@ -110,9 +119,11 @@ shaka.util.PlayerConfiguration = class {
110
119
  hls: {
111
120
  ignoreTextStreamFailures: false,
112
121
  ignoreImageStreamFailures: false,
113
- useFullSegmentsForStartTime: false,
114
122
  defaultAudioCodec: 'mp4a.40.2',
115
123
  defaultVideoCodec: 'avc1.42E01E',
124
+ ignoreManifestProgramDateTime: false,
125
+ mediaPlaylistFullMimeType:
126
+ 'video/mp2t; codecs="avc1.42E01E, mp4a.40.2"',
116
127
  },
117
128
  };
118
129
 
@@ -136,8 +147,6 @@ shaka.util.PlayerConfiguration = class {
136
147
  alwaysStreamText: false,
137
148
  startAtSegmentBoundary: false,
138
149
  gapDetectionThreshold: 0.1,
139
- smallGapLimit: 0.5,
140
- jumpLargeGaps: false,
141
150
  durationBackoff: 1,
142
151
  forceTransmuxTS: false,
143
152
  // Offset by 5 seconds since Chromecast takes a few seconds to start
@@ -213,6 +222,8 @@ shaka.util.PlayerConfiguration = class {
213
222
  // unexpected behaviours when someone tries to plays downloaded content
214
223
  // without a persistent license.
215
224
  usePersistentLicense: true,
225
+
226
+ numberOfParallelDownloads: 5,
216
227
  };
217
228
 
218
229
  const abr = {
package/lib/util/pssh.js CHANGED
@@ -90,16 +90,21 @@ shaka.util.Pssh = class {
90
90
  }
91
91
 
92
92
  /**
93
- * Creates a pssh blob from the given system ID and data.
93
+ * Creates a pssh blob from the given system ID, data, keyIds and version.
94
94
  *
95
95
  * @param {!Uint8Array} data
96
96
  * @param {!Uint8Array} systemId
97
+ * @param {!Set.<string>} keyIds
98
+ * @param {number} version
97
99
  * @return {!Uint8Array}
98
100
  */
99
- static createPssh(data, systemId) {
101
+ static createPssh(data, systemId, keyIds, version) {
100
102
  goog.asserts.assert(systemId.byteLength == 16, 'Invalid system ID length');
101
103
  const dataLength = data.length;
102
- const psshSize = 0x4 + 0x4 + 0x4 + systemId.length + 0x4 + dataLength;
104
+ let psshSize = 0x4 + 0x4 + 0x4 + systemId.length + 0x4 + dataLength;
105
+ if (version > 0) {
106
+ psshSize += 0x4 + (16 * keyIds.size);
107
+ }
103
108
 
104
109
  /** @type {!Uint8Array} */
105
110
  const psshBox = new Uint8Array(psshSize);
@@ -111,10 +116,24 @@ shaka.util.Pssh = class {
111
116
  byteCursor += 0x4;
112
117
  psshData.setUint32(byteCursor, 0x70737368); // 'pssh'
113
118
  byteCursor += 0x4;
114
- psshData.setUint32(byteCursor, 0); // flags
119
+ (version < 1) ? psshData.setUint32(byteCursor, 0) :
120
+ psshData.setUint32(byteCursor, 0x01000000); // version + flags
115
121
  byteCursor += 0x4;
116
122
  psshBox.set(systemId, byteCursor);
117
123
  byteCursor += systemId.length;
124
+
125
+ // if version > 0, add KID count and kid values.
126
+ if (version > 0) {
127
+ psshData.setUint32(byteCursor, keyIds.size); // KID_count
128
+ byteCursor += 0x4;
129
+ const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
130
+ for (const keyId of keyIds) {
131
+ const KID = Uint8ArrayUtils.fromHex(keyId);
132
+ psshBox.set(KID, byteCursor);
133
+ byteCursor += KID.length;
134
+ }
135
+ }
136
+
118
137
  psshData.setUint32(byteCursor, dataLength);
119
138
  byteCursor += 0x4;
120
139
  psshBox.set(data, byteCursor);