shaka-player 4.4.1 → 4.4.3

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 (84) hide show
  1. package/.github/workflows/deflake.yaml +8 -5
  2. package/.github/workflows/release-please.yaml +47 -7
  3. package/.github/workflows/shaka-bot-commands/command-test.sh +1 -1
  4. package/CHANGELOG.md +43 -0
  5. package/CONTRIBUTORS +1 -0
  6. package/demo/common/asset.js +5 -0
  7. package/demo/common/assets.js +20 -5
  8. package/demo/common/message_ids.js +1 -1
  9. package/demo/custom.js +5 -5
  10. package/demo/locales/en.json +2 -1
  11. package/demo/locales/source.json +5 -1
  12. package/demo/main.js +1 -1
  13. package/demo/search.js +3 -3
  14. package/dist/demo.compiled.debug.js +75 -73
  15. package/dist/demo.compiled.debug.map +3 -3
  16. package/dist/demo.compiled.js +75 -73
  17. package/dist/demo.compiled.map +3 -3
  18. package/dist/deps.js +2 -2
  19. package/dist/locales.js +31 -31
  20. package/dist/receiver.compiled.debug.js +38 -36
  21. package/dist/receiver.compiled.debug.map +3 -3
  22. package/dist/receiver.compiled.js +38 -36
  23. package/dist/receiver.compiled.map +3 -3
  24. package/dist/shaka-player.compiled.d.ts +533 -296
  25. package/dist/shaka-player.compiled.debug.d.ts +533 -296
  26. package/dist/shaka-player.compiled.debug.externs.js +308 -1
  27. package/dist/shaka-player.compiled.debug.js +280 -265
  28. package/dist/shaka-player.compiled.debug.map +3 -3
  29. package/dist/shaka-player.compiled.externs.js +308 -1
  30. package/dist/shaka-player.compiled.js +1037 -1027
  31. package/dist/shaka-player.compiled.map +4 -4
  32. package/dist/shaka-player.ui.d.ts +577 -340
  33. package/dist/shaka-player.ui.debug.d.ts +577 -340
  34. package/dist/shaka-player.ui.debug.externs.js +308 -1
  35. package/dist/shaka-player.ui.debug.js +341 -326
  36. package/dist/shaka-player.ui.debug.map +3 -3
  37. package/dist/shaka-player.ui.externs.js +308 -1
  38. package/dist/shaka-player.ui.js +1149 -1141
  39. package/dist/shaka-player.ui.map +4 -4
  40. package/docs/tutorials/fairplay.md +8 -0
  41. package/docs/tutorials/faq.md +1 -1
  42. package/docs/tutorials/offline.md +1 -1
  43. package/externs/shaka/text.js +7 -0
  44. package/lib/dash/dash_parser.js +4 -1
  45. package/lib/dash/segment_template.js +3 -0
  46. package/lib/hls/hls_parser.js +68 -28
  47. package/lib/media/media_source_engine.js +1 -1
  48. package/lib/media/segment_index.js +4 -4
  49. package/lib/media/segment_reference.js +6 -1
  50. package/lib/media/streaming_engine.js +14 -24
  51. package/lib/player.js +8 -57
  52. package/lib/text/cue.js +47 -47
  53. package/lib/text/lrc_text_parser.js +8 -0
  54. package/lib/text/mp4_ttml_parser.js +8 -0
  55. package/lib/text/mp4_vtt_parser.js +8 -0
  56. package/lib/text/sbv_text_parser.js +8 -0
  57. package/lib/text/srt_text_parser.js +8 -0
  58. package/lib/text/ssa_text_parser.js +8 -0
  59. package/lib/text/text_engine.js +8 -1
  60. package/lib/text/ttml_text_parser.js +10 -1
  61. package/lib/text/ui_text_displayer.js +49 -3
  62. package/lib/text/vtt_text_parser.js +19 -3
  63. package/lib/transmuxer/ts_transmuxer.js +44 -43
  64. package/lib/util/cmcd_manager.js +6 -1
  65. package/lib/util/error.js +16 -10
  66. package/lib/util/manifest_parser_utils.js +10 -4
  67. package/lib/util/platform.js +14 -0
  68. package/lib/util/player_configuration.js +2 -2
  69. package/lib/util/stream_utils.js +13 -11
  70. package/lib/util/ts_parser.js +73 -16
  71. package/package.json +2 -2
  72. package/test/dash/dash_parser_manifest_unit.js +5 -0
  73. package/test/dash/dash_parser_segment_base_unit.js +5 -0
  74. package/test/dash/dash_parser_segment_list_unit.js +21 -17
  75. package/test/dash/dash_parser_segment_template_unit.js +47 -0
  76. package/test/hls/hls_live_unit.js +33 -0
  77. package/test/hls/hls_parser_unit.js +2 -57
  78. package/test/test/util/dash_parser_util.js +16 -7
  79. package/test/text/text_engine_unit.js +4 -2
  80. package/test/text/ttml_text_parser_unit.js +3 -4
  81. package/test/text/web_vtt_layout_integration.js +0 -1
  82. package/test/transmuxer/transmuxer_integration.js +4 -4
  83. package/test/util/ts_parser_unit.js +1 -1
  84. package/ui/language_utils.js +0 -15
@@ -232,3 +232,11 @@ player.getNetworkingEngine()
232
232
  player.configure('drm.initDataTransform',
233
233
  FairPlayUtils.expressplayInitDataTransform);
234
234
  ```
235
+
236
+ #### Nagra (legacy Apple Media Keys)
237
+
238
+ For integration with Nagra the following can be used:
239
+
240
+ ```js
241
+ shaka.polyfill.PatchedMediaKeysApple.install();
242
+ ```
@@ -153,7 +153,7 @@ In other environments, for example Electron, it is appropriate.
153
153
  In those cases, before Shaka Player loads a manifest, you can register the
154
154
  existing http plugin for `file://` requests:
155
155
  ```js
156
- shaka.net.NetworkingEngine.registerScheme('file', shaka.net.HttpXHRPlugin);
156
+ shaka.net.NetworkingEngine.registerScheme('file', shaka.net.HttpXHRPlugin.parse);
157
157
  ```
158
158
 
159
159
  <hr>
@@ -537,7 +537,7 @@ function downloadContent(manifestUri, title) {
537
537
  'downloaded': Date()
538
538
  };
539
539
 
540
- return window.storage.store(manifestUri, metadata);
540
+ return window.storage.store(manifestUri, metadata).promise;
541
541
  }
542
542
 
543
543
  /*
@@ -48,6 +48,13 @@ shaka.extern.TextParser = class {
48
48
  * @param {boolean} sequenceMode
49
49
  */
50
50
  setSequenceMode(sequenceMode) {}
51
+
52
+ /**
53
+ * Notifies the manifest type.
54
+ *
55
+ * @param {string} manifestType
56
+ */
57
+ setManifestType(manifestType) {}
51
58
  };
52
59
 
53
60
 
@@ -533,7 +533,10 @@ shaka.dash.DashParser = class {
533
533
  // Just update the variants and text streams, which may change as periods
534
534
  // are added or removed.
535
535
  this.manifest_.variants = this.periodCombiner_.getVariants();
536
- this.manifest_.textStreams = this.periodCombiner_.getTextStreams();
536
+ const textStreams = this.periodCombiner_.getTextStreams();
537
+ if (textStreams.length > 0) {
538
+ this.manifest_.textStreams = textStreams;
539
+ }
537
540
  this.manifest_.imageStreams = this.periodCombiner_.getImageStreams();
538
541
 
539
542
  // Re-filter the manifest. This will check any configured restrictions on
@@ -868,6 +868,9 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
868
868
  .unscaledPresentationTimeOffset + range.unscaledStart;
869
869
 
870
870
  const createUrisCb = () => {
871
+ if (!this.templateInfo_) {
872
+ return [];
873
+ }
871
874
  return shaka.dash.TimelineSegmentIndex
872
875
  .createUris_(
873
876
  this.templateInfo_.mediaTemplate,
@@ -787,7 +787,7 @@ shaka.hls.HlsParser = class {
787
787
  // enough info here to determine the presentation type and duration.
788
788
  if (playlist.type == shaka.hls.PlaylistType.MEDIA) {
789
789
  if (this.isLive_()) {
790
- this.changePresentationTimelineToLive_();
790
+ this.changePresentationTimelineToLive_(playlist);
791
791
  const delay = this.getUpdatePlaylistDelay_();
792
792
  this.updatePlaylistTimer_.tickAfter(/* seconds= */ delay);
793
793
  }
@@ -856,7 +856,7 @@ shaka.hls.HlsParser = class {
856
856
 
857
857
  let segmentUris = [firstSegment.absoluteUri];
858
858
  const initSegmentRef = this.getInitSegmentReference_(
859
- playlist.absoluteUri, firstSegment.tags, new Map());
859
+ playlist, firstSegment.tags, new Map());
860
860
  if (initSegmentRef) {
861
861
  segmentUris = initSegmentRef.getUris();
862
862
  }
@@ -900,6 +900,7 @@ shaka.hls.HlsParser = class {
900
900
  const uint8ArrayData = shaka.util.BufferUtils.toUint8(response.data);
901
901
  const tsParser = new shaka.util.TsParser().parse(uint8ArrayData);
902
902
  const tsCodecs = tsParser.getCodecs();
903
+ const videoInfo = tsParser.getVideoInfo();
903
904
  const codecs = [];
904
905
  let hasAudio = false;
905
906
  let hasVideo = false;
@@ -923,7 +924,11 @@ shaka.hls.HlsParser = class {
923
924
  }
924
925
  switch (tsCodecs.video) {
925
926
  case 'avc':
926
- codecs.push('avc1.42E01E');
927
+ if (videoInfo.codec) {
928
+ codecs.push(videoInfo.codec);
929
+ } else {
930
+ codecs.push('avc1.42E01E');
931
+ }
927
932
  hasVideo = true;
928
933
  break;
929
934
  case 'hvc':
@@ -935,14 +940,13 @@ shaka.hls.HlsParser = class {
935
940
  return null;
936
941
  }
937
942
  const onlyAudio = hasAudio && !hasVideo;
938
- const videoResolution = tsParser.getVideoResolution();
939
943
  return {
940
944
  type: onlyAudio ? 'audio' : 'video',
941
945
  mimeType: 'video/mp2t',
942
946
  codecs: codecs.join(', '),
943
947
  language: null,
944
- height: videoResolution.height,
945
- width: videoResolution.width,
948
+ height: videoInfo.height,
949
+ width: videoInfo.width,
946
950
  channelCount: null,
947
951
  sampleRate: null,
948
952
  };
@@ -1777,7 +1781,13 @@ shaka.hls.HlsParser = class {
1777
1781
  goog.asserts.assert(tag.name == 'EXT-X-MEDIA',
1778
1782
  'Should only be called on media tags!');
1779
1783
  const languageValue = tag.getAttributeValue('LANGUAGE');
1780
- const language = this.getLanguage_(languageValue);
1784
+ let language = this.getLanguage_(languageValue);
1785
+ if (!languageValue) {
1786
+ const nameValue = tag.getAttributeValue('NAME');
1787
+ if (nameValue) {
1788
+ language = nameValue;
1789
+ }
1790
+ }
1781
1791
 
1782
1792
  // The GROUP-ID value is a quoted-string that specifies the group to which
1783
1793
  // the Rendition belongs.
@@ -1786,7 +1796,9 @@ shaka.hls.HlsParser = class {
1786
1796
  // The value of INSTREAM-ID is a quoted-string that specifies a Rendition
1787
1797
  // within the segments in the Media Playlist. This attribute is REQUIRED
1788
1798
  // if the TYPE attribute is CLOSED-CAPTIONS.
1789
- const instreamId = tag.getRequiredAttrValue('INSTREAM-ID');
1799
+ // We need replace SERVICE string by our internal svc string.
1800
+ const instreamId = tag.getRequiredAttrValue('INSTREAM-ID')
1801
+ .replace('SERVICE', 'svc');
1790
1802
  if (!this.groupIdToClosedCaptionsMap_.get(groupId)) {
1791
1803
  this.groupIdToClosedCaptionsMap_.set(groupId, new Map());
1792
1804
  }
@@ -2050,7 +2062,7 @@ shaka.hls.HlsParser = class {
2050
2062
  if (this.isLive_() && !wasLive) {
2051
2063
  // Now that we know that the presentation is live, convert the timeline
2052
2064
  // to live.
2053
- this.changePresentationTimelineToLive_();
2065
+ this.changePresentationTimelineToLive_(playlist);
2054
2066
  }
2055
2067
 
2056
2068
  // Copy values from the real stream info to our initial one.
@@ -2766,9 +2778,10 @@ shaka.hls.HlsParser = class {
2766
2778
 
2767
2779
 
2768
2780
  /**
2781
+ * @param {!shaka.hls.Playlist} playlist
2769
2782
  * @private
2770
2783
  */
2771
- changePresentationTimelineToLive_() {
2784
+ changePresentationTimelineToLive_(playlist) {
2772
2785
  // The live edge will be calculated from segments, so we don't need to
2773
2786
  // set a presentation start time. We will assert later that this is
2774
2787
  // working as expected.
@@ -2791,8 +2804,12 @@ shaka.hls.HlsParser = class {
2791
2804
  } else if (this.presentationDelay_) {
2792
2805
  presentationDelay = this.presentationDelay_;
2793
2806
  } else {
2794
- const numberOfSegments = this.config_.hls.liveSegmentsDelay;
2795
- presentationDelay = this.maxTargetDuration_ * numberOfSegments;
2807
+ const playlistSegments = playlist.segments.length;
2808
+ let delaySegments = this.config_.hls.liveSegmentsDelay;
2809
+ if (delaySegments > (playlistSegments - 2)) {
2810
+ delaySegments = Math.max(1, playlistSegments - 2);
2811
+ }
2812
+ presentationDelay = this.maxTargetDuration_ * delaySegments;
2796
2813
  }
2797
2814
 
2798
2815
  this.presentationTimeline_.setPresentationStartTime(0);
@@ -2802,13 +2819,13 @@ shaka.hls.HlsParser = class {
2802
2819
 
2803
2820
  /**
2804
2821
  * Get the InitSegmentReference for a segment if it has a EXT-X-MAP tag.
2805
- * @param {string} playlistUri The absolute uri of the media playlist.
2822
+ * @param {!shaka.hls.Playlist} playlist
2806
2823
  * @param {!Array.<!shaka.hls.Tag>} tags Segment tags
2807
2824
  * @param {!Map.<string, string>} variables
2808
2825
  * @return {shaka.media.InitSegmentReference}
2809
2826
  * @private
2810
2827
  */
2811
- getInitSegmentReference_(playlistUri, tags, variables) {
2828
+ getInitSegmentReference_(playlist, tags, variables) {
2812
2829
  /** @type {?shaka.hls.Tag} */
2813
2830
  const mapTag = shaka.hls.Utils.getFirstTagWithName(tags, 'EXT-X-MAP');
2814
2831
 
@@ -2819,7 +2836,7 @@ shaka.hls.HlsParser = class {
2819
2836
  const verbatimInitSegmentUri = mapTag.getRequiredAttrValue('URI');
2820
2837
  const absoluteInitSegmentUri = this.variableSubstitution_(
2821
2838
  shaka.hls.Utils.constructAbsoluteUri(
2822
- playlistUri, verbatimInitSegmentUri),
2839
+ playlist.absoluteUri, verbatimInitSegmentUri),
2823
2840
  variables);
2824
2841
 
2825
2842
  const mapTagKey = [
@@ -2827,8 +2844,18 @@ shaka.hls.HlsParser = class {
2827
2844
  mapTag.getAttributeValue('BYTERANGE', ''),
2828
2845
  ].join('-');
2829
2846
  if (!this.mapTagToInitSegmentRefMap_.has(mapTagKey)) {
2847
+ /** @type {shaka.extern.HlsAes128Key|undefined} */
2848
+ let aes128Key = undefined;
2849
+ for (const tag of tags) {
2850
+ if (tag.name == 'EXT-X-KEY') {
2851
+ if (tag.getRequiredAttrValue('METHOD') == 'AES-128' &&
2852
+ tag.id < mapTag.id) {
2853
+ aes128Key = this.parseAES128DrmTag_(tag, playlist);
2854
+ }
2855
+ }
2856
+ }
2830
2857
  const initSegmentRef = this.createInitSegmentReference_(
2831
- absoluteInitSegmentUri, mapTag);
2858
+ absoluteInitSegmentUri, mapTag, aes128Key);
2832
2859
  this.mapTagToInitSegmentRefMap_.set(mapTagKey, initSegmentRef);
2833
2860
  }
2834
2861
  return this.mapTagToInitSegmentRefMap_.get(mapTagKey);
@@ -2839,10 +2866,11 @@ shaka.hls.HlsParser = class {
2839
2866
  * playlist.
2840
2867
  * @param {string} absoluteInitSegmentUri
2841
2868
  * @param {!shaka.hls.Tag} mapTag EXT-X-MAP
2869
+ * @param {shaka.extern.HlsAes128Key=} aes128Key
2842
2870
  * @return {!shaka.media.InitSegmentReference}
2843
2871
  * @private
2844
2872
  */
2845
- createInitSegmentReference_(absoluteInitSegmentUri, mapTag) {
2873
+ createInitSegmentReference_(absoluteInitSegmentUri, mapTag, aes128Key) {
2846
2874
  let startByte = 0;
2847
2875
  let endByte = null;
2848
2876
  const byterange = mapTag.getAttributeValue('BYTERANGE');
@@ -2853,12 +2881,26 @@ shaka.hls.HlsParser = class {
2853
2881
  const byteLength = Number(blocks[0]);
2854
2882
  startByte = Number(blocks[1]);
2855
2883
  endByte = startByte + byteLength - 1;
2884
+
2885
+ if (aes128Key) {
2886
+ // MAP segment encrypted with method 'AES-128', when served with
2887
+ // HTTP Range, has the unencrypted size specified in the range.
2888
+ // See: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
2889
+ const length = (endByte + 1) - startByte;
2890
+ if (length % 16) {
2891
+ endByte += (16 - (length % 16));
2892
+ }
2893
+ }
2856
2894
  }
2857
2895
 
2858
2896
  const initSegmentRef = new shaka.media.InitSegmentReference(
2859
2897
  () => [absoluteInitSegmentUri],
2860
2898
  startByte,
2861
- endByte);
2899
+ endByte,
2900
+ /* mediaQuality= */ null,
2901
+ /* timescale= */ null,
2902
+ /* segmentData= */ null,
2903
+ aes128Key);
2862
2904
  return initSegmentRef;
2863
2905
  }
2864
2906
 
@@ -2873,15 +2915,13 @@ shaka.hls.HlsParser = class {
2873
2915
  * @param {string} absoluteMediaPlaylistUri
2874
2916
  * @param {string} type
2875
2917
  * @param {string} mimeType
2876
- * @param {number} timestampOffset
2877
2918
  * @param {shaka.extern.HlsAes128Key=} hlsAes128Key
2878
2919
  * @return {shaka.media.SegmentReference}
2879
2920
  * @private
2880
2921
  */
2881
2922
  createSegmentReference_(
2882
2923
  initSegmentReference, previousReference, hlsSegment, startTime,
2883
- variables, absoluteMediaPlaylistUri, type, mimeType, timestampOffset,
2884
- hlsAes128Key) {
2924
+ variables, absoluteMediaPlaylistUri, type, mimeType, hlsAes128Key) {
2885
2925
  const tags = hlsSegment.tags;
2886
2926
  const extinfTag =
2887
2927
  shaka.hls.Utils.getFirstTagWithName(tags, 'EXTINF');
@@ -3018,7 +3058,7 @@ shaka.hls.HlsParser = class {
3018
3058
  pStartByte,
3019
3059
  pEndByte,
3020
3060
  initSegmentReference,
3021
- /* timestampOffset= */ 0, // This value is ignored in sequence mode.
3061
+ /* timestampOffset= */ 0,
3022
3062
  /* appendWindowStart= */ 0,
3023
3063
  /* appendWindowEnd= */ Infinity,
3024
3064
  /* partialReferences= */ [],
@@ -3063,8 +3103,11 @@ shaka.hls.HlsParser = class {
3063
3103
  return null;
3064
3104
  }
3065
3105
  endTime = startTime + duration;
3066
- } else {
3106
+ } else if (partialSegmentRefs.length) {
3067
3107
  endTime = partialSegmentRefs[partialSegmentRefs.length - 1].endTime;
3108
+ } else {
3109
+ // Skip segments without duration and without partialsegments
3110
+ return null;
3068
3111
  }
3069
3112
 
3070
3113
  if (segmentWithByteRangeOptimization) {
@@ -3127,7 +3170,7 @@ shaka.hls.HlsParser = class {
3127
3170
  startByte,
3128
3171
  endByte,
3129
3172
  initSegmentReference,
3130
- timestampOffset, // This value is ignored in sequence mode.
3173
+ /* timestampOffset= */ 0,
3131
3174
  /* appendWindowStart= */ 0,
3132
3175
  /* appendWindowEnd= */ Infinity,
3133
3176
  partialSegmentRefs,
@@ -3226,7 +3269,6 @@ shaka.hls.HlsParser = class {
3226
3269
  const references = [];
3227
3270
 
3228
3271
  let previousReference = null;
3229
- let lastDiscontinuityStartTime = firstStartTime;
3230
3272
 
3231
3273
  /** @type {!Array.<{bitrate: number, duration: number}>} */
3232
3274
  const bitrates = [];
@@ -3241,7 +3283,6 @@ shaka.hls.HlsParser = class {
3241
3283
  item.tags, 'EXT-X-DISCONTINUITY');
3242
3284
  if (discontinuityTag) {
3243
3285
  discontinuitySequence++;
3244
- lastDiscontinuityStartTime = startTime;
3245
3286
  }
3246
3287
 
3247
3288
  // Apply new AES-128 tags as you see them, keeping a running total.
@@ -3257,7 +3298,7 @@ shaka.hls.HlsParser = class {
3257
3298
 
3258
3299
  mediaSequenceToStartTime.set(position, startTime);
3259
3300
 
3260
- initSegmentRef = this.getInitSegmentReference_(playlist.absoluteUri,
3301
+ initSegmentRef = this.getInitSegmentReference_(playlist,
3261
3302
  item.tags, variables);
3262
3303
 
3263
3304
  // If the stream is low latency and the user has not configured the
@@ -3281,7 +3322,6 @@ shaka.hls.HlsParser = class {
3281
3322
  playlist.absoluteUri,
3282
3323
  type,
3283
3324
  mimeType,
3284
- lastDiscontinuityStartTime,
3285
3325
  hlsAes128Key);
3286
3326
 
3287
3327
  if (reference) {
@@ -492,7 +492,7 @@ shaka.media.MediaSourceEngine = class {
492
492
  this.textEngine_ = new shaka.text.TextEngine(this.textDisplayer_);
493
493
  }
494
494
  this.textEngine_.initParser(mimeType, sequenceMode,
495
- external || this.segmentRelativeVttTiming_);
495
+ external || this.segmentRelativeVttTiming_, this.manifestType_);
496
496
  }
497
497
 
498
498
  /**
@@ -708,7 +708,7 @@ shaka.media.MetaSegmentIndex = class extends shaka.media.SegmentIndex {
708
708
  }
709
709
 
710
710
  numPassedInEarlierIndexes += index.numEvicted_ +
711
- index.references.length;
711
+ index.getNumReferences();
712
712
  }
713
713
 
714
714
  return null;
@@ -732,9 +732,9 @@ shaka.media.MetaSegmentIndex = class extends shaka.media.SegmentIndex {
732
732
  return reference;
733
733
  }
734
734
 
735
- numPassedInEarlierIndexes += index.numEvicted_ +
736
- index.references.length;
737
- sawSegments = sawSegments || index.references.length != 0;
735
+ const num = index.getNumReferences();
736
+ numPassedInEarlierIndexes += index.numEvicted_ + num;
737
+ sawSegments = sawSegments || num != 0;
738
738
  }
739
739
 
740
740
  return null;
@@ -32,9 +32,11 @@ shaka.media.InitSegmentReference = class {
32
32
  * the quality of the media associated with this init segment.
33
33
  * @param {(null|number)=} timescale
34
34
  * @param {(null|BufferSource)=} segmentData
35
+ * @param {?shaka.extern.HlsAes128Key=} aes128Key
36
+ * The segment's AES-128-CBC full segment encryption key and iv.
35
37
  */
36
38
  constructor(uris, startByte, endByte, mediaQuality = null, timescale = null,
37
- segmentData = null) {
39
+ segmentData = null, aes128Key = null) {
38
40
  /** @type {function():!Array.<string>} */
39
41
  this.getUris = uris;
40
42
 
@@ -52,6 +54,9 @@ shaka.media.InitSegmentReference = class {
52
54
 
53
55
  /** @type {BufferSource|null} */
54
56
  this.segmentData = segmentData;
57
+
58
+ /** @type {?shaka.extern.HlsAes128Key} */
59
+ this.hlsAes128Key = aes128Key;
55
60
  }
56
61
 
57
62
  /**
@@ -1409,15 +1409,11 @@ shaka.media.StreamingEngine = class {
1409
1409
  'ReadableStream is not supported by the browser.');
1410
1410
  }
1411
1411
  const fetchSegment = this.fetch_(mediaState, reference);
1412
- let result = await fetchSegment;
1412
+ const result = await fetchSegment;
1413
1413
  this.destroyer_.ensureNotDestroyed();
1414
1414
  if (this.fatalError_) {
1415
1415
  return;
1416
1416
  }
1417
- if (reference.hlsAes128Key) {
1418
- goog.asserts.assert(iter, 'mediaState.segmentIterator should exist');
1419
- result = await this.aes128Decrypt_(result, reference, iter);
1420
- }
1421
1417
  this.destroyer_.ensureNotDestroyed();
1422
1418
 
1423
1419
  // If the text stream gets switched between fetch_() and append_(), the
@@ -1502,13 +1498,13 @@ shaka.media.StreamingEngine = class {
1502
1498
 
1503
1499
  /**
1504
1500
  * @param {!BufferSource} rawResult
1505
- * @param {!shaka.media.SegmentReference} reference
1501
+ * @param {shaka.extern.HlsAes128Key} aes128Key
1506
1502
  * @param {!shaka.media.SegmentIterator} iter
1507
1503
  * @return {!Promise.<!BufferSource>} finalResult
1508
1504
  * @private
1509
1505
  */
1510
- async aes128Decrypt_(rawResult, reference, iter) {
1511
- const key = reference.hlsAes128Key;
1506
+ async aes128Decrypt_(rawResult, aes128Key, iter) {
1507
+ const key = aes128Key;
1512
1508
  if (!key.cryptoKey) {
1513
1509
  goog.asserts.assert(key.fetchKey, 'If AES-128 cryptoKey was not ' +
1514
1510
  'preloaded, fetchKey function should be provided');
@@ -1818,10 +1814,10 @@ shaka.media.StreamingEngine = class {
1818
1814
  }
1819
1815
  }
1820
1816
 
1821
- const lastDiscontinuitySequence =
1822
- mediaState.lastSegmentReference ?
1823
- mediaState.lastSegmentReference.discontinuitySequence : null;
1824
1817
  if (this.manifest_.sequenceMode) {
1818
+ const lastDiscontinuitySequence =
1819
+ mediaState.lastSegmentReference ?
1820
+ mediaState.lastSegmentReference.discontinuitySequence : null;
1825
1821
  // Across discontinuity bounds, we should resync timestamps for
1826
1822
  // sequence mode playbacks. The next segment appended should
1827
1823
  // land at its theoretical timestamp from the segment index.
@@ -1831,18 +1827,6 @@ shaka.media.StreamingEngine = class {
1831
1827
  operations.push(this.playerInterface_.mediaSourceEngine.resync(
1832
1828
  mediaState.type, reference.startTime));
1833
1829
  }
1834
- } else if (this.manifest_.ignoreManifestTimestampsInSegmentsMode) {
1835
- // In segments mode, we need to resync to set the timestampOffset
1836
- // to the start of the current discontinuity sequence. This is
1837
- // because individual discontinuity sequences may have internal
1838
- // timestamps that overlap, so we adjust the timestampOffset to avoid
1839
- // having the SourceBuffer get overwritten.
1840
- if (reference.discontinuitySequence != lastDiscontinuitySequence) {
1841
- operations.push(
1842
- this.playerInterface_.mediaSourceEngine.resync(
1843
- mediaState.type,
1844
- reference.timestampOffset));
1845
- }
1846
1830
  }
1847
1831
 
1848
1832
  await Promise.all(operations);
@@ -2200,7 +2184,13 @@ shaka.media.StreamingEngine = class {
2200
2184
  mediaState.operation = op;
2201
2185
  const response = await op.promise;
2202
2186
  mediaState.operation = null;
2203
- return response.data;
2187
+ let result = response.data;
2188
+ if (reference.hlsAes128Key) {
2189
+ const iter = mediaState.segmentIterator;
2190
+ goog.asserts.assert(iter, 'mediaState.segmentIterator should exist');
2191
+ result = await this.aes128Decrypt_(result, reference.hlsAes128Key, iter);
2192
+ }
2193
+ return result;
2204
2194
  }
2205
2195
 
2206
2196
  /**
package/lib/player.js CHANGED
@@ -2663,16 +2663,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2663
2663
  return;
2664
2664
  }
2665
2665
 
2666
- this.selectAudioLanguage(preferredAudioLanguage);
2667
-
2668
2666
  const preferredVariantRole = this.config_.preferredVariantRole;
2669
-
2670
- // If the user has not selected a role preference, the previous match is
2671
- // selected.
2672
- if (preferredVariantRole == '') {
2673
- return;
2674
- }
2675
-
2676
2667
  this.selectAudioLanguage(preferredAudioLanguage, preferredVariantRole);
2677
2668
  }
2678
2669
 
@@ -2683,7 +2674,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2683
2674
  */
2684
2675
  setupPreferredTextOnSrc_() {
2685
2676
  const preferredTextLanguage = this.config_.preferredTextLanguage;
2686
- const preferForcedSubs = this.config_.preferForcedSubs;
2687
2677
 
2688
2678
  // If the user has not selected a preference, the browser preference is
2689
2679
  // left.
@@ -2691,16 +2681,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2691
2681
  return;
2692
2682
  }
2693
2683
 
2694
- this.selectTextLanguage(preferredTextLanguage, '', preferForcedSubs);
2695
-
2684
+ const preferForcedSubs = this.config_.preferForcedSubs;
2696
2685
  const preferredTextRole = this.config_.preferredTextRole;
2697
2686
 
2698
- // If the user has not selected a role preference, the previous match is
2699
- // selected.
2700
- if (preferredTextRole == '') {
2701
- return;
2702
- }
2703
-
2704
2687
  this.selectTextLanguage(preferredTextLanguage, preferredTextRole,
2705
2688
  preferForcedSubs);
2706
2689
  }
@@ -4199,8 +4182,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4199
4182
  * @export
4200
4183
  */
4201
4184
  selectAudioLanguage(language, role, channelsCount = 0, safeMargin = 0) {
4202
- const LanguageUtils = shaka.util.LanguageUtils;
4203
-
4204
4185
  if (this.manifest_ && this.playhead_) {
4205
4186
  this.currentAdaptationSetCriteria_ =
4206
4187
  new shaka.media.PreferenceBasedCriteria(language, role || '',
@@ -4238,33 +4219,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4238
4219
  // If we haven't switched yet, just use ABR to find a new track.
4239
4220
  this.chooseVariantAndSwitch_();
4240
4221
  } else if (this.video_ && this.video_.audioTracks) {
4241
- const audioTracks = Array.from(this.video_.audioTracks);
4242
- const selectedLanguage = LanguageUtils.normalize(language);
4243
-
4244
- let languageMatch = null;
4245
- let languageAndRoleMatch = null;
4246
-
4247
- for (const audioTrack of audioTracks) {
4248
- const track = shaka.util.StreamUtils.html5AudioTrackToTrack(audioTrack);
4249
-
4250
- if (LanguageUtils.normalize(track.language) == selectedLanguage) {
4251
- languageMatch = audioTrack;
4252
-
4253
- if (role) {
4254
- if (track.roles.includes(role)) {
4255
- languageAndRoleMatch = audioTrack;
4256
- }
4257
- } else { // no role
4258
- if (track.roles.length == 0) {
4259
- languageAndRoleMatch = audioTrack;
4260
- }
4261
- }
4262
- }
4263
- }
4264
- if (languageAndRoleMatch) {
4265
- this.switchHtml5Track_(languageAndRoleMatch);
4266
- } else if (languageMatch) {
4267
- this.switchHtml5Track_(languageMatch);
4222
+ const track = shaka.util.StreamUtils.filterStreamsByLanguageAndRole(
4223
+ this.getVariantTracks(), language, role || '', false)[0];
4224
+ if (track) {
4225
+ this.selectVariantTrack(track);
4268
4226
  }
4269
4227
  }
4270
4228
  }
@@ -4280,8 +4238,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4280
4238
  * @export
4281
4239
  */
4282
4240
  selectTextLanguage(language, role, forced = false) {
4283
- const LanguageUtils = shaka.util.LanguageUtils;
4284
-
4285
4241
  if (this.manifest_ && this.playhead_) {
4286
4242
  this.currentTextLanguage_ = language;
4287
4243
  this.currentTextRole_ = role || '';
@@ -4302,13 +4258,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4302
4258
  }
4303
4259
  }
4304
4260
  } else {
4305
- const selectedLanguage = LanguageUtils.normalize(language);
4306
-
4307
- const track = this.getTextTracks().find((t) => {
4308
- return LanguageUtils.normalize(t.language) == selectedLanguage &&
4309
- (!role || t.roles.includes(role)) && t.forced == forced;
4310
- });
4311
-
4261
+ const track = shaka.util.StreamUtils.filterStreamsByLanguageAndRole(
4262
+ this.getTextTracks(), language, role || '', forced)[0];
4312
4263
  if (track) {
4313
4264
  this.selectTextTrack(track);
4314
4265
  }
@@ -7224,7 +7175,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
7224
7175
  * @define {string} A version number taken from git at compile time.
7225
7176
  * @export
7226
7177
  */
7227
- shaka.Player.version = 'v4.4.1-uncompiled';
7178
+ shaka.Player.version = 'v4.4.3-uncompiled';
7228
7179
 
7229
7180
  // Initialize the deprecation system using the version string we just set
7230
7181
  // on the player.