shaka-player 4.2.8 → 4.2.10

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 (104) 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 +50 -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 +1 -1
  16. package/dist/demo.compiled.debug.js +170 -290
  17. package/dist/demo.compiled.debug.map +4 -4
  18. package/dist/demo.compiled.js +170 -290
  19. package/dist/demo.compiled.map +4 -4
  20. package/dist/deps.js +2 -2
  21. package/dist/locales.js +30 -30
  22. package/dist/receiver.compiled.debug.js +52 -81
  23. package/dist/receiver.compiled.debug.map +4 -4
  24. package/dist/receiver.compiled.js +52 -81
  25. package/dist/receiver.compiled.map +4 -4
  26. package/dist/shaka-player.compiled.d.ts +19 -3
  27. package/dist/shaka-player.compiled.debug.d.ts +19 -3
  28. package/dist/shaka-player.compiled.debug.externs.js +17 -12
  29. package/dist/shaka-player.compiled.debug.js +181 -176
  30. package/dist/shaka-player.compiled.debug.map +4 -4
  31. package/dist/shaka-player.compiled.externs.js +17 -12
  32. package/dist/shaka-player.compiled.js +825 -823
  33. package/dist/shaka-player.compiled.map +3 -3
  34. package/dist/shaka-player.ui.d.ts +19 -3
  35. package/dist/shaka-player.ui.debug.d.ts +19 -3
  36. package/dist/shaka-player.ui.debug.externs.js +5 -0
  37. package/dist/shaka-player.ui.debug.js +191 -186
  38. package/dist/shaka-player.ui.debug.map +3 -3
  39. package/dist/shaka-player.ui.externs.js +5 -0
  40. package/dist/shaka-player.ui.js +955 -951
  41. package/dist/shaka-player.ui.map +3 -3
  42. package/docs/tutorials/a11y.md +0 -4
  43. package/docs/tutorials/ad_monetization.md +0 -4
  44. package/docs/tutorials/basic-usage.md +0 -5
  45. package/docs/tutorials/config.md +0 -5
  46. package/docs/tutorials/debugging.md +0 -5
  47. package/docs/tutorials/drm-config.md +0 -5
  48. package/docs/tutorials/errors.md +94 -0
  49. package/docs/tutorials/fairplay.md +4 -4
  50. package/docs/tutorials/index.json +2 -0
  51. package/docs/tutorials/license-server-auth.md +0 -5
  52. package/docs/tutorials/license-wrapping.md +0 -5
  53. package/docs/tutorials/network-and-buffering-config.md +0 -5
  54. package/docs/tutorials/ui-customization.md +0 -5
  55. package/docs/tutorials/ui.md +0 -7
  56. package/docs/tutorials/welcome.md +0 -5
  57. package/docs/tutorials/widevine-service-certs.md +45 -0
  58. package/externs/ima.js +9 -0
  59. package/externs/network_information.js +7 -2
  60. package/externs/shaka/abr_manager.js +6 -0
  61. package/externs/shaka/net.js +1 -0
  62. package/externs/shaka/player.js +13 -7
  63. package/lib/abr/simple_abr_manager.js +27 -3
  64. package/lib/ads/client_side_ad_manager.js +11 -5
  65. package/lib/dash/dash_parser.js +49 -48
  66. package/lib/debug/log.js +9 -13
  67. package/lib/hls/hls_parser.js +2 -0
  68. package/lib/media/drm_engine.js +4 -2
  69. package/lib/media/media_source_engine.js +11 -4
  70. package/lib/media/segment_index.js +2 -0
  71. package/lib/media/streaming_engine.js +8 -3
  72. package/lib/media/transmuxer.js +13 -7
  73. package/lib/media/video_wrapper.js +3 -3
  74. package/lib/net/http_fetch_plugin.js +79 -57
  75. package/lib/net/networking_engine.js +1 -0
  76. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  77. package/lib/player.js +24 -3
  78. package/lib/polyfill/media_capabilities.js +15 -8
  79. package/lib/polyfill/mediasource.js +24 -2
  80. package/lib/text/mp4_vtt_parser.js +4 -0
  81. package/lib/text/text_engine.js +1 -0
  82. package/lib/text/ui_text_displayer.js +1 -0
  83. package/lib/text/vtt_text_parser.js +4 -5
  84. package/lib/util/manifest_parser_utils.js +1 -2
  85. package/lib/util/mime_utils.js +12 -1
  86. package/lib/util/periods.js +5 -5
  87. package/lib/util/stream_utils.js +28 -16
  88. package/maintained-branches.md +3 -4
  89. package/package.json +1 -1
  90. package/test/media/content_workarounds_unit.js +43 -0
  91. package/test/media/drm_engine_integration.js +4 -17
  92. package/test/media/streaming_engine_unit.js +6 -1
  93. package/test/net/networking_engine_unit.js +6 -1
  94. package/test/player_integration.js +39 -0
  95. package/test/player_unit.js +57 -0
  96. package/test/polyfill/media_capabilities_unit.js +20 -23
  97. package/test/test/assets/text-clip-alt.vtt +63 -0
  98. package/test/test/util/fake_drm_engine.js +3 -0
  99. package/test/test/util/simple_fakes.js +6 -0
  100. package/test/test/util/test_scheme.js +9 -14
  101. package/test/text/mp4_vtt_parser_unit.js +8 -0
  102. package/test/text/vtt_text_parser_unit.js +26 -2
  103. package/test/text/web_vtt_layout_integration.js +0 -3
  104. package/test/util/mime_utils_unit.js +10 -0
@@ -710,26 +710,38 @@ shaka.util.StreamUtils = class {
710
710
  }
711
711
 
712
712
  if (audio) {
713
- if (!keySystemConfig.audio) {
713
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
714
+ if (info.audioRobustness != '') {
715
+ if (!keySystemConfig.audio) {
716
+ // KeySystemTrackConfiguration
717
+ keySystemConfig.audio = {
718
+ robustness: info.audioRobustness,
719
+ };
720
+ } else {
721
+ keySystemConfig.audio.robustness =
722
+ keySystemConfig.audio.robustness || info.audioRobustness;
723
+ }
724
+ } else if (!keySystemConfig.audio) {
714
725
  // KeySystemTrackConfiguration
715
- keySystemConfig.audio = {
716
- robustness: info.audioRobustness,
717
- };
718
- } else {
719
- keySystemConfig.audio.robustness =
720
- keySystemConfig.audio.robustness || info.audioRobustness;
726
+ keySystemConfig.audio = {};
721
727
  }
722
728
  }
723
729
 
724
730
  if (video) {
725
- if (!keySystemConfig.video) {
731
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
732
+ if (info.videoRobustness != '') {
733
+ if (!keySystemConfig.video) {
734
+ // KeySystemTrackConfiguration
735
+ keySystemConfig.video = {
736
+ robustness: info.videoRobustness,
737
+ };
738
+ } else {
739
+ keySystemConfig.video.robustness =
740
+ keySystemConfig.video.robustness || info.videoRobustness;
741
+ }
742
+ } else if (!keySystemConfig.video) {
726
743
  // KeySystemTrackConfiguration
727
- keySystemConfig.video = {
728
- robustness: info.videoRobustness,
729
- };
730
- } else {
731
- keySystemConfig.video.robustness =
732
- keySystemConfig.video.robustness || info.videoRobustness;
744
+ keySystemConfig.video = {};
733
745
  }
734
746
  }
735
747
  }
@@ -816,7 +828,7 @@ shaka.util.StreamUtils = class {
816
828
  const video = variant.video;
817
829
  if (audio && currentVariant && currentVariant.audio) {
818
830
  if (!StreamUtils.areStreamsCompatible_(audio, currentVariant.audio)) {
819
- shaka.log.debug('Droping variant - not compatible with active audio',
831
+ shaka.log.debug('Dropping variant - not compatible with active audio',
820
832
  'active audio',
821
833
  StreamUtils.getStreamSummaryString_(currentVariant.audio),
822
834
  'variant.audio',
@@ -827,7 +839,7 @@ shaka.util.StreamUtils = class {
827
839
 
828
840
  if (video && currentVariant && currentVariant.video) {
829
841
  if (!StreamUtils.areStreamsCompatible_(video, currentVariant.video)) {
830
- shaka.log.debug('Droping variant - not compatible with active video',
842
+ shaka.log.debug('Dropping variant - not compatible with active video',
831
843
  'active video',
832
844
  StreamUtils.getStreamSummaryString_(currentVariant.video),
833
845
  'variant.video',
@@ -2,10 +2,9 @@
2
2
 
3
3
  We are currently maintaining the following branches of Shaka Player:
4
4
 
5
- - v4.1 (latest)
6
- - v4.0 (previous)
7
- - v3.3 (LTS until April 30, 2023)
8
- - v3.2 (in use by the Cast Application Framework)
5
+ - v4.3 (latest, also in use by the Cast Application Framework)
6
+ - v4.2 (previous)
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.2.8",
4
+ "version": "4.2.10",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -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
  });
@@ -3297,7 +3297,12 @@ describe('StreamingEngine', () => {
3297
3297
  netEngine.request.and.callFake((requestType, request) => {
3298
3298
  const buffer = new ArrayBuffer(0);
3299
3299
  /** @type {shaka.extern.Response} */
3300
- const response = {uri: request.uris[0], data: buffer, headers: {}};
3300
+ const response = {
3301
+ uri: request.uris[0],
3302
+ originalUri: request.uris[0],
3303
+ data: buffer,
3304
+ headers: {},
3305
+ };
3301
3306
  return shaka.util.AbortableOperation.completed(response);
3302
3307
  });
3303
3308
 
@@ -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')
@@ -401,6 +401,45 @@ describe('Player', () => {
401
401
  player.setTextTrackVisibility(true);
402
402
  expect(getTracksActive()).toEqual([false, true]);
403
403
  });
404
+
405
+ // https://github.com/shaka-project/shaka-player/issues/4821
406
+ it('loads a single text stream', async () => {
407
+ player.configure({preferredTextLanguage: 'en'});
408
+ await player.load('test:sintel_no_text_compiled');
409
+
410
+ // Add preferred language text track.
411
+ const locationUri = new goog.Uri(location.href);
412
+ const partialUri = new goog.Uri('/base/test/test/assets/text-clip.vtt');
413
+ const absoluteUri = locationUri.resolve(partialUri);
414
+ await player.addTextTrackAsync(
415
+ absoluteUri.toString(), 'en', 'subtitles', 'text/vtt');
416
+
417
+ // Add alternate language text track.
418
+ // Two text tracks with same timings but different text
419
+ // are necessary for test.
420
+ const partialUri2 =
421
+ new goog.Uri('/base/test/test/assets/text-clip-alt.vtt');
422
+ const absoluteUri2 = locationUri.resolve(partialUri2);
423
+ await player.addTextTrackAsync(
424
+ absoluteUri2.toString(), 'fr', 'subtitles', 'text/vtt');
425
+
426
+ const textTracks = player.getTextTracks();
427
+ expect(textTracks.length).toBe(2);
428
+ expect(textTracks[0].language).toBe('en');
429
+ expect(textTracks[1].language).toBe('fr');
430
+
431
+ // Enable text visibilty and immediately change language.
432
+ // Only one set of cues should be active.
433
+ // Cues should be of the selected language track.
434
+ player.setTextTrackVisibility(true);
435
+ player.selectTextLanguage('fr');
436
+ video.currentTime = 5;
437
+ video.play();
438
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
439
+
440
+ expect(video.textTracks[0].activeCues.length).toBe(1);
441
+ expect(player.getTextTracks()[1].active).toBe(true);
442
+ });
404
443
  }); // describe('setTextTrackVisibility')
405
444
 
406
445
  describe('plays', () => {
@@ -205,6 +205,7 @@ describe('Player', () => {
205
205
  await player.destroy();
206
206
 
207
207
  expect(abrManager.stop).toHaveBeenCalled();
208
+ expect(abrManager.release).toHaveBeenCalled();
208
209
  expect(networkingEngine.destroy).toHaveBeenCalled();
209
210
  expect(drmEngine.destroy).toHaveBeenCalled();
210
211
  expect(playhead.release).toHaveBeenCalled();
@@ -243,6 +244,7 @@ describe('Player', () => {
243
244
  parser.start.and.returnValue(p);
244
245
  parser.stop.and.callFake(() => {
245
246
  expect(abrManager.stop).not.toHaveBeenCalled();
247
+ expect(abrManager.release).not.toHaveBeenCalled();
246
248
  expect(networkingEngine.destroy).not.toHaveBeenCalled();
247
249
  });
248
250
  shaka.media.ManifestParser.registerParserByMime(
@@ -252,6 +254,7 @@ describe('Player', () => {
252
254
  await shaka.test.Util.shortDelay();
253
255
  await player.destroy();
254
256
  expect(abrManager.stop).toHaveBeenCalled();
257
+ expect(abrManager.release).toHaveBeenCalled();
255
258
  expect(networkingEngine.destroy).toHaveBeenCalled();
256
259
  expect(parser.stop).toHaveBeenCalled();
257
260
  await expectAsync(load).toBeRejected();
@@ -551,6 +554,60 @@ describe('Player', () => {
551
554
  expect(streamingEngine.unloadTextStream).not.toHaveBeenCalled();
552
555
  });
553
556
  });
557
+
558
+ describe('when config.streaming.preferNativeHls is set to true', () => {
559
+ beforeEach(() => {
560
+ shaka.media.ManifestParser.registerParserByMime(
561
+ 'application/x-mpegurl',
562
+ () => new shaka.test.FakeManifestParser(manifest));
563
+ });
564
+
565
+ afterEach(() => {
566
+ shaka.media.ManifestParser.unregisterParserByMime(
567
+ 'application/x-mpegurl');
568
+ video.canPlayType.calls.reset();
569
+ });
570
+
571
+ it('only applies to HLS streams', async () => {
572
+ video.canPlayType.and.returnValue('maybe');
573
+ spyOn(shaka.util.Platform, 'anyMediaElement').and.returnValue(video);
574
+ spyOn(shaka.util.Platform, 'supportsMediaSource').and.returnValue(true);
575
+ spyOn(shaka.util.Platform, 'isApple').and.returnValue(false);
576
+ // Make sure player.load() resolves for src=
577
+ spyOn(shaka.util.MediaReadyState, 'waitForReadyState').and.callFake(
578
+ (mediaElement, readyState, eventManager, callback) => {
579
+ callback();
580
+ });
581
+
582
+ player.configure({
583
+ streaming: {
584
+ preferNativeHls: true,
585
+ useNativeHlsOnSafari: false,
586
+ },
587
+ });
588
+
589
+ await player.load(fakeManifestUri, undefined, 'application/x-mpegurl');
590
+
591
+ expect(player.getLoadMode()).toBe(shaka.Player.LoadMode.SRC_EQUALS);
592
+ });
593
+
594
+ it('does not apply to non-HLS streams', async () => {
595
+ video.canPlayType.and.returnValue('maybe');
596
+ spyOn(shaka.util.Platform, 'supportsMediaSource').and.returnValue(true);
597
+ spyOn(shaka.util.Platform, 'isApple').and.returnValue(false);
598
+
599
+ player.configure({
600
+ streaming: {
601
+ preferNativeHls: true,
602
+ useNativeHlsOnSafari: false,
603
+ },
604
+ });
605
+
606
+ await player.load(fakeManifestUri, 0, fakeMimeType);
607
+
608
+ expect(player.getLoadMode()).toBe(shaka.Player.LoadMode.MEDIA_SOURCE);
609
+ });
610
+ });
554
611
  }); // describe('load/unload')
555
612
 
556
613
  describe('getConfiguration', () => {
@@ -5,7 +5,6 @@
5
5
  */
6
6
 
7
7
  describe('MediaCapabilities', () => {
8
- const Util = shaka.test.Util;
9
8
  const originalCast = window['cast'];
10
9
  const originalVendor = navigator.vendor;
11
10
  const originalUserAgent = navigator.userAgent;
@@ -68,7 +67,6 @@ describe('MediaCapabilities', () => {
68
67
  width: 512,
69
68
  },
70
69
  };
71
- shaka.polyfill.MediaCapabilities.memoizedMediaKeySystemAccessRequests_ = {};
72
70
 
73
71
  mockCanDisplayType = jasmine.createSpy('canDisplayType');
74
72
  mockCanDisplayType.and.returnValue(false);
@@ -168,30 +166,29 @@ describe('MediaCapabilities', () => {
168
166
  expect(result.keySystemAccess).toEqual(mockResult);
169
167
  });
170
168
 
171
- it('throws when the cast namespace is not available', async () => {
172
- // Temporarily remove window.cast to trigger error. It's restored after
173
- // every test.
174
- delete window['cast'];
169
+ it('falls back to isTypeSupported() when cast namespace is not available',
170
+ async () => {
171
+ // Temporarily remove window.cast to trigger error. It's restored
172
+ // after every test.
173
+ delete window['cast'];
175
174
 
176
- const isChromecastSpy =
177
- spyOn(shaka['util']['Platform'],
178
- 'isChromecast').and.returnValue(true);
179
- const expected = Util.jasmineError(new shaka.util.Error(
180
- shaka.util.Error.Severity.CRITICAL,
181
- shaka.util.Error.Category.CAST,
182
- shaka.util.Error.Code.CAST_API_UNAVAILABLE));
183
- const isTypeSupportedSpy =
184
- spyOn(window['MediaSource'], 'isTypeSupported').and.returnValue(true);
175
+ const isChromecastSpy =
176
+ spyOn(shaka['util']['Platform'],
177
+ 'isChromecast').and.returnValue(true);
178
+ const isTypeSupportedSpy =
179
+ spyOn(window['MediaSource'], 'isTypeSupported')
180
+ .and.returnValue(true);
185
181
 
186
- shaka.polyfill.MediaCapabilities.install();
187
- await expectAsync(
188
- navigator.mediaCapabilities.decodingInfo(mockDecodingConfig))
189
- .toBeRejectedWith(expected);
182
+ shaka.polyfill.MediaCapabilities.install();
183
+ await navigator.mediaCapabilities.decodingInfo(mockDecodingConfig);
190
184
 
191
- expect(isTypeSupportedSpy).not.toHaveBeenCalled();
192
- // 1 (during install()) + 1 (for video config check).
193
- expect(isChromecastSpy).toHaveBeenCalledTimes(2);
194
- });
185
+ expect(mockCanDisplayType).not.toHaveBeenCalled();
186
+ // 1 (during install()) + 1 (for video config check).
187
+ expect(isChromecastSpy).toHaveBeenCalledTimes(2);
188
+ // 1 (fallback in canCastDisplayType()) +
189
+ // 1 (mockDecodingConfig.audio).
190
+ expect(isTypeSupportedSpy).toHaveBeenCalledTimes(2);
191
+ });
195
192
 
196
193
  it('falls back to isTypeSupported() when canDisplayType() missing',
197
194
  async () => {
@@ -0,0 +1,63 @@
1
+ WEBVTT
2
+
3
+ 00:04.000 --> 00:07.300
4
+ Journal de bord du capitaine.
5
+ Date stellaire 41636.9.
6
+
7
+ 00:07.500 --> 00:11.800
8
+ Comme nous le craignions, l'épave
9
+ du cargo Odin de la Fédération,
10
+
11
+ 00:12.100 --> 00:16.400
12
+ percuté par un astéroïde,
13
+ ne révèle aucun signe de vie.
14
+
15
+ 00:16.700 --> 00:19.000
16
+ Mais trois nacelles
17
+ de sauvetage manquaient,
18
+
19
+ 00:19.300 --> 00:21.900
20
+ laissant supposer
21
+ qu'il y aurait des survivants.
22
+
23
+ 00:22.700 --> 00:27.700
24
+ - Mise sur orbite Angel One, paré.
25
+ - Quel genre d'endroit, Data ?
26
+
27
+ 00:28.200 --> 00:31.600
28
+ Planète de Classe-M.
29
+ Faune et flore à base de carbone.
30
+
31
+ 00:31.900 --> 00:34.300
32
+ Population éparse
33
+ et forme de vie intelligente.
34
+
35
+ 00:34.600 --> 00:38.400
36
+ Développement technique équivalent
37
+ au milieu du 20ème siècle terrien.
38
+
39
+ 00:38.800 --> 00:41.000
40
+ C'est presque un retour aux sources.
41
+
42
+ 00:41.300 --> 00:43.600
43
+ Si jamais des survivants
44
+ ont pu aller si loin,
45
+
46
+ 00:43.800 --> 00:49.000
47
+ c'était la planète la plus proche.
48
+ La distance qui nous a pris 2 jours
49
+
50
+ 00:49.500 --> 00:52.400
51
+ aurait pris 5 mois aux nacelles
52
+ de sauvetage du Odin.
53
+
54
+ 00:52.600 --> 00:54.700
55
+ Cinq mois, six jours, onze heures,
56
+ deux min...
57
+
58
+ 00:54.900 --> 00:58.400
59
+ - Merci, Data.
60
+ - ..et 57 secondes.
61
+
62
+ 00:58.600 --> 01:01.300
63
+ Signal audio provenant d'Angel One.
@@ -81,6 +81,9 @@ shaka.test.FakeDrmEngine = class {
81
81
  /** @type {!jasmine.Spy} */
82
82
  this.supportsVariant = jasmine.createSpy('supportsVariant');
83
83
  this.supportsVariant.and.returnValue(true);
84
+
85
+ /** @type {!jasmine.Spy} */
86
+ this.setSrcEquals = jasmine.createSpy('setSrcEquals');
84
87
  }
85
88
 
86
89
  /**
@@ -35,6 +35,9 @@ shaka.test.FakeAbrManager = class {
35
35
  /** @type {!jasmine.Spy} */
36
36
  this.stop = jasmine.createSpy('stop');
37
37
 
38
+ /** @type {!jasmine.Spy} */
39
+ this.release = jasmine.createSpy('release');
40
+
38
41
  /** @type {!jasmine.Spy} */
39
42
  this.enable = jasmine.createSpy('enable');
40
43
 
@@ -225,6 +228,9 @@ shaka.test.FakeVideo = class {
225
228
 
226
229
  /** @type {!jasmine.Spy} */
227
230
  this.dispatchEvent = jasmine.createSpy('dispatchEvent');
231
+
232
+ /** @type {!jasmine.Spy} */
233
+ this.canPlayType = jasmine.createSpy('canPlayType');
228
234
  }
229
235
  };
230
236
 
@@ -447,6 +447,7 @@ const widevineDrmServers = {
447
447
 
448
448
  /** @type {AVMetadataType} */
449
449
  const axinomMultiDrmVideoSegment = {
450
+ // Taken from Axinom's v6 test vector.
450
451
  initSegmentUri: '/base/test/test/assets/multidrm-video-init.mp4',
451
452
  mdhdOffset: 0x1d1,
452
453
  segmentUri: '/base/test/test/assets/multidrm-video-segment.mp4',
@@ -461,6 +462,7 @@ const axinomMultiDrmVideoSegment = {
461
462
 
462
463
  /** @type {AVMetadataType} */
463
464
  const axinomMultiDrmAudioSegment = {
465
+ // Taken from Axinom's v6 test vector.
464
466
  initSegmentUri: '/base/test/test/assets/multidrm-audio-init.mp4',
465
467
  mdhdOffset: 0x192,
466
468
  segmentUri: '/base/test/test/assets/multidrm-audio-segment.mp4',
@@ -475,20 +477,15 @@ const axinomMultiDrmAudioSegment = {
475
477
 
476
478
  /** @type {!Object.<string, string>} */
477
479
  const axinomDrmServers = {
480
+ // NOTE: These are not Axinom's actual servers. These are test servers for
481
+ // Widevine and PlayReady that let us specify the known key IDs and keys for
482
+ // Axinom's v6 test vectors. Axinom's own servers started returning 403
483
+ // errors for these older test vectors, and we were forced to switch to
484
+ // something stable and independent.
478
485
  'com.widevine.alpha':
479
- 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
486
+ 'https://cwip-shaka-proxy.appspot.com/specific_key?blodJidXR9eARuql0dNLWg=GX8m9XLIZNIzizrl0RTqnA',
480
487
  'com.microsoft.playready':
481
- 'https://drm-playready-licensing.axtest.net/AcquireLicense',
482
- };
483
-
484
- /** @type {!Object.<string, string>} */
485
- const axinomDrmHeaders = {
486
- 'X-AxDRM-Message':
487
- 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5' +
488
- 'X2lkIjoiNjllNTQwODgtZTllMC00NTMwLThjMWEtMWViNmRjZDBkMTRlIiwibWVzc' +
489
- '2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIj' +
490
- 'oiNmU1YTFkMjYtMjc1Ny00N2Q3LTgwNDYtZWFhNWQxZDM0YjVhIn1dfX0.yF7PflO' +
491
- 'Pv9qHnu3ZWJNZ12jgkqTabmwXbDWk_47tLNE',
488
+ 'https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(kid:6e5a1d26-2757-47d7-8046-eaa5d1d34b5a,contentkey:GX8m9XLIZNIzizrl0RTqnA==,sl:150)',
492
489
  };
493
490
 
494
491
  /** @type {TextMetadataType} */
@@ -601,7 +598,6 @@ shaka.test.TestScheme.DATA = {
601
598
  audio: axinomMultiDrmAudioSegment,
602
599
  text: vttSegment,
603
600
  licenseServers: axinomDrmServers,
604
- licenseRequestHeaders: axinomDrmHeaders,
605
601
  duration: 30,
606
602
  sequenceMode: false,
607
603
  },
@@ -614,7 +610,6 @@ shaka.test.TestScheme.DATA = {
614
610
  initData: undefined,
615
611
  }),
616
612
  licenseServers: axinomDrmServers,
617
- licenseRequestHeaders: axinomDrmHeaders,
618
613
  duration: 30,
619
614
  sequenceMode: false,
620
615
  },
@@ -171,6 +171,14 @@ describe('Mp4VttParser', () => {
171
171
  verifyHelper(cues, result);
172
172
  });
173
173
 
174
+ it('handles empty media segments', () => {
175
+ const parser = new shaka.text.Mp4VttParser();
176
+ parser.parseInit(vttInitSegment);
177
+ const time = {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0};
178
+ const result = parser.parseMedia(new Uint8Array(0), time);
179
+ verifyHelper([], result);
180
+ });
181
+
174
182
  it('rejects init segment with no vtt', () => {
175
183
  const error = shaka.test.Util.jasmineError(new shaka.util.Error(
176
184
  shaka.util.Error.Severity.CRITICAL,
@@ -852,11 +852,35 @@ describe('VttTextParser', () => {
852
852
  it('support escaped html payload', () => {
853
853
  verifyHelper(
854
854
  [
855
- {startTime: 20.1, endTime: 40.505, payload: '"Test & 1"\u{a0}'},
855
+ {
856
+ startTime: 20.1,
857
+ endTime: 40.505,
858
+ payload: '"Test & 1"\u{a0}',
859
+ },
860
+ {
861
+ startTime: 41,
862
+ endTime: 42,
863
+ payload: '',
864
+ nestedCues: [
865
+ {
866
+ startTime: 41,
867
+ endTime: 42,
868
+ payload: 'Test',
869
+ fontStyle: Cue.fontStyle.ITALIC,
870
+ },
871
+ {
872
+ startTime: 41,
873
+ endTime: 42,
874
+ payload: '&',
875
+ },
876
+ ],
877
+ },
856
878
  ],
857
879
  'WEBVTT\n\n' +
858
880
  '00:00:20.100 --> 00:00:40.505\n' +
859
- '&quot;Test &amp; 1&quot;&nbsp;',
881
+ '&quot;Test &amp; 1&quot;&nbsp;\n\n' +
882
+ '00:00:41.000 --> 00:00:42.000\n' +
883
+ '<i>Test</i>&amp;',
860
884
  {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
861
885
  });
862
886
 
@@ -265,7 +265,6 @@ filterDescribe('WebVTT layout', shaka.test.TextLayoutTests.supported, () => {
265
265
  await helper.checkScreenshot('line-85-position-50-size-63');
266
266
  });
267
267
 
268
- // FIXME: UI version is slightly wrong: gaps between lines when bold
269
268
  it('bold long', async () => {
270
269
  parseAndDisplay([
271
270
  'WEBVTT\n',
@@ -278,7 +277,6 @@ filterDescribe('WebVTT layout', shaka.test.TextLayoutTests.supported, () => {
278
277
  await helper.checkScreenshot('bold-long');
279
278
  });
280
279
 
281
- // FIXME: UI version is slightly wrong: gaps between lines when italic
282
280
  it('italic long', async () => {
283
281
  parseAndDisplay([
284
282
  'WEBVTT\n',
@@ -291,7 +289,6 @@ filterDescribe('WebVTT layout', shaka.test.TextLayoutTests.supported, () => {
291
289
  await helper.checkScreenshot('italic-long');
292
290
  });
293
291
 
294
- // FIXME: UI version is slightly wrong: gaps between lines when italic
295
292
  it('underline long', async () => {
296
293
  parseAndDisplay([
297
294
  'WEBVTT\n',
@@ -51,4 +51,14 @@ describe('MimeUtils', () => {
51
51
  expect(getNormalizedCodec('dvh1.05')).toBe('dovi');
52
52
  expect(getNormalizedCodec('dvhe.05')).toBe('dovi');
53
53
  });
54
+
55
+ it('isHlsType', () => {
56
+ const isHlsType = (mimeType) => shaka.util.MimeUtils.isHlsType(mimeType);
57
+
58
+ expect(isHlsType('application/x-mpegurl')).toBe(true);
59
+ expect(isHlsType('application/vnd.apple.mpegurl')).toBe(true);
60
+ expect(isHlsType('application/dash+xml')).toBe(false);
61
+ expect(isHlsType('application/vnd.ms-sstr+xml')).toBe(false);
62
+ expect(isHlsType('foo')).toBe(false);
63
+ });
54
64
  });