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
@@ -7,6 +7,7 @@
7
7
  goog.provide('shaka.dash.DashParser');
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.dash.ContentProtection');
12
13
  goog.require('shaka.dash.MpdUtils');
@@ -31,6 +32,7 @@ goog.require('shaka.util.OperationManager');
31
32
  goog.require('shaka.util.PeriodCombiner');
32
33
  goog.require('shaka.util.StringUtils');
33
34
  goog.require('shaka.util.Timer');
35
+ goog.require('shaka.util.TXml');
34
36
  goog.require('shaka.util.XmlUtils');
35
37
 
36
38
 
@@ -129,9 +131,14 @@ shaka.dash.DashParser = class {
129
131
  configure(config) {
130
132
  goog.asserts.assert(config.dash != null,
131
133
  'DashManifestConfiguration should not be null!');
132
-
134
+ const needFireUpdate = this.playerInterface_ &&
135
+ config.dash.updatePeriod != this.config_.dash.updatePeriod &&
136
+ config.dash.updatePeriod >= 0;
133
137
  this.config_ = config;
134
-
138
+ if (needFireUpdate && this.manifest_ &&
139
+ this.manifest_.presentationTimeline.isLive()) {
140
+ this.updateNow_();
141
+ }
135
142
  if (this.contentSteeringManager_) {
136
143
  this.contentSteeringManager_.configure(this.config_);
137
144
  }
@@ -140,6 +147,8 @@ shaka.dash.DashParser = class {
140
147
  this.periodCombiner_.setAllowMultiTypeVariants(
141
148
  this.config_.dash.multiTypeVariantsAllowed &&
142
149
  shaka.media.Capabilities.isChangeTypeSupported());
150
+ this.periodCombiner_.setUseStreamOnce(
151
+ this.config_.dash.useStreamOnceInPeriodFlattening);
143
152
  }
144
153
  }
145
154
 
@@ -327,15 +336,38 @@ shaka.dash.DashParser = class {
327
336
  * @private
328
337
  */
329
338
  async parseManifest_(data, finalManifestUri) {
330
- const Error = shaka.util.Error;
331
- const MpdUtils = shaka.dash.MpdUtils;
332
-
333
- const mpd = shaka.util.XmlUtils.parseXml(data, 'MPD');
339
+ let manifestData = data;
340
+ const manifestPreprocessor = this.config_.dash.manifestPreprocessor;
341
+ if (manifestPreprocessor) {
342
+ shaka.Deprecate.deprecateFeature(5,
343
+ 'manifest.dash.manifestPreprocessor configuration',
344
+ 'Please Use manifest.dash.manifestPreprocessorTXml instead.');
345
+ const mpdElement =
346
+ shaka.util.XmlUtils.parseXml(manifestData, 'MPD');
347
+ if (!mpdElement) {
348
+ throw new shaka.util.Error(
349
+ shaka.util.Error.Severity.CRITICAL,
350
+ shaka.util.Error.Category.MANIFEST,
351
+ shaka.util.Error.Code.DASH_INVALID_XML,
352
+ finalManifestUri);
353
+ }
354
+ manifestPreprocessor(mpdElement);
355
+ manifestData = shaka.util.XmlUtils.toArrayBuffer(mpdElement);
356
+ }
357
+ const mpd = shaka.util.TXml.parseXml(manifestData, 'MPD');
334
358
  if (!mpd) {
335
- throw new Error(
336
- Error.Severity.CRITICAL, Error.Category.MANIFEST,
337
- Error.Code.DASH_INVALID_XML, finalManifestUri);
359
+ throw new shaka.util.Error(
360
+ shaka.util.Error.Severity.CRITICAL,
361
+ shaka.util.Error.Category.MANIFEST,
362
+ shaka.util.Error.Code.DASH_INVALID_XML,
363
+ finalManifestUri);
338
364
  }
365
+ const manifestPreprocessorTXml =
366
+ this.config_.dash.manifestPreprocessorTXml;
367
+ if (manifestPreprocessorTXml) {
368
+ manifestPreprocessorTXml(mpd);
369
+ }
370
+
339
371
  const disableXlinkProcessing = this.config_.dash.disableXlinkProcessing;
340
372
  if (disableXlinkProcessing) {
341
373
  return this.processManifest_(mpd, finalManifestUri);
@@ -343,7 +375,7 @@ shaka.dash.DashParser = class {
343
375
 
344
376
  // Process the mpd to account for xlink connections.
345
377
  const failGracefully = this.config_.dash.xlinkFailGracefully;
346
- const xlinkOperation = MpdUtils.processXlinks(
378
+ const xlinkOperation = shaka.dash.MpdUtils.processXlinks(
347
379
  mpd, this.config_.retryParameters, failGracefully, finalManifestUri,
348
380
  this.playerInterface_.networkingEngine);
349
381
  this.operationManager_.manage(xlinkOperation);
@@ -355,19 +387,17 @@ shaka.dash.DashParser = class {
355
387
  /**
356
388
  * Takes a formatted MPD and converts it into a manifest.
357
389
  *
358
- * @param {!Element} mpd
390
+ * @param {!shaka.extern.xml.Node} mpd
359
391
  * @param {string} finalManifestUri The final manifest URI, which may
360
392
  * differ from this.manifestUri_ if there has been a redirect.
361
393
  * @return {!Promise}
362
394
  * @private
363
395
  */
364
396
  async processManifest_(mpd, finalManifestUri) {
365
- const XmlUtils = shaka.util.XmlUtils;
397
+ const TXml = shaka.util.TXml;
366
398
 
367
- const manifestPreprocessor = this.config_.dash.manifestPreprocessor;
368
- if (manifestPreprocessor) {
369
- manifestPreprocessor(mpd);
370
- }
399
+ goog.asserts.assert(this.config_,
400
+ 'Must call configure() before processManifest_()!');
371
401
 
372
402
  if (this.contentSteeringManager_) {
373
403
  this.contentSteeringManager_.clearPreviousLocations();
@@ -381,10 +411,10 @@ shaka.dash.DashParser = class {
381
411
  const locations = [];
382
412
  /** @type {!Map.<string, string>} */
383
413
  const locationsMapping = new Map();
384
- const locationsObjs = XmlUtils.findChildren(mpd, 'Location');
414
+ const locationsObjs = TXml.findChildren(mpd, 'Location');
385
415
  for (const locationsObj of locationsObjs) {
386
- const serviceLocation = locationsObj.getAttribute('serviceLocation');
387
- const uri = XmlUtils.getContents(locationsObj);
416
+ const serviceLocation = locationsObj.attributes['serviceLocation'];
417
+ const uri = TXml.getContents(locationsObj);
388
418
  if (!uri) {
389
419
  continue;
390
420
  }
@@ -414,10 +444,10 @@ shaka.dash.DashParser = class {
414
444
 
415
445
  let contentSteeringPromise = Promise.resolve();
416
446
 
417
- const contentSteering = XmlUtils.findChild(mpd, 'ContentSteering');
447
+ const contentSteering = TXml.findChild(mpd, 'ContentSteering');
418
448
  if (contentSteering && this.playerInterface_) {
419
449
  const defaultPathwayId =
420
- contentSteering.getAttribute('defaultServiceLocation');
450
+ contentSteering.attributes['defaultServiceLocation'];
421
451
  if (!this.contentSteeringManager_) {
422
452
  this.contentSteeringManager_ =
423
453
  new shaka.util.ContentSteeringManager(this.playerInterface_);
@@ -426,11 +456,11 @@ shaka.dash.DashParser = class {
426
456
  shaka.media.ManifestParser.DASH);
427
457
  this.contentSteeringManager_.setBaseUris(manifestBaseUris);
428
458
  this.contentSteeringManager_.setDefaultPathwayId(defaultPathwayId);
429
- const uri = XmlUtils.getContents(contentSteering);
459
+ const uri = TXml.getContents(contentSteering);
430
460
  if (uri) {
431
461
  const queryBeforeStart =
432
- XmlUtils.parseAttr(contentSteering, 'queryBeforeStart',
433
- XmlUtils.parseBoolean, /* defaultValue= */ false);
462
+ TXml.parseAttr(contentSteering, 'queryBeforeStart',
463
+ TXml.parseBoolean, /* defaultValue= */ false);
434
464
  if (queryBeforeStart) {
435
465
  contentSteeringPromise =
436
466
  this.contentSteeringManager_.requestInfo(uri);
@@ -449,13 +479,13 @@ shaka.dash.DashParser = class {
449
479
  }
450
480
  }
451
481
 
452
- const uriObjs = XmlUtils.findChildren(mpd, 'BaseURL');
482
+ const uriObjs = TXml.findChildren(mpd, 'BaseURL');
453
483
  let calculatedBaseUris;
454
484
  let someLocationValid = false;
455
485
  if (this.contentSteeringManager_) {
456
486
  for (const uriObj of uriObjs) {
457
- const serviceLocation = uriObj.getAttribute('serviceLocation');
458
- const uri = XmlUtils.getContents(uriObj);
487
+ const serviceLocation = uriObj.attributes['serviceLocation'];
488
+ const uri = TXml.getContents(uriObj);
459
489
  if (serviceLocation && uri) {
460
490
  this.contentSteeringManager_.addLocation(
461
491
  'BaseURL', serviceLocation, uri);
@@ -464,7 +494,7 @@ shaka.dash.DashParser = class {
464
494
  }
465
495
  }
466
496
  if (!someLocationValid || !this.contentSteeringManager_) {
467
- const uris = uriObjs.map(XmlUtils.getContents);
497
+ const uris = uriObjs.map(TXml.getContents);
468
498
  calculatedBaseUris = shaka.util.ManifestParserUtils.resolveUris(
469
499
  manifestBaseUris, uris);
470
500
  }
@@ -481,41 +511,41 @@ shaka.dash.DashParser = class {
481
511
 
482
512
  let availabilityTimeOffset = 0;
483
513
  if (uriObjs && uriObjs.length) {
484
- availabilityTimeOffset = XmlUtils.parseAttr(
485
- uriObjs[0], 'availabilityTimeOffset', XmlUtils.parseFloat) || 0;
514
+ availabilityTimeOffset = TXml.parseAttr(uriObjs[0],
515
+ 'availabilityTimeOffset', TXml.parseFloat) || 0;
486
516
  }
487
517
 
488
518
  const ignoreMinBufferTime = this.config_.dash.ignoreMinBufferTime;
489
519
  let minBufferTime = 0;
490
520
  if (!ignoreMinBufferTime) {
491
521
  minBufferTime =
492
- XmlUtils.parseAttr(mpd, 'minBufferTime', XmlUtils.parseDuration) || 0;
522
+ TXml.parseAttr(mpd, 'minBufferTime', TXml.parseDuration) || 0;
493
523
  }
494
524
 
495
- this.updatePeriod_ = /** @type {number} */ (XmlUtils.parseAttr(
496
- mpd, 'minimumUpdatePeriod', XmlUtils.parseDuration, -1));
525
+ this.updatePeriod_ = /** @type {number} */ (TXml.parseAttr(
526
+ mpd, 'minimumUpdatePeriod', TXml.parseDuration, -1));
497
527
 
498
- const presentationStartTime = XmlUtils.parseAttr(
499
- mpd, 'availabilityStartTime', XmlUtils.parseDate);
500
- let segmentAvailabilityDuration = XmlUtils.parseAttr(
501
- mpd, 'timeShiftBufferDepth', XmlUtils.parseDuration);
528
+ const presentationStartTime = TXml.parseAttr(
529
+ mpd, 'availabilityStartTime', TXml.parseDate);
530
+ let segmentAvailabilityDuration = TXml.parseAttr(
531
+ mpd, 'timeShiftBufferDepth', TXml.parseDuration);
502
532
 
503
533
  const ignoreSuggestedPresentationDelay =
504
534
  this.config_.dash.ignoreSuggestedPresentationDelay;
505
535
  let suggestedPresentationDelay = null;
506
536
  if (!ignoreSuggestedPresentationDelay) {
507
- suggestedPresentationDelay = XmlUtils.parseAttr(
508
- mpd, 'suggestedPresentationDelay', XmlUtils.parseDuration);
537
+ suggestedPresentationDelay = TXml.parseAttr(
538
+ mpd, 'suggestedPresentationDelay', TXml.parseDuration);
509
539
  }
510
540
 
511
541
  const ignoreMaxSegmentDuration =
512
542
  this.config_.dash.ignoreMaxSegmentDuration;
513
543
  let maxSegmentDuration = null;
514
544
  if (!ignoreMaxSegmentDuration) {
515
- maxSegmentDuration = XmlUtils.parseAttr(
516
- mpd, 'maxSegmentDuration', XmlUtils.parseDuration);
545
+ maxSegmentDuration = TXml.parseAttr(
546
+ mpd, 'maxSegmentDuration', TXml.parseDuration);
517
547
  }
518
- const mpdType = mpd.getAttribute('type') || 'static';
548
+ const mpdType = mpd.attributes['type'] || 'static';
519
549
 
520
550
  /** @type {!shaka.media.PresentationTimeline} */
521
551
  let presentationTimeline;
@@ -575,7 +605,7 @@ shaka.dash.DashParser = class {
575
605
  presentationTimeline.setSegmentAvailabilityDuration(
576
606
  segmentAvailabilityDuration);
577
607
 
578
- const profiles = mpd.getAttribute('profiles') || '';
608
+ const profiles = mpd.attributes['profiles'] || '';
579
609
 
580
610
  /** @type {shaka.dash.DashParser.Context} */
581
611
  const context = {
@@ -666,8 +696,8 @@ shaka.dash.DashParser = class {
666
696
  // We only need to do clock sync when we're using presentation start
667
697
  // time. This condition also excludes VOD streams.
668
698
  if (presentationTimeline.usingPresentationStartTime()) {
669
- const XmlUtils = shaka.util.XmlUtils;
670
- const timingElements = XmlUtils.findChildren(mpd, 'UTCTiming');
699
+ const TXml = shaka.util.TXml;
700
+ const timingElements = TXml.findChildren(mpd, 'UTCTiming');
671
701
  const offset = await this.parseUtcTiming_(getBaseUris, timingElements);
672
702
  // Detect calls to stop().
673
703
  if (!this.playerInterface_) {
@@ -706,33 +736,33 @@ shaka.dash.DashParser = class {
706
736
  * Reads maxLatency and maxPlaybackRate properties from service
707
737
  * description element.
708
738
  *
709
- * @param {!Element} mpd
739
+ * @param {!shaka.extern.xml.Node} mpd
710
740
  * @return {?shaka.extern.ServiceDescription}
711
741
  * @private
712
742
  */
713
743
  parseServiceDescription_(mpd) {
714
- const XmlUtils = shaka.util.XmlUtils;
715
- const elem = XmlUtils.findChild(mpd, 'ServiceDescription');
744
+ const TXml = shaka.util.TXml;
745
+ const elem = TXml.findChild(mpd, 'ServiceDescription');
716
746
 
717
747
  if (!elem ) {
718
748
  return null;
719
749
  }
720
750
 
721
- const latencyNode = XmlUtils.findChild(elem, 'Latency');
722
- const playbackRateNode = XmlUtils.findChild(elem, 'PlaybackRate');
751
+ const latencyNode = TXml.findChild(elem, 'Latency');
752
+ const playbackRateNode = TXml.findChild(elem, 'PlaybackRate');
723
753
 
724
- if ((latencyNode && latencyNode.getAttribute('max')) || playbackRateNode) {
725
- const maxLatency = latencyNode && latencyNode.getAttribute('max') ?
726
- parseInt(latencyNode.getAttribute('max'), 10) / 1000 :
754
+ if ((latencyNode && latencyNode.attributes['max']) || playbackRateNode) {
755
+ const maxLatency = latencyNode && latencyNode.attributes['max'] ?
756
+ parseInt(latencyNode.attributes['max'], 10) / 1000 :
727
757
  null;
728
758
  const maxPlaybackRate = playbackRateNode ?
729
- parseFloat(playbackRateNode.getAttribute('max')) :
759
+ parseFloat(playbackRateNode.attributes['max']) :
730
760
  null;
731
- const minLatency = latencyNode && latencyNode.getAttribute('min') ?
732
- parseInt(latencyNode.getAttribute('min'), 10) / 1000 :
761
+ const minLatency = latencyNode && latencyNode.attributes['min'] ?
762
+ parseInt(latencyNode.attributes['min'], 10) / 1000 :
733
763
  null;
734
764
  const minPlaybackRate = playbackRateNode ?
735
- parseFloat(playbackRateNode.getAttribute('min')) :
765
+ parseFloat(playbackRateNode.attributes['min']) :
736
766
  null;
737
767
 
738
768
  return {
@@ -753,7 +783,7 @@ shaka.dash.DashParser = class {
753
783
  *
754
784
  * @param {shaka.dash.DashParser.Context} context
755
785
  * @param {function():!Array.<string>} getBaseUris
756
- * @param {!Element} mpd
786
+ * @param {!shaka.extern.xml.Node} mpd
757
787
  * @return {{
758
788
  * periods: !Array.<shaka.extern.Period>,
759
789
  * duration: ?number,
@@ -762,21 +792,21 @@ shaka.dash.DashParser = class {
762
792
  * @private
763
793
  */
764
794
  parsePeriods_(context, getBaseUris, mpd) {
765
- const XmlUtils = shaka.util.XmlUtils;
766
- const presentationDuration = XmlUtils.parseAttr(
767
- mpd, 'mediaPresentationDuration', XmlUtils.parseDuration);
795
+ const TXml = shaka.util.TXml;
796
+ const presentationDuration = TXml.parseAttr(
797
+ mpd, 'mediaPresentationDuration', TXml.parseDuration);
768
798
 
769
799
  const periods = [];
770
800
  let prevEnd = 0;
771
- const periodNodes = XmlUtils.findChildren(mpd, 'Period');
801
+ const periodNodes = TXml.findChildren(mpd, 'Period');
772
802
  for (let i = 0; i < periodNodes.length; i++) {
773
803
  const elem = periodNodes[i];
774
804
  const next = periodNodes[i + 1];
775
805
  const start = /** @type {number} */ (
776
- XmlUtils.parseAttr(elem, 'start', XmlUtils.parseDuration, prevEnd));
777
- const periodId = elem.id;
806
+ TXml.parseAttr(elem, 'start', TXml.parseDuration, prevEnd));
807
+ const periodId = elem.attributes['id'];
778
808
  const givenDuration =
779
- XmlUtils.parseAttr(elem, 'duration', XmlUtils.parseDuration);
809
+ TXml.parseAttr(elem, 'duration', TXml.parseDuration);
780
810
 
781
811
  let periodDuration = null;
782
812
  if (next) {
@@ -784,7 +814,7 @@ shaka.dash.DashParser = class {
784
814
  // of the following Period is the duration of the media content
785
815
  // represented by this Period."
786
816
  const nextStart =
787
- XmlUtils.parseAttr(next, 'start', XmlUtils.parseDuration);
817
+ TXml.parseAttr(next, 'start', TXml.parseDuration);
788
818
  if (nextStart != null) {
789
819
  periodDuration = nextStart - start;
790
820
  }
@@ -912,7 +942,7 @@ shaka.dash.DashParser = class {
912
942
  */
913
943
  parsePeriod_(context, getBaseUris, periodInfo) {
914
944
  const Functional = shaka.util.Functional;
915
- const XmlUtils = shaka.util.XmlUtils;
945
+ const TXml = shaka.util.TXml;
916
946
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
917
947
 
918
948
  context.period = this.createFrame_(periodInfo.node, null, getBaseUris);
@@ -928,7 +958,7 @@ shaka.dash.DashParser = class {
928
958
  }
929
959
 
930
960
  const eventStreamNodes =
931
- XmlUtils.findChildren(periodInfo.node, 'EventStream');
961
+ TXml.findChildren(periodInfo.node, 'EventStream');
932
962
  const availabilityStart =
933
963
  context.presentationTimeline.getSegmentAvailabilityStart();
934
964
 
@@ -938,7 +968,7 @@ shaka.dash.DashParser = class {
938
968
  }
939
969
 
940
970
  const adaptationSetNodes =
941
- XmlUtils.findChildren(periodInfo.node, 'AdaptationSet');
971
+ TXml.findChildren(periodInfo.node, 'AdaptationSet');
942
972
  const adaptationSets = adaptationSetNodes
943
973
  .map((node) => this.parseAdaptationSet_(context, node))
944
974
  .filter(Functional.isNotNull);
@@ -1047,12 +1077,12 @@ shaka.dash.DashParser = class {
1047
1077
  * Parses an AdaptationSet XML element.
1048
1078
  *
1049
1079
  * @param {shaka.dash.DashParser.Context} context
1050
- * @param {!Element} elem The AdaptationSet element.
1080
+ * @param {!shaka.extern.xml.Node} elem The AdaptationSet element.
1051
1081
  * @return {?shaka.dash.DashParser.AdaptationInfo}
1052
1082
  * @private
1053
1083
  */
1054
1084
  parseAdaptationSet_(context, elem) {
1055
- const XmlUtils = shaka.util.XmlUtils;
1085
+ const TXml = shaka.util.TXml;
1056
1086
  const Functional = shaka.util.Functional;
1057
1087
  const ManifestParserUtils = shaka.util.ManifestParserUtils;
1058
1088
  const ContentType = ManifestParserUtils.ContentType;
@@ -1061,9 +1091,9 @@ shaka.dash.DashParser = class {
1061
1091
  context.adaptationSet = this.createFrame_(elem, context.period, null);
1062
1092
 
1063
1093
  let main = false;
1064
- const roleElements = XmlUtils.findChildren(elem, 'Role');
1094
+ const roleElements = TXml.findChildren(elem, 'Role');
1065
1095
  const roleValues = roleElements.map((role) => {
1066
- return role.getAttribute('value');
1096
+ return role.attributes['value'];
1067
1097
  }).filter(Functional.isNotNull);
1068
1098
 
1069
1099
  // Default kind for text streams is 'subtitle' if unspecified in the
@@ -1075,12 +1105,12 @@ shaka.dash.DashParser = class {
1075
1105
  }
1076
1106
 
1077
1107
  for (const roleElement of roleElements) {
1078
- const scheme = roleElement.getAttribute('schemeIdUri');
1108
+ const scheme = roleElement.attributes['schemeIdUri'];
1079
1109
  if (scheme == null || scheme == 'urn:mpeg:dash:role:2011') {
1080
1110
  // These only apply for the given scheme, but allow them to be specified
1081
1111
  // if there is no scheme specified.
1082
1112
  // See: DASH section 5.8.5.5
1083
- const value = roleElement.getAttribute('value');
1113
+ const value = roleElement.attributes['value'];
1084
1114
  switch (value) {
1085
1115
  case 'main':
1086
1116
  main = true;
@@ -1125,18 +1155,18 @@ shaka.dash.DashParser = class {
1125
1155
  };
1126
1156
 
1127
1157
  const essentialProperties =
1128
- XmlUtils.findChildren(elem, 'EssentialProperty');
1158
+ TXml.findChildren(elem, 'EssentialProperty');
1129
1159
  // ID of real AdaptationSet if this is a trick mode set:
1130
1160
  let trickModeFor = null;
1131
1161
  let isFastSwitching = false;
1132
1162
  let unrecognizedEssentialProperty = false;
1133
1163
  for (const prop of essentialProperties) {
1134
- const schemeId = prop.getAttribute('schemeIdUri');
1164
+ const schemeId = prop.attributes['schemeIdUri'];
1135
1165
  if (schemeId == 'http://dashif.org/guidelines/trickmode') {
1136
- trickModeFor = prop.getAttribute('value');
1166
+ trickModeFor = prop.attributes['value'];
1137
1167
  } else if (schemeId == transferCharacteristicsScheme) {
1138
1168
  videoRange = getVideoRangeFromTransferCharacteristicCICP(
1139
- parseInt(prop.getAttribute('value'), 10),
1169
+ parseInt(prop.attributes['value'], 10),
1140
1170
  );
1141
1171
  } else if (schemeId == colourPrimariesScheme ||
1142
1172
  schemeId == matrixCoefficientsScheme) {
@@ -1148,25 +1178,29 @@ shaka.dash.DashParser = class {
1148
1178
  }
1149
1179
  }
1150
1180
 
1181
+ let lastSegmentNumber = null;
1182
+
1151
1183
  const supplementalProperties =
1152
- XmlUtils.findChildren(elem, 'SupplementalProperty');
1184
+ TXml.findChildren(elem, 'SupplementalProperty');
1153
1185
  for (const prop of supplementalProperties) {
1154
- const schemeId = prop.getAttribute('schemeIdUri');
1155
- if (schemeId == transferCharacteristicsScheme) {
1186
+ const schemeId = prop.attributes['schemeIdUri'];
1187
+ if (schemeId == 'http://dashif.org/guidelines/last-segment-number') {
1188
+ lastSegmentNumber = parseInt(prop.attributes['value'], 10) - 1;
1189
+ } else if (schemeId == transferCharacteristicsScheme) {
1156
1190
  videoRange = getVideoRangeFromTransferCharacteristicCICP(
1157
- parseInt(prop.getAttribute('value'), 10),
1191
+ parseInt(prop.attributes['value'], 10),
1158
1192
  );
1159
1193
  }
1160
1194
  }
1161
1195
 
1162
- const accessibilities = XmlUtils.findChildren(elem, 'Accessibility');
1196
+ const accessibilities = TXml.findChildren(elem, 'Accessibility');
1163
1197
  const LanguageUtils = shaka.util.LanguageUtils;
1164
1198
  const closedCaptions = new Map();
1165
1199
  /** @type {?shaka.media.ManifestParser.AccessibilityPurpose} */
1166
1200
  let accessibilityPurpose;
1167
1201
  for (const prop of accessibilities) {
1168
- const schemeId = prop.getAttribute('schemeIdUri');
1169
- const value = prop.getAttribute('value');
1202
+ const schemeId = prop.attributes['schemeIdUri'];
1203
+ const value = prop.attributes['value'];
1170
1204
  if (schemeId == 'urn:scte:dash:cc:cea-608:2015' ) {
1171
1205
  let channelId = 1;
1172
1206
  if (value != null) {
@@ -1270,7 +1304,7 @@ shaka.dash.DashParser = class {
1270
1304
  }
1271
1305
 
1272
1306
  const contentProtectionElems =
1273
- XmlUtils.findChildren(elem, 'ContentProtection');
1307
+ TXml.findChildren(elem, 'ContentProtection');
1274
1308
  const contentProtection = ContentProtection.parseFromAdaptationSet(
1275
1309
  contentProtectionElems,
1276
1310
  this.config_.dash.ignoreDrmInfo,
@@ -1280,24 +1314,26 @@ shaka.dash.DashParser = class {
1280
1314
  context.adaptationSet.language || 'und');
1281
1315
 
1282
1316
  // This attribute is currently non-standard, but it is supported by Kaltura.
1283
- let label = elem.getAttribute('label');
1317
+ let label = elem.attributes['label'];
1284
1318
 
1285
1319
  // See DASH IOP 4.3 here https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf (page 35)
1286
- const labelElements = XmlUtils.findChildren(elem, 'Label');
1320
+ const labelElements = TXml.findChildren(elem, 'Label');
1287
1321
  if (labelElements && labelElements.length) {
1288
1322
  // NOTE: Right now only one label field is supported.
1289
1323
  const firstLabelElement = labelElements[0];
1290
- if (firstLabelElement.textContent) {
1291
- label = firstLabelElement.textContent;
1324
+ const textContent = shaka.util.TXml.getTextContents(firstLabelElement);
1325
+ if (textContent) {
1326
+ label = textContent;
1292
1327
  }
1293
1328
  }
1294
1329
 
1295
1330
  // Parse Representations into Streams.
1296
- const representations = XmlUtils.findChildren(elem, 'Representation');
1331
+ const representations = TXml.findChildren(elem, 'Representation');
1297
1332
  const streams = representations.map((representation) => {
1298
1333
  const parsedRepresentation = this.parseRepresentation_(context,
1299
1334
  contentProtection, kind, language, label, main, roleValues,
1300
- closedCaptions, representation, accessibilityPurpose);
1335
+ closedCaptions, representation, accessibilityPurpose,
1336
+ lastSegmentNumber);
1301
1337
  if (parsedRepresentation) {
1302
1338
  parsedRepresentation.hdr = parsedRepresentation.hdr || videoRange;
1303
1339
  parsedRepresentation.fastSwitching = isFastSwitching;
@@ -1353,7 +1389,7 @@ shaka.dash.DashParser = class {
1353
1389
  }
1354
1390
 
1355
1391
  const repIds = representations
1356
- .map((node) => { return node.getAttribute('id'); })
1392
+ .map((node) => { return node.attributes['id']; })
1357
1393
  .filter(shaka.util.Functional.isNotNull);
1358
1394
 
1359
1395
  return {
@@ -1379,17 +1415,19 @@ shaka.dash.DashParser = class {
1379
1415
  * @param {boolean} isPrimary
1380
1416
  * @param {!Array.<string>} roles
1381
1417
  * @param {Map.<string, string>} closedCaptions
1382
- * @param {!Element} node
1418
+ * @param {!shaka.extern.xml.Node} node
1383
1419
  * @param {?shaka.media.ManifestParser.AccessibilityPurpose}
1384
1420
  * accessibilityPurpose
1421
+ * @param {?number} lastSegmentNumber
1385
1422
  *
1386
1423
  * @return {?shaka.extern.Stream} The Stream, or null when there is a
1387
1424
  * non-critical parsing error.
1388
1425
  * @private
1389
1426
  */
1390
1427
  parseRepresentation_(context, contentProtection, kind, language, label,
1391
- isPrimary, roles, closedCaptions, node, accessibilityPurpose) {
1392
- const XmlUtils = shaka.util.XmlUtils;
1428
+ isPrimary, roles, closedCaptions, node, accessibilityPurpose,
1429
+ lastSegmentNumber) {
1430
+ const TXml = shaka.util.TXml;
1393
1431
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
1394
1432
 
1395
1433
  context.representation =
@@ -1411,7 +1449,7 @@ shaka.dash.DashParser = class {
1411
1449
  // To avoid NaN at the variant level on broken content, fall back to zero.
1412
1450
  // https://github.com/shaka-project/shaka-player/issues/938#issuecomment-317278180
1413
1451
  context.bandwidth =
1414
- XmlUtils.parseAttr(node, 'bandwidth', XmlUtils.parsePositiveInt) || 0;
1452
+ TXml.parseAttr(node, 'bandwidth', TXml.parsePositiveInt) || 0;
1415
1453
 
1416
1454
  /** @type {?shaka.dash.DashParser.StreamInfo} */
1417
1455
  let streamInfo;
@@ -1422,8 +1460,8 @@ shaka.dash.DashParser = class {
1422
1460
  const isImage = contentType == ContentType.IMAGE;
1423
1461
 
1424
1462
  try {
1425
- /** @type {shaka.extern.aes128Key|undefined} */
1426
- let aes128Key = undefined;
1463
+ /** @type {shaka.extern.aesKey|undefined} */
1464
+ let aesKey = undefined;
1427
1465
  if (contentProtection.aes128Info) {
1428
1466
  const getBaseUris = context.representation.getBaseUris;
1429
1467
  const uris = shaka.util.ManifestParserUtils.resolveUris(
@@ -1432,15 +1470,16 @@ shaka.dash.DashParser = class {
1432
1470
  const request = shaka.net.NetworkingEngine.makeRequest(
1433
1471
  uris, this.config_.retryParameters);
1434
1472
 
1435
- aes128Key = {
1436
- method: 'AES-128',
1473
+ aesKey = {
1474
+ bitsKey: 128,
1475
+ blockCipherMode: 'CBC',
1437
1476
  iv: contentProtection.aes128Info.iv,
1438
1477
  firstMediaSequenceNumber: 0,
1439
1478
  };
1440
1479
 
1441
1480
  // Don't download the key object until the segment is parsed, to
1442
1481
  // avoid a startup delay for long manifests with lots of keys.
1443
- aes128Key.fetchKey = async () => {
1482
+ aesKey.fetchKey = async () => {
1444
1483
  const keyResponse =
1445
1484
  await this.makeNetworkRequest_(request, requestType);
1446
1485
 
@@ -1456,9 +1495,9 @@ shaka.dash.DashParser = class {
1456
1495
  const algorithm = {
1457
1496
  name: 'AES-CBC',
1458
1497
  };
1459
- aes128Key.cryptoKey = await window.crypto.subtle.importKey(
1498
+ aesKey.cryptoKey = await window.crypto.subtle.importKey(
1460
1499
  'raw', keyResponse.data, algorithm, true, ['decrypt']);
1461
- aes128Key.fetchKey = undefined; // No longer needed.
1500
+ aesKey.fetchKey = undefined; // No longer needed.
1462
1501
  };
1463
1502
  }
1464
1503
  const requestSegment = (uris, startByte, endByte, isInit) => {
@@ -1466,17 +1505,17 @@ shaka.dash.DashParser = class {
1466
1505
  };
1467
1506
  if (context.representation.segmentBase) {
1468
1507
  streamInfo = shaka.dash.SegmentBase.createStreamInfo(
1469
- context, requestSegment, aes128Key);
1508
+ context, requestSegment, aesKey);
1470
1509
  } else if (context.representation.segmentList) {
1471
1510
  streamInfo = shaka.dash.SegmentList.createStreamInfo(
1472
- context, this.streamMap_, aes128Key);
1511
+ context, this.streamMap_, aesKey);
1473
1512
  } else if (context.representation.segmentTemplate) {
1474
1513
  const hasManifest = !!this.manifest_;
1475
1514
 
1476
1515
  streamInfo = shaka.dash.SegmentTemplate.createStreamInfo(
1477
1516
  context, requestSegment, this.streamMap_, hasManifest,
1478
1517
  this.config_.dash.initialSegmentLimit, this.periodDurations_,
1479
- aes128Key);
1518
+ aesKey, lastSegmentNumber);
1480
1519
  } else {
1481
1520
  goog.asserts.assert(isText,
1482
1521
  'Must have Segment* with non-text streams.');
@@ -1508,7 +1547,7 @@ shaka.dash.DashParser = class {
1508
1547
  }
1509
1548
 
1510
1549
  const contentProtectionElems =
1511
- XmlUtils.findChildren(node, 'ContentProtection');
1550
+ TXml.findChildren(node, 'ContentProtection');
1512
1551
  const keyId = shaka.dash.ContentProtection.parseFromRepresentation(
1513
1552
  contentProtectionElems, contentProtection,
1514
1553
  this.config_.dash.ignoreDrmInfo,
@@ -1518,12 +1557,12 @@ shaka.dash.DashParser = class {
1518
1557
  // Detect the presence of E-AC3 JOC audio content, using DD+JOC signaling.
1519
1558
  // See: ETSI TS 103 420 V1.2.1 (2018-10)
1520
1559
  const supplementalPropertyElems =
1521
- XmlUtils.findChildren(node, 'SupplementalProperty');
1560
+ TXml.findChildren(node, 'SupplementalProperty');
1522
1561
  const hasJoc = supplementalPropertyElems.some((element) => {
1523
1562
  const expectedUri = 'tag:dolby.com,2018:dash:EC3_ExtensionType:2018';
1524
1563
  const expectedValue = 'JOC';
1525
- return element.getAttribute('schemeIdUri') == expectedUri &&
1526
- element.getAttribute('value') == expectedValue;
1564
+ return element.attributes['schemeIdUri'] == expectedUri &&
1565
+ element.attributes['value'] == expectedValue;
1527
1566
  });
1528
1567
  let spatialAudio = false;
1529
1568
  if (hasJoc) {
@@ -1541,16 +1580,16 @@ shaka.dash.DashParser = class {
1541
1580
  let tilesLayout;
1542
1581
  if (isImage) {
1543
1582
  const essentialPropertyElems =
1544
- XmlUtils.findChildren(node, 'EssentialProperty');
1583
+ TXml.findChildren(node, 'EssentialProperty');
1545
1584
  const thumbnailTileElem = essentialPropertyElems.find((element) => {
1546
1585
  const expectedUris = [
1547
1586
  'http://dashif.org/thumbnail_tile',
1548
1587
  'http://dashif.org/guidelines/thumbnail_tile',
1549
1588
  ];
1550
- return expectedUris.includes(element.getAttribute('schemeIdUri'));
1589
+ return expectedUris.includes(element.attributes['schemeIdUri']);
1551
1590
  });
1552
1591
  if (thumbnailTileElem) {
1553
- tilesLayout = thumbnailTileElem.getAttribute('value');
1592
+ tilesLayout = thumbnailTileElem.attributes['value'];
1554
1593
  }
1555
1594
  // Filter image adaptation sets that has no tilesLayout.
1556
1595
  if (!tilesLayout) {
@@ -1682,6 +1721,15 @@ shaka.dash.DashParser = class {
1682
1721
  this.setUpdateTimer_(updateDelay);
1683
1722
  }
1684
1723
 
1724
+ /**
1725
+ * Update now the manifest
1726
+ *
1727
+ * @private
1728
+ */
1729
+ updateNow_() {
1730
+ this.updateTimer_.tickNow();
1731
+ }
1732
+
1685
1733
  /**
1686
1734
  * Sets the update timer. Does nothing if the manifest does not specify an
1687
1735
  * update period.
@@ -1698,9 +1746,13 @@ shaka.dash.DashParser = class {
1698
1746
  if (this.updatePeriod_ < 0) {
1699
1747
  return;
1700
1748
  }
1749
+ let updateTime = this.updatePeriod_;
1750
+ if (this.config_.dash.updatePeriod >= 0) {
1751
+ updateTime = this.config_.dash.updatePeriod;
1752
+ }
1701
1753
 
1702
1754
  const finalDelay = Math.max(
1703
- this.updatePeriod_ - offset,
1755
+ updateTime - offset,
1704
1756
  this.averageUpdateDuration_.getEstimate());
1705
1757
 
1706
1758
  // We do not run the timer as repeating because part of update is async and
@@ -1711,7 +1763,7 @@ shaka.dash.DashParser = class {
1711
1763
  /**
1712
1764
  * Creates a new inheritance frame for the given element.
1713
1765
  *
1714
- * @param {!Element} elem
1766
+ * @param {!shaka.extern.xml.Node} elem
1715
1767
  * @param {?shaka.dash.DashParser.InheritanceFrame} parent
1716
1768
  * @param {?function():!Array.<string>} getBaseUris
1717
1769
  * @return {shaka.dash.DashParser.InheritanceFrame}
@@ -1721,7 +1773,7 @@ shaka.dash.DashParser = class {
1721
1773
  goog.asserts.assert(parent || getBaseUris,
1722
1774
  'Must provide either parent or getBaseUris');
1723
1775
  const ManifestParserUtils = shaka.util.ManifestParserUtils;
1724
- const XmlUtils = shaka.util.XmlUtils;
1776
+ const TXml = shaka.util.TXml;
1725
1777
  parent = parent || /** @type {shaka.dash.DashParser.InheritanceFrame} */ ({
1726
1778
  contentType: '',
1727
1779
  mimeType: '',
@@ -1736,17 +1788,17 @@ shaka.dash.DashParser = class {
1736
1788
  });
1737
1789
  getBaseUris = getBaseUris || parent.getBaseUris;
1738
1790
 
1739
- const parseNumber = XmlUtils.parseNonNegativeInt;
1740
- const evalDivision = XmlUtils.evalDivision;
1791
+ const parseNumber = TXml.parseNonNegativeInt;
1792
+ const evalDivision = TXml.evalDivision;
1741
1793
 
1742
- const id = elem.getAttribute('id');
1743
- const uriObjs = XmlUtils.findChildren(elem, 'BaseURL');
1794
+ const id = elem.attributes['id'];
1795
+ const uriObjs = TXml.findChildren(elem, 'BaseURL');
1744
1796
  let calculatedBaseUris;
1745
1797
  let someLocationValid = false;
1746
1798
  if (this.contentSteeringManager_) {
1747
1799
  for (const uriObj of uriObjs) {
1748
- const serviceLocation = uriObj.getAttribute('serviceLocation');
1749
- const uri = XmlUtils.getContents(uriObj);
1800
+ const serviceLocation = uriObj.attributes['serviceLocation'];
1801
+ const uri = TXml.getContents(uriObj);
1750
1802
  if (serviceLocation && uri) {
1751
1803
  this.contentSteeringManager_.addLocation(
1752
1804
  id, serviceLocation, uri);
@@ -1755,7 +1807,7 @@ shaka.dash.DashParser = class {
1755
1807
  }
1756
1808
  }
1757
1809
  if (!someLocationValid || !this.contentSteeringManager_) {
1758
- calculatedBaseUris = uriObjs.map(XmlUtils.getContents);
1810
+ calculatedBaseUris = uriObjs.map(TXml.getContents);
1759
1811
  }
1760
1812
 
1761
1813
  const getFrameUris = () => {
@@ -1771,55 +1823,55 @@ shaka.dash.DashParser = class {
1771
1823
  return [];
1772
1824
  };
1773
1825
 
1774
- let contentType = elem.getAttribute('contentType') || parent.contentType;
1775
- const mimeType = elem.getAttribute('mimeType') || parent.mimeType;
1776
- const codecs = elem.getAttribute('codecs') || parent.codecs;
1826
+ let contentType = elem.attributes['contentType'] || parent.contentType;
1827
+ const mimeType = elem.attributes['mimeType'] || parent.mimeType;
1828
+ const codecs = elem.attributes['codecs'] || parent.codecs;
1777
1829
  const frameRate =
1778
- XmlUtils.parseAttr(elem, 'frameRate', evalDivision) || parent.frameRate;
1830
+ TXml.parseAttr(elem, 'frameRate', evalDivision) || parent.frameRate;
1779
1831
  const pixelAspectRatio =
1780
- elem.getAttribute('sar') || parent.pixelAspectRatio;
1832
+ elem.attributes['sar'] || parent.pixelAspectRatio;
1781
1833
  const emsgSchemeIdUris = this.emsgSchemeIdUris_(
1782
- XmlUtils.findChildren(elem, 'InbandEventStream'),
1834
+ TXml.findChildren(elem, 'InbandEventStream'),
1783
1835
  parent.emsgSchemeIdUris);
1784
1836
  const audioChannelConfigs =
1785
- XmlUtils.findChildren(elem, 'AudioChannelConfiguration');
1837
+ TXml.findChildren(elem, 'AudioChannelConfiguration');
1786
1838
  const numChannels =
1787
1839
  this.parseAudioChannels_(audioChannelConfigs) || parent.numChannels;
1788
1840
  const audioSamplingRate =
1789
- XmlUtils.parseAttr(elem, 'audioSamplingRate', parseNumber) ||
1841
+ TXml.parseAttr(elem, 'audioSamplingRate', parseNumber) ||
1790
1842
  parent.audioSamplingRate;
1791
1843
 
1792
1844
  if (!contentType) {
1793
1845
  contentType = shaka.dash.DashParser.guessContentType_(mimeType, codecs);
1794
1846
  }
1795
1847
 
1796
- const segmentBase = XmlUtils.findChild(elem, 'SegmentBase');
1797
- const segmentTemplate = XmlUtils.findChild(elem, 'SegmentTemplate');
1848
+ const segmentBase = TXml.findChild(elem, 'SegmentBase');
1849
+ const segmentTemplate = TXml.findChild(elem, 'SegmentTemplate');
1798
1850
 
1799
1851
  // The availabilityTimeOffset is the sum of all @availabilityTimeOffset
1800
1852
  // values that apply to the adaptation set, via BaseURL, SegmentBase,
1801
1853
  // or SegmentTemplate elements.
1802
1854
  const segmentBaseAto = segmentBase ?
1803
- (XmlUtils.parseAttr(segmentBase, 'availabilityTimeOffset',
1804
- XmlUtils.parseFloat) || 0) : 0;
1855
+ (TXml.parseAttr(segmentBase, 'availabilityTimeOffset',
1856
+ TXml.parseFloat) || 0) : 0;
1805
1857
  const segmentTemplateAto = segmentTemplate ?
1806
- (XmlUtils.parseAttr(segmentTemplate, 'availabilityTimeOffset',
1807
- XmlUtils.parseFloat) || 0) : 0;
1858
+ (TXml.parseAttr(segmentTemplate, 'availabilityTimeOffset',
1859
+ TXml.parseFloat) || 0) : 0;
1808
1860
  const baseUriAto = uriObjs && uriObjs.length ?
1809
- (XmlUtils.parseAttr(uriObjs[0], 'availabilityTimeOffset',
1810
- XmlUtils.parseFloat) || 0) : 0;
1861
+ (TXml.parseAttr(uriObjs[0], 'availabilityTimeOffset',
1862
+ TXml.parseFloat) || 0) : 0;
1811
1863
 
1812
1864
  const availabilityTimeOffset = parent.availabilityTimeOffset + baseUriAto +
1813
1865
  segmentBaseAto + segmentTemplateAto;
1814
1866
 
1815
1867
  let segmentSequenceCadence = null;
1816
1868
  const segmentSequenceProperties =
1817
- XmlUtils.findChild(elem, 'SegmentSequenceProperties');
1869
+ TXml.findChild(elem, 'SegmentSequenceProperties');
1818
1870
  if (segmentSequenceProperties) {
1819
- const sap = XmlUtils.findChild(segmentSequenceProperties, 'SAP');
1871
+ const sap = TXml.findChild(segmentSequenceProperties, 'SAP');
1820
1872
  if (sap) {
1821
- segmentSequenceCadence = XmlUtils.parseAttr(sap, 'cadence',
1822
- XmlUtils.parseInt);
1873
+ segmentSequenceCadence = TXml.parseAttr(sap, 'cadence',
1874
+ TXml.parseInt);
1823
1875
  }
1824
1876
  }
1825
1877
 
@@ -1828,10 +1880,10 @@ shaka.dash.DashParser = class {
1828
1880
  () => ManifestParserUtils.resolveUris(getBaseUris(), getFrameUris()),
1829
1881
  segmentBase: segmentBase || parent.segmentBase,
1830
1882
  segmentList:
1831
- XmlUtils.findChild(elem, 'SegmentList') || parent.segmentList,
1883
+ TXml.findChild(elem, 'SegmentList') || parent.segmentList,
1832
1884
  segmentTemplate: segmentTemplate || parent.segmentTemplate,
1833
- width: XmlUtils.parseAttr(elem, 'width', parseNumber) || parent.width,
1834
- height: XmlUtils.parseAttr(elem, 'height', parseNumber) || parent.height,
1885
+ width: TXml.parseAttr(elem, 'width', parseNumber) || parent.width,
1886
+ height: TXml.parseAttr(elem, 'height', parseNumber) || parent.height,
1835
1887
  contentType: contentType,
1836
1888
  mimeType: mimeType,
1837
1889
  codecs: codecs,
@@ -1839,7 +1891,7 @@ shaka.dash.DashParser = class {
1839
1891
  pixelAspectRatio: pixelAspectRatio,
1840
1892
  emsgSchemeIdUris: emsgSchemeIdUris,
1841
1893
  id: id,
1842
- language: elem.getAttribute('lang'),
1894
+ language: elem.attributes['lang'],
1843
1895
  numChannels: numChannels,
1844
1896
  audioSamplingRate: audioSamplingRate,
1845
1897
  availabilityTimeOffset: availabilityTimeOffset,
@@ -1853,7 +1905,8 @@ shaka.dash.DashParser = class {
1853
1905
  * of the ones parsed from inBandEventStreams and the ones provided in
1854
1906
  * emsgSchemeIdUris.
1855
1907
  *
1856
- * @param {!Array.<!Element>} inBandEventStreams Array of InbandEventStream
1908
+ * @param {!Array.<!shaka.extern.xml.Node>} inBandEventStreams
1909
+ * Array of InbandEventStream
1857
1910
  * elements to parse and add to the returned array.
1858
1911
  * @param {!Array.<string>} emsgSchemeIdUris Array of parsed
1859
1912
  * InbandEventStream schemeIdUri attributes to add to the returned array.
@@ -1864,7 +1917,7 @@ shaka.dash.DashParser = class {
1864
1917
  emsgSchemeIdUris_(inBandEventStreams, emsgSchemeIdUris) {
1865
1918
  const schemeIdUris = emsgSchemeIdUris.slice();
1866
1919
  for (const event of inBandEventStreams) {
1867
- const schemeIdUri = event.getAttribute('schemeIdUri');
1920
+ const schemeIdUri = event.attributes['schemeIdUri'];
1868
1921
  if (!schemeIdUris.includes(schemeIdUri)) {
1869
1922
  schemeIdUris.push(schemeIdUri);
1870
1923
  }
@@ -1873,19 +1926,19 @@ shaka.dash.DashParser = class {
1873
1926
  }
1874
1927
 
1875
1928
  /**
1876
- * @param {!Array.<!Element>} audioChannelConfigs An array of
1929
+ * @param {!Array.<!shaka.extern.xml.Node>} audioChannelConfigs An array of
1877
1930
  * AudioChannelConfiguration elements.
1878
1931
  * @return {?number} The number of audio channels, or null if unknown.
1879
1932
  * @private
1880
1933
  */
1881
1934
  parseAudioChannels_(audioChannelConfigs) {
1882
1935
  for (const elem of audioChannelConfigs) {
1883
- const scheme = elem.getAttribute('schemeIdUri');
1936
+ const scheme = elem.attributes['schemeIdUri'];
1884
1937
  if (!scheme) {
1885
1938
  continue;
1886
1939
  }
1887
1940
 
1888
- const value = elem.getAttribute('value');
1941
+ const value = elem.attributes['value'];
1889
1942
  if (!value) {
1890
1943
  continue;
1891
1944
  }
@@ -2056,15 +2109,15 @@ shaka.dash.DashParser = class {
2056
2109
  * Parses an array of UTCTiming elements.
2057
2110
  *
2058
2111
  * @param {function():!Array.<string>} getBaseUris
2059
- * @param {!Array.<!Element>} elems
2112
+ * @param {!Array.<!shaka.extern.xml.Node>} elems
2060
2113
  * @return {!Promise.<number>}
2061
2114
  * @private
2062
2115
  */
2063
2116
  async parseUtcTiming_(getBaseUris, elems) {
2064
2117
  const schemesAndValues = elems.map((elem) => {
2065
2118
  return {
2066
- scheme: elem.getAttribute('schemeIdUri'),
2067
- value: elem.getAttribute('value'),
2119
+ scheme: elem.attributes['schemeIdUri'],
2120
+ value: elem.attributes['value'],
2068
2121
  };
2069
2122
  });
2070
2123
 
@@ -2128,23 +2181,23 @@ shaka.dash.DashParser = class {
2128
2181
  *
2129
2182
  * @param {number} periodStart
2130
2183
  * @param {?number} periodDuration
2131
- * @param {!Element} elem
2184
+ * @param {!shaka.extern.xml.Node} elem
2132
2185
  * @param {number} availabilityStart
2133
2186
  * @private
2134
2187
  */
2135
2188
  parseEventStream_(periodStart, periodDuration, elem, availabilityStart) {
2136
- const XmlUtils = shaka.util.XmlUtils;
2137
- const parseNumber = XmlUtils.parseNonNegativeInt;
2189
+ const TXml = shaka.util.TXml;
2190
+ const parseNumber = shaka.util.TXml.parseNonNegativeInt;
2138
2191
 
2139
- const schemeIdUri = elem.getAttribute('schemeIdUri') || '';
2140
- const value = elem.getAttribute('value') || '';
2141
- const timescale = XmlUtils.parseAttr(elem, 'timescale', parseNumber) || 1;
2192
+ const schemeIdUri = elem.attributes['schemeIdUri'] || '';
2193
+ const value = elem.attributes['value'] || '';
2194
+ const timescale = TXml.parseAttr(elem, 'timescale', parseNumber) || 1;
2142
2195
 
2143
- for (const eventNode of XmlUtils.findChildren(elem, 'Event')) {
2196
+ for (const eventNode of TXml.findChildren(elem, 'Event')) {
2144
2197
  const presentationTime =
2145
- XmlUtils.parseAttr(eventNode, 'presentationTime', parseNumber) || 0;
2198
+ TXml.parseAttr(eventNode, 'presentationTime', parseNumber) || 0;
2146
2199
  const duration =
2147
- XmlUtils.parseAttr(eventNode, 'duration', parseNumber) || 0;
2200
+ TXml.parseAttr(eventNode, 'duration', parseNumber) || 0;
2148
2201
 
2149
2202
  let startTime = presentationTime / timescale + periodStart;
2150
2203
  let endTime = startTime + (duration / timescale);
@@ -2166,8 +2219,9 @@ shaka.dash.DashParser = class {
2166
2219
  value: value,
2167
2220
  startTime: startTime,
2168
2221
  endTime: endTime,
2169
- id: eventNode.getAttribute('id') || '',
2170
- eventElement: eventNode,
2222
+ id: eventNode.attributes['id'] || '',
2223
+ eventElement: TXml.txmlNodeToDomElement(eventNode),
2224
+ eventNode: eventNode,
2171
2225
  };
2172
2226
 
2173
2227
  this.playerInterface_.onTimelineRegionAdded(region);
@@ -2255,9 +2309,9 @@ shaka.dash.DashParser.RequestSegmentCallback;
2255
2309
 
2256
2310
  /**
2257
2311
  * @typedef {{
2258
- * segmentBase: Element,
2259
- * segmentList: Element,
2260
- * segmentTemplate: Element,
2312
+ * segmentBase: ?shaka.extern.xml.Node,
2313
+ * segmentList: ?shaka.extern.xml.Node,
2314
+ * segmentTemplate: ?shaka.extern.xml.Node,
2261
2315
  * getBaseUris: function():!Array.<string>,
2262
2316
  * width: (number|undefined),
2263
2317
  * height: (number|undefined),
@@ -2279,11 +2333,11 @@ shaka.dash.DashParser.RequestSegmentCallback;
2279
2333
  * A collection of elements and properties which are inherited across levels
2280
2334
  * of a DASH manifest.
2281
2335
  *
2282
- * @property {Element} segmentBase
2336
+ * @property {?shaka.extern.xml.Node} segmentBase
2283
2337
  * The XML node for SegmentBase.
2284
- * @property {Element} segmentList
2338
+ * @property {?shaka.extern.xml.Node} segmentList
2285
2339
  * The XML node for SegmentList.
2286
- * @property {Element} segmentTemplate
2340
+ * @property {?shaka.extern.xml.Node} segmentTemplate
2287
2341
  * The XML node for SegmentTemplate.
2288
2342
  * @property {function():!Array.<string>} getBaseUris
2289
2343
  * Function than returns an array of absolute base URIs for the frame.
@@ -2368,7 +2422,7 @@ shaka.dash.DashParser.Context;
2368
2422
  * @typedef {{
2369
2423
  * start: number,
2370
2424
  * duration: ?number,
2371
- * node: !Element,
2425
+ * node: !shaka.extern.xml.Node,
2372
2426
  * isLastPeriod: boolean
2373
2427
  * }}
2374
2428
  *
@@ -2380,7 +2434,7 @@ shaka.dash.DashParser.Context;
2380
2434
  * @property {?number} duration
2381
2435
  * The duration of the period; or null if the duration is not given. This
2382
2436
  * will be non-null for all periods except the last.
2383
- * @property {!Element} node
2437
+ * @property {!shaka.extern.xml.Node} node
2384
2438
  * The XML Node for the Period.
2385
2439
  * @property {boolean} isLastPeriod
2386
2440
  * Whether this Period is the last one in the manifest.