shaka-player 4.7.13 → 4.8.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 (114) hide show
  1. package/AUTHORS +1 -0
  2. package/CONTRIBUTORS +1 -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 +44 -34
  9. package/dist/shaka-player.compiled.d.ts +194 -44
  10. package/dist/shaka-player.compiled.debug.d.ts +194 -44
  11. package/dist/shaka-player.compiled.debug.externs.js +474 -337
  12. package/dist/shaka-player.compiled.debug.js +949 -832
  13. package/dist/shaka-player.compiled.debug.map +4 -4
  14. package/dist/shaka-player.compiled.externs.js +474 -337
  15. package/dist/shaka-player.compiled.js +1237 -1171
  16. package/dist/shaka-player.compiled.map +4 -4
  17. package/dist/shaka-player.ui.d.ts +257 -47
  18. package/dist/shaka-player.ui.debug.d.ts +257 -47
  19. package/dist/shaka-player.ui.debug.externs.js +591 -376
  20. package/dist/shaka-player.ui.debug.js +1165 -965
  21. package/dist/shaka-player.ui.debug.map +4 -4
  22. package/dist/shaka-player.ui.externs.js +591 -376
  23. package/dist/shaka-player.ui.js +1521 -1404
  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 +230 -176
  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 +26 -21
  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 +40 -30
  59. package/lib/media/segment_prefetch.js +140 -43
  60. package/lib/media/segment_reference.js +31 -8
  61. package/lib/media/segment_utils.js +208 -25
  62. package/lib/media/streaming_engine.js +319 -63
  63. package/lib/mss/content_protection.js +31 -25
  64. package/lib/mss/mss_parser.js +74 -55
  65. package/lib/net/networking_engine.js +49 -4
  66. package/lib/offline/storage.js +3 -3
  67. package/lib/player.js +882 -673
  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 +152 -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 +61 -3
  87. package/lib/util/stats.js +16 -0
  88. package/lib/util/stream_utils.js +16 -6
  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');
@@ -23,6 +24,7 @@ goog.require('shaka.util.MimeUtils');
23
24
  goog.require('shaka.util.Mp4Generator');
24
25
  goog.require('shaka.util.OperationManager');
25
26
  goog.require('shaka.util.Timer');
27
+ goog.require('shaka.util.TXml');
26
28
  goog.require('shaka.util.XmlUtils');
27
29
 
28
30
 
@@ -278,7 +280,25 @@ shaka.mss.MssParser = class {
278
280
  * @private
279
281
  */
280
282
  parseManifest_(data, finalManifestUri) {
281
- const mss = shaka.util.XmlUtils.parseXml(data, 'SmoothStreamingMedia');
283
+ let manifestData = data;
284
+ const manifestPreprocessor = this.config_.mss.manifestPreprocessor;
285
+ if (manifestPreprocessor) {
286
+ shaka.Deprecate.deprecateFeature(5,
287
+ 'manifest.mss.manifestPreprocessor configuration',
288
+ 'Please Use manifest.mss.manifestPreprocessorTXml instead.');
289
+ const mssElement =
290
+ shaka.util.XmlUtils.parseXml(manifestData, 'SmoothStreamingMedia');
291
+ if (!mssElement) {
292
+ throw new shaka.util.Error(
293
+ shaka.util.Error.Severity.CRITICAL,
294
+ shaka.util.Error.Category.MANIFEST,
295
+ shaka.util.Error.Code.MSS_INVALID_XML,
296
+ finalManifestUri);
297
+ }
298
+ manifestPreprocessor(mssElement);
299
+ manifestData = shaka.util.XmlUtils.toArrayBuffer(mssElement);
300
+ }
301
+ const mss = shaka.util.TXml.parseXml(manifestData, 'SmoothStreamingMedia');
282
302
  if (!mss) {
283
303
  throw new shaka.util.Error(
284
304
  shaka.util.Error.Severity.CRITICAL,
@@ -286,6 +306,10 @@ shaka.mss.MssParser = class {
286
306
  shaka.util.Error.Code.MSS_INVALID_XML,
287
307
  finalManifestUri);
288
308
  }
309
+ const manifestPreprocessorTXml = this.config_.mss.manifestPreprocessorTXml;
310
+ if (manifestPreprocessorTXml) {
311
+ manifestPreprocessorTXml(mss);
312
+ }
289
313
  this.processManifest_(mss, finalManifestUri);
290
314
  return Promise.resolve();
291
315
  }
@@ -294,26 +318,21 @@ shaka.mss.MssParser = class {
294
318
  /**
295
319
  * Takes a formatted MSS and converts it into a manifest.
296
320
  *
297
- * @param {!Element} mss
321
+ * @param {!shaka.extern.xml.Node} mss
298
322
  * @param {string} finalManifestUri The final manifest URI, which may
299
323
  * differ from this.manifestUri_ if there has been a redirect.
300
324
  * @private
301
325
  */
302
326
  processManifest_(mss, finalManifestUri) {
303
- const XmlUtils = shaka.util.XmlUtils;
304
-
305
- const manifestPreprocessor = this.config_.mss.manifestPreprocessor;
306
- if (manifestPreprocessor) {
307
- manifestPreprocessor(mss);
308
- }
327
+ const TXml = shaka.util.TXml;
309
328
 
310
329
  if (!this.presentationTimeline_) {
311
330
  this.presentationTimeline_ = new shaka.media.PresentationTimeline(
312
331
  /* presentationStartTime= */ null, /* delay= */ 0);
313
332
  }
314
333
 
315
- const isLive = XmlUtils.parseAttr(mss, 'IsLive',
316
- XmlUtils.parseBoolean, /* defaultValue= */ false);
334
+ const isLive = TXml.parseAttr(mss, 'IsLive',
335
+ TXml.parseBoolean, /* defaultValue= */ false);
317
336
 
318
337
  if (isLive) {
319
338
  throw new shaka.util.Error(
@@ -324,21 +343,21 @@ shaka.mss.MssParser = class {
324
343
 
325
344
  this.presentationTimeline_.setStatic(!isLive);
326
345
 
327
- const timescale = XmlUtils.parseAttr(mss, 'TimeScale',
328
- XmlUtils.parseNonNegativeInt, shaka.mss.MssParser.DEFAULT_TIME_SCALE_);
346
+ const timescale = TXml.parseAttr(mss, 'TimeScale',
347
+ TXml.parseNonNegativeInt, shaka.mss.MssParser.DEFAULT_TIME_SCALE_);
329
348
  goog.asserts.assert(timescale && timescale >= 0,
330
349
  'Timescale must be defined!');
331
350
 
332
- let dvrWindowLength = XmlUtils.parseAttr(mss, 'DVRWindowLength',
333
- XmlUtils.parseNonNegativeInt);
351
+ let dvrWindowLength = TXml.parseAttr(mss, 'DVRWindowLength',
352
+ TXml.parseNonNegativeInt);
334
353
  // If the DVRWindowLength field is omitted for a live presentation or set
335
354
  // to 0, the DVR window is effectively infinite
336
355
  if (isLive && (dvrWindowLength === 0 || isNaN(dvrWindowLength))) {
337
356
  dvrWindowLength = Infinity;
338
357
  }
339
358
  // Start-over
340
- const canSeek = XmlUtils.parseAttr(mss, 'CanSeek',
341
- XmlUtils.parseBoolean, /* defaultValue= */ false);
359
+ const canSeek = TXml.parseAttr(mss, 'CanSeek',
360
+ TXml.parseBoolean, /* defaultValue= */ false);
342
361
  if (dvrWindowLength === 0 && canSeek) {
343
362
  dvrWindowLength = Infinity;
344
363
  }
@@ -363,8 +382,8 @@ shaka.mss.MssParser = class {
363
382
  segmentAvailabilityDuration);
364
383
 
365
384
  // Duration in timescale units.
366
- const duration = XmlUtils.parseAttr(mss, 'Duration',
367
- XmlUtils.parseNonNegativeInt, Infinity);
385
+ const duration = TXml.parseAttr(mss, 'Duration',
386
+ TXml.parseNonNegativeInt, Infinity);
368
387
  goog.asserts.assert(duration && duration >= 0,
369
388
  'Duration must be defined!');
370
389
 
@@ -414,25 +433,25 @@ shaka.mss.MssParser = class {
414
433
  }
415
434
 
416
435
  /**
417
- * @param {!Element} mss
436
+ * @param {!shaka.extern.xml.Node} mss
418
437
  * @param {!shaka.mss.MssParser.Context} context
419
438
  * @private
420
439
  */
421
440
  parseStreamIndexes_(mss, context) {
422
441
  const ContentProtection = shaka.mss.ContentProtection;
423
- const XmlUtils = shaka.util.XmlUtils;
442
+ const TXml = shaka.util.TXml;
424
443
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
425
444
 
426
- const protectionElems = XmlUtils.findChildren(mss, 'Protection');
445
+ const protectionElems = TXml.findChildren(mss, 'Protection');
427
446
  const drmInfos = ContentProtection.parseFromProtection(
428
447
  protectionElems, this.config_.mss.keySystemsBySystemId);
429
448
 
430
449
  const audioStreams = [];
431
450
  const videoStreams = [];
432
451
  const textStreams = [];
433
- const streamIndexes = XmlUtils.findChildren(mss, 'StreamIndex');
452
+ const streamIndexes = TXml.findChildren(mss, 'StreamIndex');
434
453
  for (const streamIndex of streamIndexes) {
435
- const qualityLevels = XmlUtils.findChildren(streamIndex, 'QualityLevel');
454
+ const qualityLevels = TXml.findChildren(streamIndex, 'QualityLevel');
436
455
  const timeline = this.createTimeline_(
437
456
  streamIndex, context.timescale, context.duration);
438
457
  // For each QualityLevel node, create a stream element
@@ -467,8 +486,8 @@ shaka.mss.MssParser = class {
467
486
  }
468
487
 
469
488
  /**
470
- * @param {!Element} streamIndex
471
- * @param {!Element} qualityLevel
489
+ * @param {!shaka.extern.xml.Node} streamIndex
490
+ * @param {!shaka.extern.xml.Node} qualityLevel
472
491
  * @param {!Array.<shaka.mss.MssParser.TimeRange>} timeline
473
492
  * @param {!Array.<shaka.extern.DrmInfo>} drmInfos
474
493
  * @param {!shaka.mss.MssParser.Context} context
@@ -476,11 +495,11 @@ shaka.mss.MssParser = class {
476
495
  * @private
477
496
  */
478
497
  createStream_(streamIndex, qualityLevel, timeline, drmInfos, context) {
479
- const XmlUtils = shaka.util.XmlUtils;
498
+ const TXml = shaka.util.TXml;
480
499
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
481
500
  const MssParser = shaka.mss.MssParser;
482
501
 
483
- const type = streamIndex.getAttribute('Type');
502
+ const type = streamIndex.attributes['Type'];
484
503
  const isValidType = type === 'audio' || type === 'video' ||
485
504
  type === 'text';
486
505
  if (!isValidType) {
@@ -488,19 +507,19 @@ shaka.mss.MssParser = class {
488
507
  return null;
489
508
  }
490
509
 
491
- const lang = streamIndex.getAttribute('Language');
510
+ const lang = streamIndex.attributes['Language'];
492
511
  const id = this.globalId_++;
493
512
 
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);
513
+ const bandwidth = TXml.parseAttr(
514
+ qualityLevel, 'Bitrate', TXml.parsePositiveInt);
515
+ const width = TXml.parseAttr(
516
+ qualityLevel, 'MaxWidth', TXml.parsePositiveInt);
517
+ const height = TXml.parseAttr(
518
+ qualityLevel, 'MaxHeight', TXml.parsePositiveInt);
519
+ const channelsCount = TXml.parseAttr(
520
+ qualityLevel, 'Channels', TXml.parsePositiveInt);
521
+ const audioSamplingRate = TXml.parseAttr(
522
+ qualityLevel, 'SamplingRate', TXml.parsePositiveInt);
504
523
 
505
524
  let duration = context.duration;
506
525
  if (timeline.length) {
@@ -516,7 +535,7 @@ shaka.mss.MssParser = class {
516
535
  /** @type {!shaka.extern.Stream} */
517
536
  const stream = {
518
537
  id: id,
519
- originalId: streamIndex.getAttribute('Name') || String(id),
538
+ originalId: streamIndex.attributes['Name'] || String(id),
520
539
  groupId: null,
521
540
  createSegmentIndex: () => Promise.resolve(),
522
541
  closeSegmentIndex: () => Promise.resolve(),
@@ -561,7 +580,7 @@ shaka.mss.MssParser = class {
561
580
  };
562
581
 
563
582
  // This is specifically for text tracks.
564
- const subType = streamIndex.getAttribute('Subtype');
583
+ const subType = streamIndex.attributes['Subtype'];
565
584
  if (subType) {
566
585
  const role = MssParser.ROLE_MAPPING_[subType];
567
586
  if (role) {
@@ -572,12 +591,12 @@ shaka.mss.MssParser = class {
572
591
  }
573
592
  }
574
593
 
575
- let fourCCValue = qualityLevel.getAttribute('FourCC');
594
+ let fourCCValue = qualityLevel.attributes['FourCC'];
576
595
 
577
596
  // If FourCC not defined at QualityLevel level,
578
597
  // then get it from StreamIndex level
579
598
  if (fourCCValue === null || fourCCValue === '') {
580
- fourCCValue = streamIndex.getAttribute('FourCC');
599
+ fourCCValue = streamIndex.attributes['FourCC'];
581
600
  }
582
601
 
583
602
  // If still not defined (optional for audio stream,
@@ -700,7 +719,7 @@ shaka.mss.MssParser = class {
700
719
  }
701
720
 
702
721
  /**
703
- * @param {!Element} qualityLevel
722
+ * @param {!shaka.extern.xml.Node} qualityLevel
704
723
  * @param {string} type
705
724
  * @param {string} fourCCValue
706
725
  * @param {!shaka.extern.Stream} stream
@@ -708,7 +727,7 @@ shaka.mss.MssParser = class {
708
727
  * @private
709
728
  */
710
729
  getCodecPrivateData_(qualityLevel, type, fourCCValue, stream) {
711
- const codecPrivateData = qualityLevel.getAttribute('CodecPrivateData');
730
+ const codecPrivateData = qualityLevel.attributes['CodecPrivateData'];
712
731
  if (codecPrivateData) {
713
732
  return codecPrivateData;
714
733
  }
@@ -786,7 +805,7 @@ shaka.mss.MssParser = class {
786
805
  }
787
806
 
788
807
  /**
789
- * @param {!Element} qualityLevel
808
+ * @param {!shaka.extern.xml.Node} qualityLevel
790
809
  * @param {string} fourCCValue
791
810
  * @param {?string} codecPrivateData
792
811
  * @return {string}
@@ -815,7 +834,7 @@ shaka.mss.MssParser = class {
815
834
  }
816
835
 
817
836
  /**
818
- * @param {!Element} qualityLevel
837
+ * @param {!shaka.extern.xml.Node} qualityLevel
819
838
  * @param {?string} codecPrivateData
820
839
  * @return {string}
821
840
  * @private
@@ -841,14 +860,14 @@ shaka.mss.MssParser = class {
841
860
  /**
842
861
  * @param {!shaka.media.InitSegmentReference} initSegmentRef
843
862
  * @param {!shaka.extern.Stream} stream
844
- * @param {!Element} streamIndex
863
+ * @param {!shaka.extern.xml.Node} streamIndex
845
864
  * @param {!Array.<shaka.mss.MssParser.TimeRange>} timeline
846
865
  * @return {!Array.<!shaka.media.SegmentReference>}
847
866
  * @private
848
867
  */
849
868
  createSegments_(initSegmentRef, stream, streamIndex, timeline) {
850
869
  const ManifestParserUtils = shaka.util.ManifestParserUtils;
851
- const url = streamIndex.getAttribute('Url');
870
+ const url = streamIndex.attributes['Url'];
852
871
  goog.asserts.assert(url, 'Missing URL for segments');
853
872
 
854
873
  const mediaUrl = url.replace('{bitrate}', String(stream.bandwidth));
@@ -877,7 +896,7 @@ shaka.mss.MssParser = class {
877
896
  * Expands a streamIndex into an array-based timeline. The results are in
878
897
  * seconds.
879
898
  *
880
- * @param {!Element} streamIndex
899
+ * @param {!shaka.extern.xml.Node} streamIndex
881
900
  * @param {number} timescale
882
901
  * @param {number} duration The duration in seconds.
883
902
  * @return {!Array.<shaka.mss.MssParser.TimeRange>}
@@ -890,9 +909,9 @@ shaka.mss.MssParser = class {
890
909
  goog.asserts.assert(
891
910
  duration > 0, 'duration must be a positive integer');
892
911
 
893
- const XmlUtils = shaka.util.XmlUtils;
912
+ const TXml = shaka.util.TXml;
894
913
 
895
- const timePoints = XmlUtils.findChildren(streamIndex, 'c');
914
+ const timePoints = TXml.findChildren(streamIndex, 'c');
896
915
 
897
916
  /** @type {!Array.<shaka.mss.MssParser.TimeRange>} */
898
917
  const timeline = [];
@@ -902,10 +921,10 @@ shaka.mss.MssParser = class {
902
921
  const timePoint = timePoints[i];
903
922
  const next = timePoints[i + 1];
904
923
  const t =
905
- XmlUtils.parseAttr(timePoint, 't', XmlUtils.parseNonNegativeInt);
924
+ TXml.parseAttr(timePoint, 't', TXml.parseNonNegativeInt);
906
925
  const d =
907
- XmlUtils.parseAttr(timePoint, 'd', XmlUtils.parseNonNegativeInt);
908
- const r = XmlUtils.parseAttr(timePoint, 'r', XmlUtils.parseInt);
926
+ TXml.parseAttr(timePoint, 'd', TXml.parseNonNegativeInt);
927
+ const r = TXml.parseAttr(timePoint, 'r', TXml.parseInt);
909
928
 
910
929
  if (!d) {
911
930
  shaka.log.warning(
@@ -920,7 +939,7 @@ shaka.mss.MssParser = class {
920
939
  if (repeat < 0) {
921
940
  if (next) {
922
941
  const nextStartTime =
923
- XmlUtils.parseAttr(next, 't', XmlUtils.parseNonNegativeInt);
942
+ TXml.parseAttr(next, 't', TXml.parseNonNegativeInt);
924
943
  if (nextStartTime == null) {
925
944
  shaka.log.warning(
926
945
  '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);