shaka-player 4.3.4 → 4.3.6

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 (111) hide show
  1. package/.github/workflows/build-and-test.yaml +4 -4
  2. package/.github/workflows/demo-version-index.yaml +6 -0
  3. package/.github/workflows/selenium-lab-tests.yaml +78 -17
  4. package/.github/workflows/update-screenshots.yaml +142 -0
  5. package/AUTHORS +2 -1
  6. package/CHANGELOG.md +56 -0
  7. package/CONTRIBUTORS +4 -1
  8. package/demo/common/asset.js +15 -0
  9. package/demo/common/assets.js +4 -2
  10. package/demo/common/message_ids.js +1 -0
  11. package/demo/custom.js +19 -0
  12. package/demo/locales/en.json +1 -0
  13. package/demo/locales/source.json +4 -0
  14. package/demo/main.js +14 -0
  15. package/dist/controls.css +2 -2
  16. package/dist/controls.css.map +1 -1
  17. package/dist/demo.compiled.debug.js +184 -311
  18. package/dist/demo.compiled.debug.map +4 -4
  19. package/dist/demo.compiled.js +184 -311
  20. package/dist/demo.compiled.map +4 -4
  21. package/dist/deps.js +2 -2
  22. package/dist/locales.js +29 -29
  23. package/dist/receiver.compiled.debug.js +51 -80
  24. package/dist/receiver.compiled.debug.map +4 -4
  25. package/dist/receiver.compiled.js +51 -80
  26. package/dist/receiver.compiled.map +4 -4
  27. package/dist/shaka-player.compiled.d.ts +19 -3
  28. package/dist/shaka-player.compiled.debug.d.ts +19 -3
  29. package/dist/shaka-player.compiled.debug.externs.js +20 -14
  30. package/dist/shaka-player.compiled.debug.js +291 -283
  31. package/dist/shaka-player.compiled.debug.map +4 -4
  32. package/dist/shaka-player.compiled.externs.js +20 -14
  33. package/dist/shaka-player.compiled.js +830 -825
  34. package/dist/shaka-player.compiled.map +3 -3
  35. package/dist/shaka-player.ui.d.ts +19 -3
  36. package/dist/shaka-player.ui.debug.d.ts +19 -3
  37. package/dist/shaka-player.ui.debug.externs.js +8 -2
  38. package/dist/shaka-player.ui.debug.js +301 -292
  39. package/dist/shaka-player.ui.debug.map +3 -3
  40. package/dist/shaka-player.ui.externs.js +8 -2
  41. package/dist/shaka-player.ui.js +927 -922
  42. package/dist/shaka-player.ui.map +3 -3
  43. package/docs/tutorials/a11y.md +0 -4
  44. package/docs/tutorials/ad_monetization.md +0 -4
  45. package/docs/tutorials/basic-usage.md +0 -5
  46. package/docs/tutorials/config.md +0 -5
  47. package/docs/tutorials/debugging.md +0 -5
  48. package/docs/tutorials/drm-config.md +0 -5
  49. package/docs/tutorials/errors.md +94 -0
  50. package/docs/tutorials/fairplay.md +4 -4
  51. package/docs/tutorials/index.json +2 -0
  52. package/docs/tutorials/license-server-auth.md +0 -5
  53. package/docs/tutorials/license-wrapping.md +0 -5
  54. package/docs/tutorials/network-and-buffering-config.md +0 -5
  55. package/docs/tutorials/ui-customization.md +0 -5
  56. package/docs/tutorials/ui.md +0 -7
  57. package/docs/tutorials/welcome.md +0 -5
  58. package/docs/tutorials/widevine-service-certs.md +45 -0
  59. package/externs/ima.js +9 -0
  60. package/externs/network_information.js +7 -2
  61. package/externs/shaka/abr_manager.js +6 -0
  62. package/externs/shaka/net.js +1 -0
  63. package/externs/shaka/player.js +13 -7
  64. package/lib/abr/simple_abr_manager.js +27 -3
  65. package/lib/ads/client_side_ad_manager.js +11 -5
  66. package/lib/dash/dash_parser.js +49 -48
  67. package/lib/debug/log.js +9 -13
  68. package/lib/hls/hls_parser.js +23 -6
  69. package/lib/media/drm_engine.js +4 -2
  70. package/lib/media/media_source_engine.js +27 -9
  71. package/lib/media/presentation_timeline.js +9 -2
  72. package/lib/media/segment_index.js +2 -0
  73. package/lib/media/segment_reference.js +3 -2
  74. package/lib/media/streaming_engine.js +31 -7
  75. package/lib/media/transmuxer.js +13 -7
  76. package/lib/media/video_wrapper.js +3 -3
  77. package/lib/net/http_fetch_plugin.js +79 -57
  78. package/lib/net/networking_engine.js +1 -0
  79. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  80. package/lib/player.js +24 -3
  81. package/lib/polyfill/media_capabilities.js +15 -8
  82. package/lib/polyfill/mediasource.js +24 -2
  83. package/lib/text/mp4_vtt_parser.js +4 -0
  84. package/lib/text/text_engine.js +1 -0
  85. package/lib/text/ui_text_displayer.js +1 -0
  86. package/lib/text/vtt_text_parser.js +4 -5
  87. package/lib/util/manifest_parser_utils.js +1 -2
  88. package/lib/util/mime_utils.js +12 -1
  89. package/lib/util/periods.js +5 -5
  90. package/lib/util/stream_utils.js +28 -16
  91. package/maintained-branches.md +2 -3
  92. package/package.json +1 -1
  93. package/test/dash/dash_parser_live_unit.js +3 -2
  94. package/test/hls/hls_parser_unit.js +156 -0
  95. package/test/media/content_workarounds_unit.js +43 -0
  96. package/test/media/drm_engine_integration.js +4 -17
  97. package/test/media/streaming_engine_unit.js +6 -1
  98. package/test/net/networking_engine_unit.js +6 -1
  99. package/test/player_integration.js +39 -0
  100. package/test/player_unit.js +57 -0
  101. package/test/polyfill/media_capabilities_unit.js +22 -22
  102. package/test/test/assets/text-clip-alt.vtt +63 -0
  103. package/test/test/util/fake_drm_engine.js +3 -0
  104. package/test/test/util/fake_media_source_engine.js +4 -0
  105. package/test/test/util/simple_fakes.js +6 -0
  106. package/test/test/util/test_scheme.js +9 -14
  107. package/test/text/mp4_vtt_parser_unit.js +8 -0
  108. package/test/text/vtt_text_parser_unit.js +26 -2
  109. package/test/text/web_vtt_layout_integration.js +0 -3
  110. package/test/util/mime_utils_unit.js +10 -0
  111. package/ui/less/containers.less +4 -0
@@ -9,7 +9,6 @@ goog.provide('shaka.polyfill.MediaCapabilities');
9
9
  goog.require('shaka.log');
10
10
  goog.require('shaka.media.Capabilities');
11
11
  goog.require('shaka.polyfill');
12
- goog.require('shaka.util.Error');
13
12
  goog.require('shaka.util.Platform');
14
13
 
15
14
 
@@ -120,6 +119,19 @@ shaka.polyfill.MediaCapabilities = class {
120
119
  if (shaka.util.Platform.isChromecast()) {
121
120
  isSupported =
122
121
  shaka.polyfill.MediaCapabilities.canCastDisplayType_(videoConfig);
122
+ } else if (shaka.util.Platform.isTizen()) {
123
+ let extendedType = videoConfig.contentType;
124
+ if (videoConfig.width && videoConfig.height) {
125
+ extendedType += `; width=${videoConfig.width}`;
126
+ extendedType += `; height=${videoConfig.height}`;
127
+ }
128
+ if (videoConfig.framerate) {
129
+ extendedType += `; framerate=${videoConfig.framerate}`;
130
+ }
131
+ if (videoConfig.bitrate) {
132
+ extendedType += `; bitrate=${videoConfig.bitrate}`;
133
+ }
134
+ isSupported = Capabilities.isTypeSupported(extendedType);
123
135
  } else {
124
136
  isSupported = Capabilities.isTypeSupported(videoConfig.contentType);
125
137
  }
@@ -230,13 +242,8 @@ shaka.polyfill.MediaCapabilities = class {
230
242
  * @private
231
243
  */
232
244
  static canCastDisplayType_(videoConfig) {
233
- if (!(window.cast)) {
234
- shaka.log.error('Expected cast namespace to be available!');
235
- throw new shaka.util.Error(
236
- shaka.util.Error.Severity.CRITICAL,
237
- shaka.util.Error.Category.CAST,
238
- shaka.util.Error.Code.CAST_API_UNAVAILABLE);
239
- } else if (!(cast.__platform__ && cast.__platform__.canDisplayType)) {
245
+ if (!(window.cast &&
246
+ cast.__platform__ && cast.__platform__.canDisplayType)) {
240
247
  shaka.log.warning('Expected cast APIs to be available! Falling back to ' +
241
248
  'shaka.media.Capabilities.isTypeSupported() for type support.');
242
249
  return shaka.media.Capabilities.isTypeSupported(videoConfig.contentType);
@@ -53,14 +53,19 @@ shaka.polyfill.MediaSource = class {
53
53
  // Offsetting the end of the removal range seems to help.
54
54
  // Bug filed: https://bugs.webkit.org/show_bug.cgi?id=177884
55
55
  shaka.polyfill.MediaSource.patchRemovalRange_();
56
- } else {
57
- shaka.log.info('Patching Safari 13 MSE bugs.');
56
+ } else if (safariVersion <= 15) {
57
+ shaka.log.info('Patching Safari 13 & 14 & 15 MSE bugs.');
58
58
  // Safari 13 does not correctly implement abort() on SourceBuffer.
59
59
  // Calling abort() before appending a segment causes that segment to be
60
60
  // incomplete in the buffer.
61
61
  // Bug filed: https://bugs.webkit.org/show_bug.cgi?id=165342
62
62
  shaka.polyfill.MediaSource.stubAbort_();
63
63
  }
64
+ } else if (shaka.util.Platform.isEdge()) {
65
+ shaka.log.info('Rejecting TS container.');
66
+ // TS content is broken on Edge in general.
67
+ // See https://github.com/shaka-project/shaka-player/issues/4955
68
+ shaka.polyfill.MediaSource.rejectContainer_('mp2t');
64
69
  } else if (shaka.util.Platform.isTizen2() ||
65
70
  shaka.util.Platform.isTizen3() ||
66
71
  shaka.util.Platform.isTizen4()) {
@@ -122,6 +127,23 @@ shaka.polyfill.MediaSource = class {
122
127
  };
123
128
  }
124
129
 
130
+ /**
131
+ * Patch |MediaSource.isTypeSupported| to always reject |container|. This is
132
+ * used when we know that we are on a platform that does not work well with
133
+ * a given container.
134
+ *
135
+ * @param {string} container
136
+ * @private
137
+ */
138
+ static rejectContainer_(container) {
139
+ const isTypeSupported = MediaSource.isTypeSupported;
140
+
141
+ MediaSource.isTypeSupported = (mimeType) => {
142
+ const actualContainer = shaka.util.MimeUtils.getContainerType(mimeType);
143
+ return actualContainer != container && isTypeSupported(mimeType);
144
+ };
145
+ }
146
+
125
147
  /**
126
148
  * Patch |MediaSource.isTypeSupported| to always reject |codec|. This is used
127
149
  * when we know that we are on a platform that does not work well with a given
@@ -97,6 +97,10 @@ shaka.text.Mp4VttParser = class {
97
97
  * @export
98
98
  */
99
99
  parseMedia(data, time) {
100
+ if (!data.length) {
101
+ return [];
102
+ }
103
+
100
104
  if (!this.timescale_) {
101
105
  // Missing timescale for VTT content. We should have seen the init
102
106
  // segment.
@@ -139,6 +139,7 @@ shaka.text.TextEngine = class {
139
139
  // into TextEngine and TextDisplayer.
140
140
  if (mimeType == shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE ||
141
141
  mimeType == shaka.util.MimeUtils.CEA708_CLOSED_CAPTION_MIMETYPE) {
142
+ this.parser_ = null;
142
143
  return;
143
144
  }
144
145
 
@@ -474,6 +474,7 @@ shaka.text.UITextDisplayer = class {
474
474
  wrapper = shaka.util.Dom.createHTMLElement('span');
475
475
  wrapper.classList.add('shaka-text-wrapper');
476
476
  wrapper.style.backgroundColor = cue.backgroundColor;
477
+ wrapper.style.lineHeight = 'normal';
477
478
  cueElement.appendChild(wrapper);
478
479
  }
479
480
 
@@ -391,8 +391,7 @@ shaka.text.VttTextParser = class {
391
391
  end += timeOffset;
392
392
 
393
393
  // Get the payload.
394
- const payload = VttTextParser.htmlUnescape_(
395
- text.slice(1).join('\n').trim());
394
+ const payload = text.slice(1).join('\n').trim();
396
395
 
397
396
  let cue = null;
398
397
  if (styles.has('global')) {
@@ -450,7 +449,7 @@ shaka.text.VttTextParser = class {
450
449
  const childNode = childNodes[0];
451
450
  if (childNode.nodeType == Node.TEXT_NODE ||
452
451
  childNode.nodeType == Node.CDATA_SECTION_NODE) {
453
- rootCue.payload = payload;
452
+ rootCue.payload = VttTextParser.htmlUnescape_(payload);
454
453
  return;
455
454
  }
456
455
  }
@@ -461,7 +460,7 @@ shaka.text.VttTextParser = class {
461
460
  rootCue.nestedCues = cues;
462
461
  } else {
463
462
  shaka.log.warning('The cue\'s markup could not be parsed: ', payload);
464
- rootCue.payload = payload;
463
+ rootCue.payload = VttTextParser.htmlUnescape_(payload);
465
464
  }
466
465
  }
467
466
 
@@ -755,7 +754,7 @@ shaka.text.VttTextParser = class {
755
754
  }
756
755
  if (text.length > 0) {
757
756
  const textCue = nestedCue.clone();
758
- textCue.payload = text;
757
+ textCue.payload = VttTextParser.htmlUnescape_(text);
759
758
  cues.push(textCue);
760
759
  }
761
760
  isFirst = false;
@@ -185,8 +185,7 @@ shaka.util.ManifestParserUtils.AUDIO_CODEC_REGEXPS_ = [
185
185
  /^mp4a/,
186
186
  /^[ae]c-3$/,
187
187
  /^ac-4$/,
188
- /^dts[cx]$/, // DTS Surround Sound
189
- /^[du]dts$/, // DTS Surround Sound
188
+ /^dts[cex]$/, // DTS Digital Surround (dtsc), DTS Express (dtse), DTS:X (dtsx)
190
189
  ];
191
190
 
192
191
 
@@ -49,7 +49,7 @@ shaka.util.MimeUtils = class {
49
49
 
50
50
  if (Transmuxer.isSupported(fullMimeType, contentType)) {
51
51
  return shaka.media.Transmuxer.convertCodecs(contentType, fullMimeType);
52
- } else if (contentType == ContentType.AUDIO) {
52
+ } else if (mimeType != 'video/mp2t' && contentType == ContentType.AUDIO) {
53
53
  // video/mp2t is the correct mime type for TS audio, so only replace the
54
54
  // word "video" with "audio" for non-TS audio content.
55
55
  return fullMimeType.replace('video', 'audio');
@@ -193,6 +193,17 @@ shaka.util.MimeUtils = class {
193
193
  return value;
194
194
  }
195
195
 
196
+ /**
197
+ * Checks if the given MIME type is HLS MIME type.
198
+ *
199
+ * @param {string} mimeType
200
+ * @return {boolean}
201
+ */
202
+ static isHlsType(mimeType) {
203
+ return mimeType === 'application/x-mpegurl' ||
204
+ mimeType === 'application/vnd.apple.mpegurl';
205
+ }
206
+
196
207
  /**
197
208
  * Get the base and profile of a codec string. Where [0] will be the codec
198
209
  * base and [1] will be the profile.
@@ -671,11 +671,11 @@ shaka.util.PeriodCombiner = class {
671
671
  // Also checks if the segmentIndex is still valid after the async
672
672
  // operations, to make sure we stop if the active stream has changed.
673
673
  if (outputStream.segmentIndex instanceof shaka.media.MetaSegmentIndex) {
674
- for (let i = 0; i < streams.length; i++) {
674
+ for (let i = firstNewPeriodIndex; i < streams.length; i++) {
675
675
  const match = streams[i];
676
- if (match.segmentIndex && i >= firstNewPeriodIndex) {
677
- goog.asserts.assert(match.segmentIndex,
678
- 'stream should have a segmentIndex.');
676
+ goog.asserts.assert(match.segmentIndex,
677
+ 'stream should have a segmentIndex.');
678
+ if (match.segmentIndex) {
679
679
  outputStream.segmentIndex.appendSegmentIndex(match.segmentIndex);
680
680
  }
681
681
  }
@@ -728,7 +728,7 @@ shaka.util.PeriodCombiner = class {
728
728
  // in advance. concat() will add them to the output's MetaSegmentIndex.
729
729
  }
730
730
 
731
- if (!outputStream.matchedStreams) {
731
+ if (!outputStream.matchedStreams || !outputStream.matchedStreams.length) {
732
732
  // This is not a stream we can build output from, but it may become part
733
733
  // of another output based on another period's stream.
734
734
  return null;
@@ -712,26 +712,38 @@ shaka.util.StreamUtils = class {
712
712
  }
713
713
 
714
714
  if (audio) {
715
- if (!keySystemConfig.audio) {
715
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
716
+ if (info.audioRobustness != '') {
717
+ if (!keySystemConfig.audio) {
718
+ // KeySystemTrackConfiguration
719
+ keySystemConfig.audio = {
720
+ robustness: info.audioRobustness,
721
+ };
722
+ } else {
723
+ keySystemConfig.audio.robustness =
724
+ keySystemConfig.audio.robustness || info.audioRobustness;
725
+ }
726
+ } else if (!keySystemConfig.audio) {
716
727
  // KeySystemTrackConfiguration
717
- keySystemConfig.audio = {
718
- robustness: info.audioRobustness,
719
- };
720
- } else {
721
- keySystemConfig.audio.robustness =
722
- keySystemConfig.audio.robustness || info.audioRobustness;
728
+ keySystemConfig.audio = {};
723
729
  }
724
730
  }
725
731
 
726
732
  if (video) {
727
- if (!keySystemConfig.video) {
733
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
734
+ if (info.videoRobustness != '') {
735
+ if (!keySystemConfig.video) {
736
+ // KeySystemTrackConfiguration
737
+ keySystemConfig.video = {
738
+ robustness: info.videoRobustness,
739
+ };
740
+ } else {
741
+ keySystemConfig.video.robustness =
742
+ keySystemConfig.video.robustness || info.videoRobustness;
743
+ }
744
+ } else if (!keySystemConfig.video) {
728
745
  // KeySystemTrackConfiguration
729
- keySystemConfig.video = {
730
- robustness: info.videoRobustness,
731
- };
732
- } else {
733
- keySystemConfig.video.robustness =
734
- keySystemConfig.video.robustness || info.videoRobustness;
746
+ keySystemConfig.video = {};
735
747
  }
736
748
  }
737
749
  }
@@ -818,7 +830,7 @@ shaka.util.StreamUtils = class {
818
830
  const video = variant.video;
819
831
  if (audio && currentVariant && currentVariant.audio) {
820
832
  if (!StreamUtils.areStreamsCompatible_(audio, currentVariant.audio)) {
821
- shaka.log.debug('Droping variant - not compatible with active audio',
833
+ shaka.log.debug('Dropping variant - not compatible with active audio',
822
834
  'active audio',
823
835
  StreamUtils.getStreamSummaryString_(currentVariant.audio),
824
836
  'variant.audio',
@@ -829,7 +841,7 @@ shaka.util.StreamUtils = class {
829
841
 
830
842
  if (video && currentVariant && currentVariant.video) {
831
843
  if (!StreamUtils.areStreamsCompatible_(video, currentVariant.video)) {
832
- shaka.log.debug('Droping variant - not compatible with active video',
844
+ shaka.log.debug('Dropping variant - not compatible with active video',
833
845
  'active video',
834
846
  StreamUtils.getStreamSummaryString_(currentVariant.video),
835
847
  'variant.video',
@@ -2,10 +2,9 @@
2
2
 
3
3
  We are currently maintaining the following branches of Shaka Player:
4
4
 
5
- - v4.3 (latest)
5
+ - v4.3 (latest, also in use by the Cast Application Framework)
6
6
  - v4.2 (previous)
7
- - v3.3 (LTS until April 30, 2023)
8
- - v3.2 (in use by the Cast Application Framework)
7
+ - No active LTS branches at this time
9
8
 
10
9
  Other branches are no longer receiving bug fixes, and we recommend you upgrade
11
10
  to a maintained branch. For details on upgrading, please see our
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shaka-player",
3
3
  "description": "DASH/EME video player library",
4
- "version": "4.3.4",
4
+ "version": "4.3.6",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -194,7 +194,8 @@ describe('DashParser Live', () => {
194
194
  template, {updateTime: updateTime, contents: basicLines.join('\n')});
195
195
 
196
196
  fakeNetEngine.setResponseText('dummy://foo', text);
197
- Date.now = () => 0;
197
+ const baseTime = new Date(2015, 11, 30);
198
+ Date.now = () => baseTime.getTime();
198
199
  const manifest = await parser.start('dummy://foo', playerInterface);
199
200
 
200
201
  expect(manifest).toBeTruthy();
@@ -211,7 +212,7 @@ describe('DashParser Live', () => {
211
212
  // seconds long in all of these cases. So 11 seconds after the
212
213
  // manifest was parsed, the first segment should have fallen out of
213
214
  // the availability window.
214
- Date.now = () => 11 * 1000;
215
+ Date.now = () => baseTime.getTime() + (11 * 1000);
215
216
  await updateManifest();
216
217
  // The first reference should have been evicted.
217
218
  expect(stream.segmentIndex.find(0)).toBe(firstPosition + 1);
@@ -987,6 +987,118 @@ describe('HlsParser', () => {
987
987
  await testHlsParser(master, media, manifest);
988
988
  });
989
989
 
990
+ it('parses discontinuity tags', async () => {
991
+ const master = [
992
+ '#EXTM3U\n',
993
+ '#EXT-X-STREAM-INF:BANDWIDTH=2000000,CODECS="avc1"\n',
994
+ 'video\n',
995
+ ].join('');
996
+
997
+ const media = [
998
+ '#EXTM3U\n',
999
+ '#EXT-X-VERSION:3\n',
1000
+ '#EXT-X-TARGETDURATION:5\n',
1001
+ '#EXT-X-MEDIA-SEQUENCE:0\n',
1002
+ '#EXTINF:3,\n',
1003
+ 'clip0-video-0.ts\n',
1004
+ '#EXTINF:1,\n',
1005
+ 'clip0-video-1.ts\n',
1006
+ '#EXT-X-DISCONTINUITY\n',
1007
+ '#EXTINF:2,\n',
1008
+ 'clip1-video-1.ts\n',
1009
+ '#EXTINF:3,\n',
1010
+ 'clip1-video-2.ts\n',
1011
+ '#EXT-X-DISCONTINUITY\n',
1012
+ '#EXTINF:1,\n',
1013
+ 'media-clip2-video-0.ts\n',
1014
+ '#EXTINF:1,\n',
1015
+ 'media-clip2-video-1.ts\n',
1016
+ '#EXT-X-DISCONTINUITY\n',
1017
+ '#EXTINF:4,\n',
1018
+ 'media-clip3-video-1.ts\n',
1019
+ '#EXT-X-ENDLIST\n',
1020
+ ].join('');
1021
+
1022
+ fakeNetEngine
1023
+ .setResponseText('test:/master', master)
1024
+ .setResponseText('test:/video', media);
1025
+
1026
+ const manifest = await parser.start('test:/master', playerInterface);
1027
+ await manifest.variants[0].video.createSegmentIndex();
1028
+
1029
+ const segmentIndex = manifest.variants[0].video.segmentIndex;
1030
+ const references = [];
1031
+
1032
+ for (let i = 0; i < 7; i++) {
1033
+ references.push(segmentIndex.get(i));
1034
+ }
1035
+
1036
+ expect(references[0].discontinuitySequence).toBe(0);
1037
+ expect(references[1].discontinuitySequence).toBe(0);
1038
+ expect(references[2].discontinuitySequence).toBe(1);
1039
+ expect(references[3].discontinuitySequence).toBe(1);
1040
+ expect(references[4].discontinuitySequence).toBe(2);
1041
+ expect(references[5].discontinuitySequence).toBe(2);
1042
+ expect(references[6].discontinuitySequence).toBe(3);
1043
+ });
1044
+
1045
+ it('sets reference timetampOffset based on discontinuity start time',
1046
+ async () => {
1047
+ const master = [
1048
+ '#EXTM3U\n',
1049
+ '#EXT-X-STREAM-INF:BANDWIDTH=2000000,CODECS="avc1"\n',
1050
+ 'video\n',
1051
+ ].join('');
1052
+
1053
+ const media = [
1054
+ '#EXTM3U\n',
1055
+ '#EXT-X-VERSION:3\n',
1056
+ '#EXT-X-TARGETDURATION:5\n',
1057
+ '#EXT-X-MEDIA-SEQUENCE:0\n',
1058
+ '#EXTINF:3,\n',
1059
+ 'clip0-video-0.ts\n',
1060
+ '#EXTINF:1,\n',
1061
+ 'clip0-video-1.ts\n',
1062
+ '#EXT-X-DISCONTINUITY\n',
1063
+ '#EXTINF:2,\n',
1064
+ 'clip1-video-1.ts\n',
1065
+ '#EXTINF:3,\n',
1066
+ 'clip1-video-2.ts\n',
1067
+ '#EXT-X-DISCONTINUITY\n',
1068
+ '#EXTINF:1,\n',
1069
+ 'media-clip2-video-0.ts\n',
1070
+ '#EXTINF:1,\n',
1071
+ 'media-clip2-video-1.ts\n',
1072
+ '#EXT-X-DISCONTINUITY\n',
1073
+ '#EXTINF:4,\n',
1074
+ 'media-clip3-video-1.ts\n',
1075
+ '#EXT-X-ENDLIST\n',
1076
+ ].join('');
1077
+
1078
+ fakeNetEngine
1079
+ .setResponseText('test:/master', master)
1080
+ .setResponseText('test:/video', media);
1081
+
1082
+ const manifest = await parser.start('test:/master', playerInterface);
1083
+ await manifest.variants[0].video.createSegmentIndex();
1084
+
1085
+ const segmentIndex = manifest.variants[0].video.segmentIndex;
1086
+ const references = [];
1087
+
1088
+ for (let i = 0; i < 7; i++) {
1089
+ references.push(segmentIndex.get(i));
1090
+ }
1091
+
1092
+ expect(references[0].timestampOffset).toBe(0);
1093
+ expect(references[1].timestampOffset).toBe(0);
1094
+ expect(references[2].timestampOffset).toBe(4);
1095
+ expect(references[3].timestampOffset).toBe(4);
1096
+ expect(references[4].timestampOffset).toBe(9);
1097
+ expect(references[5].timestampOffset).toBe(9);
1098
+ expect(references[6].timestampOffset).toBe(11);
1099
+ },
1100
+ );
1101
+
990
1102
  it('parses characteristics from audio tags', async () => {
991
1103
  const master = [
992
1104
  '#EXTM3U\n',
@@ -2132,6 +2244,50 @@ describe('HlsParser', () => {
2132
2244
  expect(actual).toEqual(manifest);
2133
2245
  });
2134
2246
 
2247
+ it('parses manifest with MP4+WEBVTT streams', async () => {
2248
+ const master = [
2249
+ '#EXTM3U\n',
2250
+ '#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="eng",',
2251
+ 'CODECS="wvtt",URI="text"\n',
2252
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
2253
+ 'RESOLUTION=960x540,FRAME-RATE=60,SUBTITLES="sub1"\n',
2254
+ 'video\n',
2255
+ ].join('');
2256
+
2257
+ const media = [
2258
+ '#EXTM3U\n',
2259
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
2260
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
2261
+ '#EXTINF:5,\n',
2262
+ '#EXT-X-BYTERANGE:121090@616\n',
2263
+ 'main.mp4',
2264
+ ].join('');
2265
+
2266
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2267
+ manifest.anyTimeline();
2268
+ manifest.addPartialVariant((variant) => {
2269
+ variant.addPartialStream(ContentType.VIDEO);
2270
+ });
2271
+ manifest.addPartialTextStream((stream) => {
2272
+ stream.language = 'en';
2273
+ stream.mime('application/mp4', 'wvtt');
2274
+ });
2275
+ manifest.sequenceMode = true;
2276
+ });
2277
+
2278
+ fakeNetEngine
2279
+ .setResponseText('test:/master', master)
2280
+ .setResponseText('test:/audio', media)
2281
+ .setResponseText('test:/video', media)
2282
+ .setResponseText('test:/text', media)
2283
+ .setResponseValue('test:/init.mp4', initSegmentData)
2284
+ .setResponseValue('test:/main.mp4', segmentData);
2285
+
2286
+ const actual = await parser.start('test:/master', playerInterface);
2287
+ await loadAllStreamsFor(actual);
2288
+ expect(actual).toEqual(manifest);
2289
+ });
2290
+
2135
2291
  it('detects VTT streams by codec', async () => {
2136
2292
  const master = [
2137
2293
  '#EXTM3U\n',
@@ -0,0 +1,43 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ describe('ContentWorkarounds', () => {
8
+ const encryptionBoxes = {
9
+ 'encv': ['hev1', 'hvc1', 'avc1', 'avc3'],
10
+ 'enca': ['ac-3', 'ec-3', 'mp4a'],
11
+ };
12
+ for (const encryptionBox of Object.keys(encryptionBoxes)) {
13
+ for (const box of encryptionBoxes[encryptionBox]) {
14
+ it(`adds ${encryptionBox} box for ${box}`, () => {
15
+ const boxType = [];
16
+ for (const char of box) {
17
+ boxType.push(char.charCodeAt(0));
18
+ }
19
+ const unencrypted = new Uint8Array([
20
+ 0x00, 0x00, 0x00, 0x20, // size
21
+ 0x73, 0x74, 0x73, 0x64, // stsd
22
+ 0x01, // version
23
+ 0x12, 0x34, 0x56, // flags
24
+ 0x00, 0x00, 0x00, 0x01, // count
25
+ 0x00, 0x00, 0x00, 0x10, // size
26
+ ...boxType, // box type
27
+ 0x01, // version
28
+ 0x12, 0x34, 0x56, // flags
29
+ 0x00, 0x11, 0x22, 0x33, // payload
30
+ ]);
31
+
32
+ const faked =
33
+ shaka.media.ContentWorkarounds.fakeEncryption(unencrypted);
34
+ const spy = jasmine.createSpy('boxCallback');
35
+ new shaka.util.Mp4Parser()
36
+ .fullBox('stsd', shaka.util.Mp4Parser.sampleDescription)
37
+ .box(encryptionBox, /** @type {!Function} */ (spy))
38
+ .parse(faked);
39
+ expect(spy).toHaveBeenCalled();
40
+ });
41
+ }
42
+ }
43
+ });
@@ -74,19 +74,6 @@ describe('DrmEngine', () => {
74
74
  onEventSpy = jasmine.createSpy('onEvent');
75
75
 
76
76
  networkingEngine = new shaka.net.NetworkingEngine();
77
- networkingEngine.registerRequestFilter((type, request) => {
78
- if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
79
- return;
80
- }
81
-
82
- request.headers['X-AxDRM-Message'] = [
83
- 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lk',
84
- 'IjoiNjllNTQwODgtZTllMC00NTMwLThjMWEtMWViNmRjZDBkMTRlIiwibWVzc2FnZSI6e',
85
- 'yJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiNmU1YTFkMj',
86
- 'YtMjc1Ny00N2Q3LTgwNDYtZWFhNWQxZDM0YjVhIn1dfX0.yF7PflOPv9qHnu3ZWJNZ12j',
87
- 'gkqTabmwXbDWk_47tLNE',
88
- ].join('');
89
- });
90
77
 
91
78
  const playerInterface = {
92
79
  netEngine: networkingEngine,
@@ -99,22 +86,22 @@ describe('DrmEngine', () => {
99
86
  drmEngine = new shaka.media.DrmEngine(playerInterface);
100
87
  const config = shaka.util.PlayerConfiguration.createDefault().drm;
101
88
  config.servers['com.widevine.alpha'] =
102
- 'https://drm-widevine-licensing.axtest.net/AcquireLicense';
89
+ 'https://cwip-shaka-proxy.appspot.com/specific_key?blodJidXR9eARuql0dNLWg=GX8m9XLIZNIzizrl0RTqnA';
103
90
  config.servers['com.microsoft.playready'] =
104
- 'https://drm-playready-licensing.axtest.net/AcquireLicense';
91
+ 'https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(kid:6e5a1d26-2757-47d7-8046-eaa5d1d34b5a,contentkey:GX8m9XLIZNIzizrl0RTqnA==,sl:150)';
105
92
  drmEngine.configure(config);
106
93
 
107
94
  manifest = shaka.test.ManifestGenerator.generate((manifest) => {
108
95
  manifest.addVariant(0, (variant) => {
109
96
  variant.addVideo(1, (stream) => {
110
97
  stream.encrypted = true;
111
- stream.addDrmInfo('com.widevine.alpha');
112
98
  stream.addDrmInfo('com.microsoft.playready');
99
+ stream.addDrmInfo('com.widevine.alpha');
113
100
  });
114
101
  variant.addAudio(2, (stream) => {
115
102
  stream.encrypted = true;
116
- stream.addDrmInfo('com.widevine.alpha');
117
103
  stream.addDrmInfo('com.microsoft.playready');
104
+ stream.addDrmInfo('com.widevine.alpha');
118
105
  });
119
106
  });
120
107
  });
@@ -3412,7 +3412,12 @@ describe('StreamingEngine', () => {
3412
3412
  netEngine.request.and.callFake((requestType, request) => {
3413
3413
  const buffer = new ArrayBuffer(0);
3414
3414
  /** @type {shaka.extern.Response} */
3415
- const response = {uri: request.uris[0], data: buffer, headers: {}};
3415
+ const response = {
3416
+ uri: request.uris[0],
3417
+ originalUri: request.uris[0],
3418
+ data: buffer,
3419
+ headers: {},
3420
+ };
3416
3421
  return shaka.util.AbortableOperation.completed(response);
3417
3422
  });
3418
3423
 
@@ -1226,6 +1226,11 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ () => {
1226
1226
 
1227
1227
  /** @return {shaka.extern.Response} */
1228
1228
  function createResponse() {
1229
- return {uri: '', data: new ArrayBuffer(5), headers: {}};
1229
+ return {
1230
+ uri: '',
1231
+ originalUri: '',
1232
+ data: new ArrayBuffer(5),
1233
+ headers: {},
1234
+ };
1230
1235
  }
1231
1236
  }); // describe('NetworkingEngine')