shaka-player 4.7.13 → 4.8.1

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 (114) hide show
  1. package/AUTHORS +2 -0
  2. package/CONTRIBUTORS +2 -0
  3. package/LICENSE +54 -0
  4. package/README.md +22 -1
  5. package/dist/controls.css +1 -1
  6. package/dist/controls.css.map +1 -1
  7. package/dist/deps.js +34 -23
  8. package/dist/locales.js +41 -31
  9. package/dist/shaka-player.compiled.d.ts +196 -45
  10. package/dist/shaka-player.compiled.debug.d.ts +196 -45
  11. package/dist/shaka-player.compiled.debug.externs.js +491 -348
  12. package/dist/shaka-player.compiled.debug.js +969 -847
  13. package/dist/shaka-player.compiled.debug.map +4 -4
  14. package/dist/shaka-player.compiled.externs.js +491 -348
  15. package/dist/shaka-player.compiled.js +1238 -1171
  16. package/dist/shaka-player.compiled.map +4 -4
  17. package/dist/shaka-player.ui.d.ts +259 -48
  18. package/dist/shaka-player.ui.debug.d.ts +259 -48
  19. package/dist/shaka-player.ui.debug.externs.js +598 -377
  20. package/dist/shaka-player.ui.debug.js +1185 -980
  21. package/dist/shaka-player.ui.debug.map +4 -4
  22. package/dist/shaka-player.ui.externs.js +598 -377
  23. package/dist/shaka-player.ui.js +1526 -1408
  24. package/dist/shaka-player.ui.map +4 -4
  25. package/externs/device_sensor_event.js +18 -0
  26. package/externs/hisense.js +16 -0
  27. package/externs/playstation.js +31 -0
  28. package/externs/shaka/abr_manager.js +3 -1
  29. package/externs/shaka/ads.js +5 -0
  30. package/externs/shaka/codecs.js +13 -0
  31. package/externs/shaka/manifest.js +58 -6
  32. package/externs/shaka/net.js +13 -1
  33. package/externs/shaka/player.js +184 -13
  34. package/externs/shaka/text.js +19 -0
  35. package/externs/tizen.js +41 -0
  36. package/externs/webos.js +19 -0
  37. package/externs/xbox.js +43 -0
  38. package/lib/abr/simple_abr_manager.js +9 -1
  39. package/lib/ads/ad_manager.js +19 -2
  40. package/lib/ads/client_side_ad_manager.js +5 -3
  41. package/lib/ads/media_tailor_ad_manager.js +9 -0
  42. package/lib/cast/cast_receiver.js +0 -14
  43. package/lib/cast/cast_utils.js +1 -0
  44. package/lib/cea/mp4_cea_parser.js +6 -1
  45. package/lib/dash/content_protection.js +97 -53
  46. package/lib/dash/dash_parser.js +237 -177
  47. package/lib/dash/mpd_utils.js +72 -65
  48. package/lib/dash/segment_base.js +27 -21
  49. package/lib/dash/segment_list.js +18 -16
  50. package/lib/dash/segment_template.js +45 -22
  51. package/lib/hls/hls_parser.js +358 -164
  52. package/lib/media/buffering_observer.js +25 -1
  53. package/lib/media/drm_engine.js +91 -71
  54. package/lib/media/manifest_filterer.js +220 -0
  55. package/lib/media/media_source_engine.js +34 -5
  56. package/lib/media/preload_manager.js +827 -0
  57. package/lib/media/presentation_timeline.js +11 -0
  58. package/lib/media/segment_index.js +93 -47
  59. package/lib/media/segment_prefetch.js +140 -43
  60. package/lib/media/segment_reference.js +43 -8
  61. package/lib/media/segment_utils.js +208 -25
  62. package/lib/media/streaming_engine.js +355 -66
  63. package/lib/mss/content_protection.js +31 -25
  64. package/lib/mss/mss_parser.js +79 -55
  65. package/lib/net/networking_engine.js +49 -4
  66. package/lib/offline/storage.js +3 -3
  67. package/lib/player.js +882 -672
  68. package/lib/polyfill/media_capabilities.js +16 -1
  69. package/lib/text/simple_text_displayer.js +9 -0
  70. package/lib/text/stub_text_displayer.js +7 -0
  71. package/lib/text/text_engine.js +16 -3
  72. package/lib/text/ttml_text_parser.js +116 -114
  73. package/lib/text/ui_text_displayer.js +28 -11
  74. package/lib/text/vtt_text_parser.js +54 -115
  75. package/lib/transmuxer/opus.js +91 -0
  76. package/lib/transmuxer/ts_transmuxer.js +115 -0
  77. package/lib/util/cmcd_manager.js +153 -3
  78. package/lib/util/dom_utils.js +11 -0
  79. package/lib/util/error.js +5 -0
  80. package/lib/util/fake_event.js +2 -0
  81. package/lib/util/manifest_parser_utils.js +97 -3
  82. package/lib/util/mp4_box_parsers.js +346 -17
  83. package/lib/util/mp4_generator.js +23 -0
  84. package/lib/util/periods.js +19 -0
  85. package/lib/util/platform.js +161 -9
  86. package/lib/util/player_configuration.js +79 -13
  87. package/lib/util/stats.js +16 -0
  88. package/lib/util/stream_utils.js +22 -8
  89. package/lib/util/string_utils.js +36 -0
  90. package/lib/util/tXml.js +814 -0
  91. package/lib/util/ts_parser.js +50 -0
  92. package/lib/util/xml_utils.js +10 -338
  93. package/package.json +2 -2
  94. package/shaka-player.uncompiled.js +8 -0
  95. package/ui/controls.js +187 -5
  96. package/ui/enums.js +2 -0
  97. package/ui/externs/ui.js +30 -3
  98. package/ui/gl_matrix/matrix_4x4.js +568 -0
  99. package/ui/gl_matrix/matrix_quaternion.js +45 -0
  100. package/ui/less/containers.less +11 -0
  101. package/ui/locales/en-GB.json +2 -0
  102. package/ui/locales/en.json +2 -0
  103. package/ui/locales/es-419.json +2 -0
  104. package/ui/locales/es.json +2 -0
  105. package/ui/locales/source.json +8 -0
  106. package/ui/recenter_vr.js +126 -0
  107. package/ui/resolution_selection.js +25 -5
  108. package/ui/statistics_button.js +12 -0
  109. package/ui/text_selection.js +1 -1
  110. package/ui/toggle_stereoscopic.js +127 -0
  111. package/ui/ui.js +74 -38
  112. package/ui/vr_manager.js +557 -0
  113. package/ui/vr_utils.js +232 -0
  114. package/ui/vr_webgl.js +697 -0
@@ -11,8 +11,8 @@ goog.require('shaka.util.BufferUtils');
11
11
  goog.require('shaka.util.ManifestParserUtils');
12
12
  goog.require('shaka.util.Pssh');
13
13
  goog.require('shaka.util.StringUtils');
14
+ goog.require('shaka.util.TXml');
14
15
  goog.require('shaka.util.Uint8ArrayUtils');
15
- goog.require('shaka.util.XmlUtils');
16
16
 
17
17
 
18
18
  /**
@@ -23,19 +23,19 @@ shaka.mss.ContentProtection = class {
23
23
  /**
24
24
  * Parses info from the Protection elements.
25
25
  *
26
- * @param {!Array.<!Element>} elems
26
+ * @param {!Array.<!shaka.extern.xml.Node>} elems
27
27
  * @param {!Object.<string, string>} keySystemsBySystemId
28
28
  * @return {!Array.<shaka.extern.DrmInfo>}
29
29
  */
30
30
  static parseFromProtection(elems, keySystemsBySystemId) {
31
31
  const ContentProtection = shaka.mss.ContentProtection;
32
- const XmlUtils = shaka.util.XmlUtils;
32
+ const TXml = shaka.util.TXml;
33
33
 
34
- /** @type {!Array.<!Element>} */
34
+ /** @type {!Array.<!shaka.extern.xml.Node>} */
35
35
  let protectionHeader = [];
36
36
  for (const elem of elems) {
37
37
  protectionHeader = protectionHeader.concat(
38
- XmlUtils.findChildren(elem, 'ProtectionHeader'));
38
+ TXml.findChildren(elem, 'ProtectionHeader'));
39
39
  }
40
40
  if (!protectionHeader.length) {
41
41
  return [];
@@ -123,18 +123,19 @@ shaka.mss.ContentProtection = class {
123
123
  * Parse a PlayReady Header format: https://goo.gl/dBzxNA
124
124
  * a try to find the LA_URL value.
125
125
  *
126
- * @param {!Element} xml
126
+ * @param {!shaka.extern.xml.Node} xml
127
127
  * @return {string}
128
128
  * @private
129
129
  */
130
130
  static getLaurl_(xml) {
131
+ const TXml = shaka.util.TXml;
131
132
  // LA_URL element is optional and no more than one is
132
133
  // allowed inside the DATA element. Only absolute URLs are allowed.
133
134
  // If the LA_URL element exists, it must not be empty.
134
- for (const elem of xml.getElementsByTagName('DATA')) {
135
- const laUrl = shaka.util.XmlUtils.findChild(elem, 'LA_URL');
135
+ for (const elem of TXml.getElementsByTagName(xml, 'DATA')) {
136
+ const laUrl = TXml.findChild(elem, 'LA_URL');
136
137
  if (laUrl) {
137
- return laUrl.textContent;
138
+ return /** @type {string} */ (shaka.util.TXml.getTextContents(laUrl));
138
139
  }
139
140
  }
140
141
 
@@ -148,7 +149,7 @@ shaka.mss.ContentProtection = class {
148
149
  * Gets a PlayReady license URL from a protection element
149
150
  * containing a PlayReady Header Object
150
151
  *
151
- * @param {!Element} element
152
+ * @param {!shaka.extern.xml.Node} element
152
153
  * @return {string}
153
154
  */
154
155
  static getPlayReadyLicenseUrl(element) {
@@ -165,19 +166,21 @@ shaka.mss.ContentProtection = class {
165
166
  * Parse a PlayReady Header format: https://goo.gl/dBzxNA
166
167
  * a try to find the KID value.
167
168
  *
168
- * @param {!Element} xml
169
+ * @param {!shaka.extern.xml.Node} xml
169
170
  * @return {?string}
170
171
  * @private
171
172
  */
172
173
  static getKID_(xml) {
174
+ const TXml = shaka.util.TXml;
173
175
  // KID element is optional and no more than one is
174
176
  // allowed inside the DATA element.
175
- for (const elem of xml.getElementsByTagName('DATA')) {
176
- const kid = shaka.util.XmlUtils.findChild(elem, 'KID');
177
+ for (const elem of TXml.getElementsByTagName(xml, 'DATA')) {
178
+ const kid = TXml.findChild(elem, 'KID');
177
179
  if (kid) {
178
180
  // GUID: [DWORD, WORD, WORD, 8-BYTE]
179
181
  const guidBytes =
180
- shaka.util.Uint8ArrayUtils.fromBase64(kid.textContent);
182
+ shaka.util.Uint8ArrayUtils.fromBase64(
183
+ /** @type{string} */ (shaka.util.TXml.getTextContents(kid)));
181
184
  // Reverse byte order from little-endian to big-endian
182
185
  const kidBytes = new Uint8Array([
183
186
  guidBytes[3], guidBytes[2], guidBytes[1], guidBytes[0],
@@ -197,7 +200,7 @@ shaka.mss.ContentProtection = class {
197
200
  * Gets a PlayReady KID from a protection element
198
201
  * containing a PlayReady Header Object
199
202
  *
200
- * @param {!Element} element
203
+ * @param {!shaka.extern.xml.Node} element
201
204
  * @return {?string}
202
205
  * @private
203
206
  */
@@ -214,15 +217,16 @@ shaka.mss.ContentProtection = class {
214
217
  /**
215
218
  * Gets a PlayReady Header Object from a protection element
216
219
  *
217
- * @param {!Element} element
218
- * @return {?Element}
220
+ * @param {!shaka.extern.xml.Node} element
221
+ * @return {?shaka.extern.xml.Node}
219
222
  * @private
220
223
  */
221
224
  static getPlayReadyHeaderObject_(element) {
222
225
  const ContentProtection = shaka.mss.ContentProtection;
223
226
  const PLAYREADY_RECORD_TYPES = ContentProtection.PLAYREADY_RECORD_TYPES;
224
227
 
225
- const bytes = shaka.util.Uint8ArrayUtils.fromBase64(element.textContent);
228
+ const bytes = shaka.util.Uint8ArrayUtils.fromBase64(
229
+ /** @type{string} */ (shaka.util.TXml.getTextContents(element)));
226
230
  const records = ContentProtection.parseMsPro_(bytes);
227
231
  const record = records.filter((record) => {
228
232
  return record.type === PLAYREADY_RECORD_TYPES.RIGHTS_MANAGEMENT;
@@ -233,7 +237,7 @@ shaka.mss.ContentProtection = class {
233
237
  }
234
238
 
235
239
  const xml = shaka.util.StringUtils.fromUTF16(record.value, true);
236
- const rootElement = shaka.util.XmlUtils.parseXmlString(xml, 'WRMHEADER');
240
+ const rootElement = shaka.util.TXml.parseXmlString(xml, 'WRMHEADER');
237
241
  if (!rootElement) {
238
242
  return null;
239
243
  }
@@ -243,7 +247,7 @@ shaka.mss.ContentProtection = class {
243
247
  /**
244
248
  * Gets a initData from a protection element.
245
249
  *
246
- * @param {!Element} element
250
+ * @param {!shaka.extern.xml.Node} element
247
251
  * @param {string} systemID
248
252
  * @param {?string} keyId
249
253
  * @return {?Array.<shaka.extern.InitDataOverride>}
@@ -251,7 +255,8 @@ shaka.mss.ContentProtection = class {
251
255
  */
252
256
  static getInitDataFromPro_(element, systemID, keyId) {
253
257
  const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
254
- const data = Uint8ArrayUtils.fromBase64(element.textContent);
258
+ const data = Uint8ArrayUtils.fromBase64(
259
+ /** @type{string} */ (shaka.util.TXml.getTextContents(element)));
255
260
  const systemId = Uint8ArrayUtils.fromHex(systemID.replace(/-/g, ''));
256
261
  const keyIds = new Set();
257
262
  const psshVersion = 0;
@@ -269,7 +274,7 @@ shaka.mss.ContentProtection = class {
269
274
  /**
270
275
  * Creates DrmInfo objects from an array of elements.
271
276
  *
272
- * @param {!Array.<!Element>} elements
277
+ * @param {!Array.<!shaka.extern.xml.Node>} elements
273
278
  * @param {!Object.<string, string>} keySystemsBySystemId
274
279
  * @return {!Array.<shaka.extern.DrmInfo>}
275
280
  * @private
@@ -284,14 +289,15 @@ shaka.mss.ContentProtection = class {
284
289
 
285
290
  for (let i = 0; i < elements.length; i++) {
286
291
  const element = elements[i];
287
- const systemID = element.getAttribute('SystemID').toLowerCase();
292
+ const systemID = element.attributes['SystemID'].toLowerCase();
288
293
  const keySystem = keySystemsBySystemId[systemID];
289
294
  if (keySystem) {
290
295
  const KID = ContentProtection.getPlayReadyKID_(element);
291
296
  const initData = ContentProtection.getInitDataFromPro_(
292
297
  element, systemID, KID);
293
298
 
294
- const info = ManifestParserUtils.createDrmInfo(keySystem, initData);
299
+ const info = ManifestParserUtils.createDrmInfo(
300
+ keySystem, /* encryptionScheme= */ 'cenc', initData);
295
301
  if (KID) {
296
302
  info.keyIds.add(KID);
297
303
  }
@@ -338,7 +344,7 @@ shaka.mss.ContentProtection.PLAYREADY_RECORD_TYPES = {
338
344
  /**
339
345
  * A map of key system name to license server url parser.
340
346
  *
341
- * @const {!Map.<string, function(!Element)>}
347
+ * @const {!Map.<string, function(!shaka.extern.xml.Node)>}
342
348
  * @private
343
349
  */
344
350
  shaka.mss.ContentProtection.licenseUrlParsers_ = new Map()
@@ -7,6 +7,7 @@
7
7
  goog.provide('shaka.mss.MssParser');
8
8
 
9
9
  goog.require('goog.asserts');
10
+ goog.require('shaka.Deprecate');
10
11
  goog.require('shaka.abr.Ewma');
11
12
  goog.require('shaka.log');
12
13
  goog.require('shaka.media.InitSegmentReference');
@@ -22,7 +23,9 @@ goog.require('shaka.util.ManifestParserUtils');
22
23
  goog.require('shaka.util.MimeUtils');
23
24
  goog.require('shaka.util.Mp4Generator');
24
25
  goog.require('shaka.util.OperationManager');
26
+ goog.require('shaka.util.PlayerConfiguration');
25
27
  goog.require('shaka.util.Timer');
28
+ goog.require('shaka.util.TXml');
26
29
  goog.require('shaka.util.XmlUtils');
27
30
 
28
31
 
@@ -278,7 +281,27 @@ shaka.mss.MssParser = class {
278
281
  * @private
279
282
  */
280
283
  parseManifest_(data, finalManifestUri) {
281
- const mss = shaka.util.XmlUtils.parseXml(data, 'SmoothStreamingMedia');
284
+ let manifestData = data;
285
+ const manifestPreprocessor = this.config_.mss.manifestPreprocessor;
286
+ const defaultManifestPreprocessor =
287
+ shaka.util.PlayerConfiguration.defaultManifestPreprocessor;
288
+ if (manifestPreprocessor != defaultManifestPreprocessor) {
289
+ shaka.Deprecate.deprecateFeature(5,
290
+ 'manifest.mss.manifestPreprocessor configuration',
291
+ 'Please Use manifest.mss.manifestPreprocessorTXml instead.');
292
+ const mssElement =
293
+ shaka.util.XmlUtils.parseXml(manifestData, 'SmoothStreamingMedia');
294
+ if (!mssElement) {
295
+ throw new shaka.util.Error(
296
+ shaka.util.Error.Severity.CRITICAL,
297
+ shaka.util.Error.Category.MANIFEST,
298
+ shaka.util.Error.Code.MSS_INVALID_XML,
299
+ finalManifestUri);
300
+ }
301
+ manifestPreprocessor(mssElement);
302
+ manifestData = shaka.util.XmlUtils.toArrayBuffer(mssElement);
303
+ }
304
+ const mss = shaka.util.TXml.parseXml(manifestData, 'SmoothStreamingMedia');
282
305
  if (!mss) {
283
306
  throw new shaka.util.Error(
284
307
  shaka.util.Error.Severity.CRITICAL,
@@ -286,6 +309,12 @@ shaka.mss.MssParser = class {
286
309
  shaka.util.Error.Code.MSS_INVALID_XML,
287
310
  finalManifestUri);
288
311
  }
312
+ const manifestPreprocessorTXml = this.config_.mss.manifestPreprocessorTXml;
313
+ const defaultManifestPreprocessorTXml =
314
+ shaka.util.PlayerConfiguration.defaultManifestPreprocessorTXml;
315
+ if (manifestPreprocessorTXml != defaultManifestPreprocessorTXml) {
316
+ manifestPreprocessorTXml(mss);
317
+ }
289
318
  this.processManifest_(mss, finalManifestUri);
290
319
  return Promise.resolve();
291
320
  }
@@ -294,26 +323,21 @@ shaka.mss.MssParser = class {
294
323
  /**
295
324
  * Takes a formatted MSS and converts it into a manifest.
296
325
  *
297
- * @param {!Element} mss
326
+ * @param {!shaka.extern.xml.Node} mss
298
327
  * @param {string} finalManifestUri The final manifest URI, which may
299
328
  * differ from this.manifestUri_ if there has been a redirect.
300
329
  * @private
301
330
  */
302
331
  processManifest_(mss, finalManifestUri) {
303
- const XmlUtils = shaka.util.XmlUtils;
304
-
305
- const manifestPreprocessor = this.config_.mss.manifestPreprocessor;
306
- if (manifestPreprocessor) {
307
- manifestPreprocessor(mss);
308
- }
332
+ const TXml = shaka.util.TXml;
309
333
 
310
334
  if (!this.presentationTimeline_) {
311
335
  this.presentationTimeline_ = new shaka.media.PresentationTimeline(
312
336
  /* presentationStartTime= */ null, /* delay= */ 0);
313
337
  }
314
338
 
315
- const isLive = XmlUtils.parseAttr(mss, 'IsLive',
316
- XmlUtils.parseBoolean, /* defaultValue= */ false);
339
+ const isLive = TXml.parseAttr(mss, 'IsLive',
340
+ TXml.parseBoolean, /* defaultValue= */ false);
317
341
 
318
342
  if (isLive) {
319
343
  throw new shaka.util.Error(
@@ -324,21 +348,21 @@ shaka.mss.MssParser = class {
324
348
 
325
349
  this.presentationTimeline_.setStatic(!isLive);
326
350
 
327
- const timescale = XmlUtils.parseAttr(mss, 'TimeScale',
328
- XmlUtils.parseNonNegativeInt, shaka.mss.MssParser.DEFAULT_TIME_SCALE_);
351
+ const timescale = TXml.parseAttr(mss, 'TimeScale',
352
+ TXml.parseNonNegativeInt, shaka.mss.MssParser.DEFAULT_TIME_SCALE_);
329
353
  goog.asserts.assert(timescale && timescale >= 0,
330
354
  'Timescale must be defined!');
331
355
 
332
- let dvrWindowLength = XmlUtils.parseAttr(mss, 'DVRWindowLength',
333
- XmlUtils.parseNonNegativeInt);
356
+ let dvrWindowLength = TXml.parseAttr(mss, 'DVRWindowLength',
357
+ TXml.parseNonNegativeInt);
334
358
  // If the DVRWindowLength field is omitted for a live presentation or set
335
359
  // to 0, the DVR window is effectively infinite
336
360
  if (isLive && (dvrWindowLength === 0 || isNaN(dvrWindowLength))) {
337
361
  dvrWindowLength = Infinity;
338
362
  }
339
363
  // Start-over
340
- const canSeek = XmlUtils.parseAttr(mss, 'CanSeek',
341
- XmlUtils.parseBoolean, /* defaultValue= */ false);
364
+ const canSeek = TXml.parseAttr(mss, 'CanSeek',
365
+ TXml.parseBoolean, /* defaultValue= */ false);
342
366
  if (dvrWindowLength === 0 && canSeek) {
343
367
  dvrWindowLength = Infinity;
344
368
  }
@@ -363,8 +387,8 @@ shaka.mss.MssParser = class {
363
387
  segmentAvailabilityDuration);
364
388
 
365
389
  // Duration in timescale units.
366
- const duration = XmlUtils.parseAttr(mss, 'Duration',
367
- XmlUtils.parseNonNegativeInt, Infinity);
390
+ const duration = TXml.parseAttr(mss, 'Duration',
391
+ TXml.parseNonNegativeInt, Infinity);
368
392
  goog.asserts.assert(duration && duration >= 0,
369
393
  'Duration must be defined!');
370
394
 
@@ -414,25 +438,25 @@ shaka.mss.MssParser = class {
414
438
  }
415
439
 
416
440
  /**
417
- * @param {!Element} mss
441
+ * @param {!shaka.extern.xml.Node} mss
418
442
  * @param {!shaka.mss.MssParser.Context} context
419
443
  * @private
420
444
  */
421
445
  parseStreamIndexes_(mss, context) {
422
446
  const ContentProtection = shaka.mss.ContentProtection;
423
- const XmlUtils = shaka.util.XmlUtils;
447
+ const TXml = shaka.util.TXml;
424
448
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
425
449
 
426
- const protectionElems = XmlUtils.findChildren(mss, 'Protection');
450
+ const protectionElems = TXml.findChildren(mss, 'Protection');
427
451
  const drmInfos = ContentProtection.parseFromProtection(
428
452
  protectionElems, this.config_.mss.keySystemsBySystemId);
429
453
 
430
454
  const audioStreams = [];
431
455
  const videoStreams = [];
432
456
  const textStreams = [];
433
- const streamIndexes = XmlUtils.findChildren(mss, 'StreamIndex');
457
+ const streamIndexes = TXml.findChildren(mss, 'StreamIndex');
434
458
  for (const streamIndex of streamIndexes) {
435
- const qualityLevels = XmlUtils.findChildren(streamIndex, 'QualityLevel');
459
+ const qualityLevels = TXml.findChildren(streamIndex, 'QualityLevel');
436
460
  const timeline = this.createTimeline_(
437
461
  streamIndex, context.timescale, context.duration);
438
462
  // For each QualityLevel node, create a stream element
@@ -467,8 +491,8 @@ shaka.mss.MssParser = class {
467
491
  }
468
492
 
469
493
  /**
470
- * @param {!Element} streamIndex
471
- * @param {!Element} qualityLevel
494
+ * @param {!shaka.extern.xml.Node} streamIndex
495
+ * @param {!shaka.extern.xml.Node} qualityLevel
472
496
  * @param {!Array.<shaka.mss.MssParser.TimeRange>} timeline
473
497
  * @param {!Array.<shaka.extern.DrmInfo>} drmInfos
474
498
  * @param {!shaka.mss.MssParser.Context} context
@@ -476,11 +500,11 @@ shaka.mss.MssParser = class {
476
500
  * @private
477
501
  */
478
502
  createStream_(streamIndex, qualityLevel, timeline, drmInfos, context) {
479
- const XmlUtils = shaka.util.XmlUtils;
503
+ const TXml = shaka.util.TXml;
480
504
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
481
505
  const MssParser = shaka.mss.MssParser;
482
506
 
483
- const type = streamIndex.getAttribute('Type');
507
+ const type = streamIndex.attributes['Type'];
484
508
  const isValidType = type === 'audio' || type === 'video' ||
485
509
  type === 'text';
486
510
  if (!isValidType) {
@@ -488,19 +512,19 @@ shaka.mss.MssParser = class {
488
512
  return null;
489
513
  }
490
514
 
491
- const lang = streamIndex.getAttribute('Language');
515
+ const lang = streamIndex.attributes['Language'];
492
516
  const id = this.globalId_++;
493
517
 
494
- const bandwidth = XmlUtils.parseAttr(
495
- qualityLevel, 'Bitrate', XmlUtils.parsePositiveInt);
496
- const width = XmlUtils.parseAttr(
497
- qualityLevel, 'MaxWidth', XmlUtils.parsePositiveInt);
498
- const height = XmlUtils.parseAttr(
499
- qualityLevel, 'MaxHeight', XmlUtils.parsePositiveInt);
500
- const channelsCount = XmlUtils.parseAttr(
501
- qualityLevel, 'Channels', XmlUtils.parsePositiveInt);
502
- const audioSamplingRate = XmlUtils.parseAttr(
503
- qualityLevel, 'SamplingRate', XmlUtils.parsePositiveInt);
518
+ const bandwidth = TXml.parseAttr(
519
+ qualityLevel, 'Bitrate', TXml.parsePositiveInt);
520
+ const width = TXml.parseAttr(
521
+ qualityLevel, 'MaxWidth', TXml.parsePositiveInt);
522
+ const height = TXml.parseAttr(
523
+ qualityLevel, 'MaxHeight', TXml.parsePositiveInt);
524
+ const channelsCount = TXml.parseAttr(
525
+ qualityLevel, 'Channels', TXml.parsePositiveInt);
526
+ const audioSamplingRate = TXml.parseAttr(
527
+ qualityLevel, 'SamplingRate', TXml.parsePositiveInt);
504
528
 
505
529
  let duration = context.duration;
506
530
  if (timeline.length) {
@@ -516,7 +540,7 @@ shaka.mss.MssParser = class {
516
540
  /** @type {!shaka.extern.Stream} */
517
541
  const stream = {
518
542
  id: id,
519
- originalId: streamIndex.getAttribute('Name') || String(id),
543
+ originalId: streamIndex.attributes['Name'] || String(id),
520
544
  groupId: null,
521
545
  createSegmentIndex: () => Promise.resolve(),
522
546
  closeSegmentIndex: () => Promise.resolve(),
@@ -561,7 +585,7 @@ shaka.mss.MssParser = class {
561
585
  };
562
586
 
563
587
  // This is specifically for text tracks.
564
- const subType = streamIndex.getAttribute('Subtype');
588
+ const subType = streamIndex.attributes['Subtype'];
565
589
  if (subType) {
566
590
  const role = MssParser.ROLE_MAPPING_[subType];
567
591
  if (role) {
@@ -572,12 +596,12 @@ shaka.mss.MssParser = class {
572
596
  }
573
597
  }
574
598
 
575
- let fourCCValue = qualityLevel.getAttribute('FourCC');
599
+ let fourCCValue = qualityLevel.attributes['FourCC'];
576
600
 
577
601
  // If FourCC not defined at QualityLevel level,
578
602
  // then get it from StreamIndex level
579
603
  if (fourCCValue === null || fourCCValue === '') {
580
- fourCCValue = streamIndex.getAttribute('FourCC');
604
+ fourCCValue = streamIndex.attributes['FourCC'];
581
605
  }
582
606
 
583
607
  // If still not defined (optional for audio stream,
@@ -700,7 +724,7 @@ shaka.mss.MssParser = class {
700
724
  }
701
725
 
702
726
  /**
703
- * @param {!Element} qualityLevel
727
+ * @param {!shaka.extern.xml.Node} qualityLevel
704
728
  * @param {string} type
705
729
  * @param {string} fourCCValue
706
730
  * @param {!shaka.extern.Stream} stream
@@ -708,7 +732,7 @@ shaka.mss.MssParser = class {
708
732
  * @private
709
733
  */
710
734
  getCodecPrivateData_(qualityLevel, type, fourCCValue, stream) {
711
- const codecPrivateData = qualityLevel.getAttribute('CodecPrivateData');
735
+ const codecPrivateData = qualityLevel.attributes['CodecPrivateData'];
712
736
  if (codecPrivateData) {
713
737
  return codecPrivateData;
714
738
  }
@@ -786,7 +810,7 @@ shaka.mss.MssParser = class {
786
810
  }
787
811
 
788
812
  /**
789
- * @param {!Element} qualityLevel
813
+ * @param {!shaka.extern.xml.Node} qualityLevel
790
814
  * @param {string} fourCCValue
791
815
  * @param {?string} codecPrivateData
792
816
  * @return {string}
@@ -815,7 +839,7 @@ shaka.mss.MssParser = class {
815
839
  }
816
840
 
817
841
  /**
818
- * @param {!Element} qualityLevel
842
+ * @param {!shaka.extern.xml.Node} qualityLevel
819
843
  * @param {?string} codecPrivateData
820
844
  * @return {string}
821
845
  * @private
@@ -841,14 +865,14 @@ shaka.mss.MssParser = class {
841
865
  /**
842
866
  * @param {!shaka.media.InitSegmentReference} initSegmentRef
843
867
  * @param {!shaka.extern.Stream} stream
844
- * @param {!Element} streamIndex
868
+ * @param {!shaka.extern.xml.Node} streamIndex
845
869
  * @param {!Array.<shaka.mss.MssParser.TimeRange>} timeline
846
870
  * @return {!Array.<!shaka.media.SegmentReference>}
847
871
  * @private
848
872
  */
849
873
  createSegments_(initSegmentRef, stream, streamIndex, timeline) {
850
874
  const ManifestParserUtils = shaka.util.ManifestParserUtils;
851
- const url = streamIndex.getAttribute('Url');
875
+ const url = streamIndex.attributes['Url'];
852
876
  goog.asserts.assert(url, 'Missing URL for segments');
853
877
 
854
878
  const mediaUrl = url.replace('{bitrate}', String(stream.bandwidth));
@@ -877,7 +901,7 @@ shaka.mss.MssParser = class {
877
901
  * Expands a streamIndex into an array-based timeline. The results are in
878
902
  * seconds.
879
903
  *
880
- * @param {!Element} streamIndex
904
+ * @param {!shaka.extern.xml.Node} streamIndex
881
905
  * @param {number} timescale
882
906
  * @param {number} duration The duration in seconds.
883
907
  * @return {!Array.<shaka.mss.MssParser.TimeRange>}
@@ -890,9 +914,9 @@ shaka.mss.MssParser = class {
890
914
  goog.asserts.assert(
891
915
  duration > 0, 'duration must be a positive integer');
892
916
 
893
- const XmlUtils = shaka.util.XmlUtils;
917
+ const TXml = shaka.util.TXml;
894
918
 
895
- const timePoints = XmlUtils.findChildren(streamIndex, 'c');
919
+ const timePoints = TXml.findChildren(streamIndex, 'c');
896
920
 
897
921
  /** @type {!Array.<shaka.mss.MssParser.TimeRange>} */
898
922
  const timeline = [];
@@ -902,10 +926,10 @@ shaka.mss.MssParser = class {
902
926
  const timePoint = timePoints[i];
903
927
  const next = timePoints[i + 1];
904
928
  const t =
905
- XmlUtils.parseAttr(timePoint, 't', XmlUtils.parseNonNegativeInt);
929
+ TXml.parseAttr(timePoint, 't', TXml.parseNonNegativeInt);
906
930
  const d =
907
- XmlUtils.parseAttr(timePoint, 'd', XmlUtils.parseNonNegativeInt);
908
- const r = XmlUtils.parseAttr(timePoint, 'r', XmlUtils.parseInt);
931
+ TXml.parseAttr(timePoint, 'd', TXml.parseNonNegativeInt);
932
+ const r = TXml.parseAttr(timePoint, 'r', TXml.parseInt);
909
933
 
910
934
  if (!d) {
911
935
  shaka.log.warning(
@@ -920,7 +944,7 @@ shaka.mss.MssParser = class {
920
944
  if (repeat < 0) {
921
945
  if (next) {
922
946
  const nextStartTime =
923
- XmlUtils.parseAttr(next, 't', XmlUtils.parseNonNegativeInt);
947
+ TXml.parseAttr(next, 't', TXml.parseNonNegativeInt);
924
948
  if (nextStartTime == null) {
925
949
  shaka.log.warning(
926
950
  'An "c" element cannot have a negative repeat',
@@ -46,7 +46,8 @@ goog.require('shaka.util.Timer');
46
46
  */
47
47
  shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
48
48
  /**
49
- * @param {function(number, number, boolean)=} onProgressUpdated Called when
49
+ * @param {shaka.net.NetworkingEngine.onProgressUpdated=} onProgressUpdated
50
+ * Called when
50
51
  * a progress event is triggered. Passed the duration, in milliseconds,
51
52
  * that the request took, the number of bytes transferred, and the boolean
52
53
  * of whether the switching is allowed.
@@ -58,9 +59,11 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
58
59
  * Called when a request is made
59
60
  * @param {shaka.net.NetworkingEngine.OnRetry=} onRetry
60
61
  * Called when a request retry is made
62
+ * @param {shaka.net.NetworkingEngine.OnResponse=} onResponse
63
+ * Called when receive the response
61
64
  */
62
65
  constructor(onProgressUpdated, onHeadersReceived, onDownloadFailed,
63
- onRequest, onRetry) {
66
+ onRequest, onRetry, onResponse) {
64
67
  super();
65
68
 
66
69
  /** @private {boolean} */
@@ -75,7 +78,7 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
75
78
  /** @private {!Set.<shaka.extern.ResponseFilter>} */
76
79
  this.responseFilters_ = new Set();
77
80
 
78
- /** @private {?function(number, number, boolean)} */
81
+ /** @private {?shaka.net.NetworkingEngine.onProgressUpdated} */
79
82
  this.onProgressUpdated_ = onProgressUpdated || null;
80
83
 
81
84
  /** @private {?shaka.net.NetworkingEngine.OnHeadersReceived} */
@@ -90,6 +93,9 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
90
93
  /** @private {?shaka.net.NetworkingEngine.OnRetry} */
91
94
  this.onRetry_ = onRetry || null;
92
95
 
96
+ /** @private {?shaka.net.NetworkingEngine.OnResponse} */
97
+ this.onResponse_ = onResponse || null;
98
+
93
99
  /** @private {boolean} */
94
100
  this.forceHTTPS_ = false;
95
101
  }
@@ -333,6 +339,9 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
333
339
  this.onProgressUpdated_(
334
340
  response.timeMs, response.data.byteLength, allowSwitch);
335
341
  }
342
+ if (this.onResponse_) {
343
+ this.onResponse_(type, response, context);
344
+ }
336
345
  return response;
337
346
  }, (e) => {
338
347
  // Any error thrown from elsewhere should be recategorized as CRITICAL
@@ -510,6 +519,7 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
510
519
 
511
520
  startTimeMs = Date.now();
512
521
  const segment = shaka.net.NetworkingEngine.RequestType.SEGMENT;
522
+ let packetNumber = 0;
513
523
 
514
524
  const progressUpdated = (time, bytes, numBytesRemaining) => {
515
525
  if (connectionTimer) {
@@ -519,8 +529,10 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
519
529
  stallTimer.tickAfter(stallTimeoutMs / 1000);
520
530
  }
521
531
  if (this.onProgressUpdated_ && type == segment) {
532
+ packetNumber++;
533
+ request.packetNumber = packetNumber;
522
534
  const allowSwitch = this.allowSwitch_(context);
523
- this.onProgressUpdated_(time, bytes, allowSwitch);
535
+ this.onProgressUpdated_(time, bytes, allowSwitch, request);
524
536
  gotProgress = true;
525
537
  numBytesRemainingObj.setBytes(numBytesRemaining);
526
538
  }
@@ -530,7 +542,11 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
530
542
  this.onHeadersReceived_(headers, request, type);
531
543
  }
532
544
  headersReceivedCalled = true;
545
+ request.timeToFirstByte = Date.now() -
546
+ /** @type {number} */ (request.requestStartTime);
533
547
  };
548
+ request.requestStartTime = Date.now();
549
+
534
550
  const requestPlugin = plugin(
535
551
  request.uris[index], request, type, progressUpdated, headersReceived);
536
552
 
@@ -899,6 +915,21 @@ shaka.net.NetworkingEngine.ResponseAndGotProgress;
899
915
  */
900
916
  shaka.net.NetworkingEngine.OnHeadersReceived;
901
917
 
918
+ /**
919
+ * @typedef {function(
920
+ * number,
921
+ * number,
922
+ * boolean,
923
+ * shaka.extern.Request=)}
924
+ *
925
+ * @description
926
+ * A callback that is passed the duration, in milliseconds,
927
+ * that the request took, the number of bytes transferred, a boolean
928
+ * representing whether the switching is allowed and a ref to the
929
+ * original request.
930
+ * @export
931
+ */
932
+ shaka.net.NetworkingEngine.onProgressUpdated;
902
933
 
903
934
  /**
904
935
  * @typedef {function(
@@ -941,3 +972,17 @@ shaka.net.NetworkingEngine.OnRequest;
941
972
  * @export
942
973
  */
943
974
  shaka.net.NetworkingEngine.OnRetry;
975
+
976
+
977
+ /**
978
+ * @typedef {function(
979
+ * !shaka.net.NetworkingEngine.RequestType,
980
+ * !shaka.extern.Response,
981
+ * (shaka.extern.RequestContext|undefined))}
982
+ *
983
+ * @description
984
+ * A callback function called on every request
985
+ * @export
986
+ */
987
+ shaka.net.NetworkingEngine.OnResponse;
988
+
@@ -664,7 +664,8 @@ shaka.offline.Storage = class {
664
664
  // Filter the manifest based on what we know MediaCapabilities will be able
665
665
  // to play later (no point storing something we can't play).
666
666
  await shaka.util.StreamUtils.filterManifestByMediaCapabilities(
667
- drmEngine, manifest, config.offline.usePersistentLicense);
667
+ drmEngine, manifest, config.offline.usePersistentLicense,
668
+ config.drm.preferredKeySystems);
668
669
 
669
670
  // Gather all tracks.
670
671
  const allTracks = [];
@@ -1656,7 +1657,6 @@ shaka.offline.Storage.defaultSystemIds_ = new Map()
1656
1657
  .set('com.microsoft.playready.software',
1657
1658
  '9a04f07998404286ab92e65be0885f95')
1658
1659
  .set('com.microsoft.playready.hardware',
1659
- '9a04f07998404286ab92e65be0885f95')
1660
- .set('com.adobe.primetime', 'f239e769efa348509c16a903c6932efb');
1660
+ '9a04f07998404286ab92e65be0885f95');
1661
1661
 
1662
1662
  shaka.Player.registerSupportPlugin('offline', shaka.offline.Storage.support);