shaka-player 3.2.19 → 3.2.21

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 (80) 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 +40 -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 +150 -148
  17. package/dist/demo.compiled.debug.map +3 -3
  18. package/dist/demo.compiled.js +150 -148
  19. package/dist/demo.compiled.map +3 -3
  20. package/dist/deps.js +1 -1
  21. package/dist/locales.js +30 -30
  22. package/dist/receiver.compiled.debug.js +19 -19
  23. package/dist/receiver.compiled.debug.map +2 -2
  24. package/dist/receiver.compiled.js +19 -19
  25. package/dist/receiver.compiled.map +2 -2
  26. package/dist/shaka-player.compiled.d.ts +13 -2
  27. package/dist/shaka-player.compiled.debug.d.ts +13 -2
  28. package/dist/shaka-player.compiled.debug.js +178 -176
  29. package/dist/shaka-player.compiled.debug.map +3 -3
  30. package/dist/shaka-player.compiled.js +294 -292
  31. package/dist/shaka-player.compiled.map +3 -3
  32. package/dist/shaka-player.ui.d.ts +13 -2
  33. package/dist/shaka-player.ui.debug.d.ts +13 -2
  34. package/dist/shaka-player.ui.debug.js +117 -115
  35. package/dist/shaka-player.ui.debug.map +3 -3
  36. package/dist/shaka-player.ui.js +318 -316
  37. package/dist/shaka-player.ui.map +3 -3
  38. package/docs/tutorials/errors.md +94 -0
  39. package/docs/tutorials/fairplay.md +2 -2
  40. package/docs/tutorials/index.json +2 -0
  41. package/docs/tutorials/widevine-service-certs.md +45 -0
  42. package/externs/ima.js +9 -0
  43. package/externs/shaka/net.js +1 -0
  44. package/externs/shaka/player.js +13 -7
  45. package/lib/ads/client_side_ad_manager.js +8 -5
  46. package/lib/hls/hls_parser.js +2 -0
  47. package/lib/media/media_source_engine.js +9 -4
  48. package/lib/media/streaming_engine.js +8 -3
  49. package/lib/media/transmuxer.js +13 -7
  50. package/lib/media/video_wrapper.js +3 -3
  51. package/lib/net/http_fetch_plugin.js +10 -0
  52. package/lib/net/networking_engine.js +1 -0
  53. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  54. package/lib/player.js +19 -2
  55. package/lib/polyfill/media_capabilities.js +15 -8
  56. package/lib/polyfill/mediasource.js +7 -2
  57. package/lib/text/mp4_vtt_parser.js +4 -0
  58. package/lib/text/text_engine.js +1 -0
  59. package/lib/text/ui_text_displayer.js +1 -0
  60. package/lib/text/vtt_text_parser.js +4 -5
  61. package/lib/util/manifest_parser_utils.js +1 -2
  62. package/lib/util/mime_utils.js +12 -1
  63. package/lib/util/stream_utils.js +28 -16
  64. package/maintained-branches.md +3 -4
  65. package/package.json +1 -1
  66. package/test/media/content_workarounds_unit.js +43 -0
  67. package/test/media/drm_engine_integration.js +4 -17
  68. package/test/media/streaming_engine_unit.js +6 -1
  69. package/test/net/networking_engine_unit.js +6 -1
  70. package/test/player_integration.js +39 -0
  71. package/test/player_unit.js +54 -0
  72. package/test/polyfill/media_capabilities_unit.js +20 -23
  73. package/test/test/assets/text-clip-alt.vtt +63 -0
  74. package/test/test/util/fake_drm_engine.js +3 -0
  75. package/test/test/util/simple_fakes.js +3 -0
  76. package/test/test/util/test_scheme.js +9 -14
  77. package/test/text/mp4_vtt_parser_unit.js +8 -0
  78. package/test/text/vtt_text_parser_unit.js +26 -2
  79. package/test/text/web_vtt_layout_integration.js +0 -3
  80. package/test/util/mime_utils_unit.js +10 -0
@@ -369,8 +369,7 @@ shaka.text.VttTextParser = class {
369
369
  end += timeOffset;
370
370
 
371
371
  // Get the payload.
372
- const payload = VttTextParser.htmlUnescape_(
373
- text.slice(1).join('\n').trim());
372
+ const payload = text.slice(1).join('\n').trim();
374
373
 
375
374
  let cue = null;
376
375
  if (styles.has('global')) {
@@ -427,7 +426,7 @@ shaka.text.VttTextParser = class {
427
426
  const childNode = childNodes[0];
428
427
  if (childNode.nodeType == Node.TEXT_NODE ||
429
428
  childNode.nodeType == Node.CDATA_SECTION_NODE) {
430
- rootCue.payload = payload;
429
+ rootCue.payload = VttTextParser.htmlUnescape_(payload);
431
430
  return;
432
431
  }
433
432
  }
@@ -438,7 +437,7 @@ shaka.text.VttTextParser = class {
438
437
  rootCue.nestedCues = cues;
439
438
  } else {
440
439
  shaka.log.warning('The cue\'s markup could not be parsed: ', payload);
441
- rootCue.payload = payload;
440
+ rootCue.payload = VttTextParser.htmlUnescape_(payload);
442
441
  }
443
442
  }
444
443
 
@@ -682,7 +681,7 @@ shaka.text.VttTextParser = class {
682
681
  }
683
682
  if (text.length > 0) {
684
683
  const textCue = nestedCue.clone();
685
- textCue.payload = text;
684
+ textCue.payload = VttTextParser.htmlUnescape_(text);
686
685
  cues.push(textCue);
687
686
  }
688
687
  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
 
@@ -50,7 +50,7 @@ shaka.util.MimeUtils = class {
50
50
  return shaka.media.Transmuxer.convertTsCodecs(
51
51
  contentType, fullMimeType);
52
52
  }
53
- } else if (contentType == ContentType.AUDIO) {
53
+ } else if (mimeType != 'video/mp2t' && contentType == ContentType.AUDIO) {
54
54
  // video/mp2t is the correct mime type for TS audio, so only replace the
55
55
  // word "video" with "audio" for non-TS audio content.
56
56
  return fullMimeType.replace('video', 'audio');
@@ -194,6 +194,17 @@ shaka.util.MimeUtils = class {
194
194
  return value;
195
195
  }
196
196
 
197
+ /**
198
+ * Checks if the given MIME type is HLS MIME type.
199
+ *
200
+ * @param {string} mimeType
201
+ * @return {boolean}
202
+ */
203
+ static isHlsType(mimeType) {
204
+ return mimeType === 'application/x-mpegurl' ||
205
+ mimeType === 'application/vnd.apple.mpegurl';
206
+ }
207
+
197
208
  /**
198
209
  * Get the base and profile of a codec string. Where [0] will be the codec
199
210
  * base and [1] will be the profile.
@@ -703,26 +703,38 @@ shaka.util.StreamUtils = class {
703
703
  }
704
704
 
705
705
  if (audio) {
706
- if (!keySystemConfig.audio) {
706
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
707
+ if (info.audioRobustness != '') {
708
+ if (!keySystemConfig.audio) {
709
+ // KeySystemTrackConfiguration
710
+ keySystemConfig.audio = {
711
+ robustness: info.audioRobustness,
712
+ };
713
+ } else {
714
+ keySystemConfig.audio.robustness =
715
+ keySystemConfig.audio.robustness || info.audioRobustness;
716
+ }
717
+ } else if (!keySystemConfig.audio) {
707
718
  // KeySystemTrackConfiguration
708
- keySystemConfig.audio = {
709
- robustness: info.audioRobustness,
710
- };
711
- } else {
712
- keySystemConfig.audio.robustness =
713
- keySystemConfig.audio.robustness || info.audioRobustness;
719
+ keySystemConfig.audio = {};
714
720
  }
715
721
  }
716
722
 
717
723
  if (video) {
718
- if (!keySystemConfig.video) {
724
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
725
+ if (info.videoRobustness != '') {
726
+ if (!keySystemConfig.video) {
727
+ // KeySystemTrackConfiguration
728
+ keySystemConfig.video = {
729
+ robustness: info.videoRobustness,
730
+ };
731
+ } else {
732
+ keySystemConfig.video.robustness =
733
+ keySystemConfig.video.robustness || info.videoRobustness;
734
+ }
735
+ } else if (!keySystemConfig.video) {
719
736
  // KeySystemTrackConfiguration
720
- keySystemConfig.video = {
721
- robustness: info.videoRobustness,
722
- };
723
- } else {
724
- keySystemConfig.video.robustness =
725
- keySystemConfig.video.robustness || info.videoRobustness;
737
+ keySystemConfig.video = {};
726
738
  }
727
739
  }
728
740
  }
@@ -809,7 +821,7 @@ shaka.util.StreamUtils = class {
809
821
  const video = variant.video;
810
822
  if (audio && currentVariant && currentVariant.audio) {
811
823
  if (!StreamUtils.areStreamsCompatible_(audio, currentVariant.audio)) {
812
- shaka.log.debug('Droping variant - not compatible with active audio',
824
+ shaka.log.debug('Dropping variant - not compatible with active audio',
813
825
  'active audio',
814
826
  StreamUtils.getStreamSummaryString_(currentVariant.audio),
815
827
  'variant.audio',
@@ -820,7 +832,7 @@ shaka.util.StreamUtils = class {
820
832
 
821
833
  if (video && currentVariant && currentVariant.video) {
822
834
  if (!StreamUtils.areStreamsCompatible_(video, currentVariant.video)) {
823
- shaka.log.debug('Droping variant - not compatible with active video',
835
+ shaka.log.debug('Dropping variant - not compatible with active video',
824
836
  'active video',
825
837
  StreamUtils.getStreamSummaryString_(currentVariant.video),
826
838
  '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": "3.2.19",
4
+ "version": "3.2.21",
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
  });
@@ -3275,7 +3275,12 @@ describe('StreamingEngine', () => {
3275
3275
  netEngine.request.and.callFake((requestType, request) => {
3276
3276
  const buffer = new ArrayBuffer(0);
3277
3277
  /** @type {shaka.extern.Response} */
3278
- const response = {uri: request.uris[0], data: buffer, headers: {}};
3278
+ const response = {
3279
+ uri: request.uris[0],
3280
+ originalUri: request.uris[0],
3281
+ data: buffer,
3282
+ headers: {},
3283
+ };
3279
3284
  return shaka.util.AbortableOperation.completed(response);
3280
3285
  });
3281
3286
 
@@ -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')
@@ -336,6 +336,45 @@ describe('Player', () => {
336
336
  player.setTextTrackVisibility(true);
337
337
  expect(getTracksActive()).toEqual([false, true]);
338
338
  });
339
+
340
+ // https://github.com/shaka-project/shaka-player/issues/4821
341
+ it('loads a single text stream', async () => {
342
+ player.configure({preferredTextLanguage: 'en'});
343
+ await player.load('test:sintel_no_text_compiled');
344
+
345
+ // Add preferred language text track.
346
+ const locationUri = new goog.Uri(location.href);
347
+ const partialUri = new goog.Uri('/base/test/test/assets/text-clip.vtt');
348
+ const absoluteUri = locationUri.resolve(partialUri);
349
+ await player.addTextTrackAsync(
350
+ absoluteUri.toString(), 'en', 'subtitles', 'text/vtt');
351
+
352
+ // Add alternate language text track.
353
+ // Two text tracks with same timings but different text
354
+ // are necessary for test.
355
+ const partialUri2 =
356
+ new goog.Uri('/base/test/test/assets/text-clip-alt.vtt');
357
+ const absoluteUri2 = locationUri.resolve(partialUri2);
358
+ await player.addTextTrackAsync(
359
+ absoluteUri2.toString(), 'fr', 'subtitles', 'text/vtt');
360
+
361
+ const textTracks = player.getTextTracks();
362
+ expect(textTracks.length).toBe(2);
363
+ expect(textTracks[0].language).toBe('en');
364
+ expect(textTracks[1].language).toBe('fr');
365
+
366
+ // Enable text visibilty and immediately change language.
367
+ // Only one set of cues should be active.
368
+ // Cues should be of the selected language track.
369
+ player.setTextTrackVisibility(true);
370
+ player.selectTextLanguage('fr');
371
+ video.currentTime = 5;
372
+ video.play();
373
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
374
+
375
+ expect(video.textTracks[0].activeCues.length).toBe(1);
376
+ expect(player.getTextTracks()[1].active).toBe(true);
377
+ });
339
378
  }); // describe('setTextTrackVisibility')
340
379
 
341
380
  describe('plays', () => {
@@ -370,6 +370,60 @@ describe('Player', () => {
370
370
  expect(streamingEngine.unloadTextStream).not.toHaveBeenCalled();
371
371
  });
372
372
  });
373
+
374
+ describe('when config.streaming.preferNativeHls is set to true', () => {
375
+ beforeEach(() => {
376
+ shaka.media.ManifestParser.registerParserByMime(
377
+ 'application/x-mpegurl',
378
+ () => new shaka.test.FakeManifestParser(manifest));
379
+ });
380
+
381
+ afterEach(() => {
382
+ shaka.media.ManifestParser.unregisterParserByMime(
383
+ 'application/x-mpegurl');
384
+ video.canPlayType.calls.reset();
385
+ });
386
+
387
+ it('only applies to HLS streams', async () => {
388
+ video.canPlayType.and.returnValue('maybe');
389
+ spyOn(shaka.util.Platform, 'anyMediaElement').and.returnValue(video);
390
+ spyOn(shaka.util.Platform, 'supportsMediaSource').and.returnValue(true);
391
+ spyOn(shaka.util.Platform, 'isApple').and.returnValue(false);
392
+ // Make sure player.load() resolves for src=
393
+ spyOn(shaka.util.MediaReadyState, 'waitForReadyState').and.callFake(
394
+ (mediaElement, readyState, eventManager, callback) => {
395
+ callback();
396
+ });
397
+
398
+ player.configure({
399
+ streaming: {
400
+ preferNativeHls: true,
401
+ useNativeHlsOnSafari: false,
402
+ },
403
+ });
404
+
405
+ await player.load(fakeManifestUri, undefined, 'application/x-mpegurl');
406
+
407
+ expect(player.getLoadMode()).toBe(shaka.Player.LoadMode.SRC_EQUALS);
408
+ });
409
+
410
+ it('does not apply to non-HLS streams', async () => {
411
+ video.canPlayType.and.returnValue('maybe');
412
+ spyOn(shaka.util.Platform, 'supportsMediaSource').and.returnValue(true);
413
+ spyOn(shaka.util.Platform, 'isApple').and.returnValue(false);
414
+
415
+ player.configure({
416
+ streaming: {
417
+ preferNativeHls: true,
418
+ useNativeHlsOnSafari: false,
419
+ },
420
+ });
421
+
422
+ await player.load(fakeManifestUri, 0, fakeMimeType);
423
+
424
+ expect(player.getLoadMode()).toBe(shaka.Player.LoadMode.MEDIA_SOURCE);
425
+ });
426
+ });
373
427
  }); // describe('load/unload')
374
428
 
375
429
  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.
@@ -74,6 +74,9 @@ shaka.test.FakeDrmEngine = class {
74
74
  /** @type {!jasmine.Spy} */
75
75
  this.supportsVariant = jasmine.createSpy('supportsVariant');
76
76
  this.supportsVariant.and.returnValue(true);
77
+
78
+ /** @type {!jasmine.Spy} */
79
+ this.setSrcEquals = jasmine.createSpy('setSrcEquals');
77
80
  }
78
81
 
79
82
  /**
@@ -225,6 +225,9 @@ shaka.test.FakeVideo = class {
225
225
 
226
226
  /** @type {!jasmine.Spy} */
227
227
  this.dispatchEvent = jasmine.createSpy('dispatchEvent');
228
+
229
+ /** @type {!jasmine.Spy} */
230
+ this.canPlayType = jasmine.createSpy('canPlayType');
228
231
  }
229
232
  };
230
233
 
@@ -431,6 +431,7 @@ const widevineDrmServers = {
431
431
 
432
432
  /** @type {AVMetadataType} */
433
433
  const axinomMultiDrmVideoSegment = {
434
+ // Taken from Axinom's v6 test vector.
434
435
  initSegmentUri: '/base/test/test/assets/multidrm-video-init.mp4',
435
436
  mdhdOffset: 0x1d1,
436
437
  segmentUri: '/base/test/test/assets/multidrm-video-segment.mp4',
@@ -445,6 +446,7 @@ const axinomMultiDrmVideoSegment = {
445
446
 
446
447
  /** @type {AVMetadataType} */
447
448
  const axinomMultiDrmAudioSegment = {
449
+ // Taken from Axinom's v6 test vector.
448
450
  initSegmentUri: '/base/test/test/assets/multidrm-audio-init.mp4',
449
451
  mdhdOffset: 0x192,
450
452
  segmentUri: '/base/test/test/assets/multidrm-audio-segment.mp4',
@@ -459,20 +461,15 @@ const axinomMultiDrmAudioSegment = {
459
461
 
460
462
  /** @type {!Object.<string, string>} */
461
463
  const axinomDrmServers = {
464
+ // NOTE: These are not Axinom's actual servers. These are test servers for
465
+ // Widevine and PlayReady that let us specify the known key IDs and keys for
466
+ // Axinom's v6 test vectors. Axinom's own servers started returning 403
467
+ // errors for these older test vectors, and we were forced to switch to
468
+ // something stable and independent.
462
469
  'com.widevine.alpha':
463
- 'https://drm-widevine-licensing.axtest.net/AcquireLicense',
470
+ 'https://cwip-shaka-proxy.appspot.com/specific_key?blodJidXR9eARuql0dNLWg=GX8m9XLIZNIzizrl0RTqnA',
464
471
  'com.microsoft.playready':
465
- 'https://drm-playready-licensing.axtest.net/AcquireLicense',
466
- };
467
-
468
- /** @type {!Object.<string, string>} */
469
- const axinomDrmHeaders = {
470
- 'X-AxDRM-Message':
471
- 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5' +
472
- 'X2lkIjoiNjllNTQwODgtZTllMC00NTMwLThjMWEtMWViNmRjZDBkMTRlIiwibWVzc' +
473
- '2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIj' +
474
- 'oiNmU1YTFkMjYtMjc1Ny00N2Q3LTgwNDYtZWFhNWQxZDM0YjVhIn1dfX0.yF7PflO' +
475
- 'Pv9qHnu3ZWJNZ12jgkqTabmwXbDWk_47tLNE',
472
+ 'https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(kid:6e5a1d26-2757-47d7-8046-eaa5d1d34b5a,contentkey:GX8m9XLIZNIzizrl0RTqnA==,sl:150)',
476
473
  };
477
474
 
478
475
  /** @type {TextMetadataType} */
@@ -568,7 +565,6 @@ shaka.test.TestScheme.DATA = {
568
565
  audio: axinomMultiDrmAudioSegment,
569
566
  text: vttSegment,
570
567
  licenseServers: axinomDrmServers,
571
- licenseRequestHeaders: axinomDrmHeaders,
572
568
  duration: 30,
573
569
  },
574
570
 
@@ -580,7 +576,6 @@ shaka.test.TestScheme.DATA = {
580
576
  initData: undefined,
581
577
  }),
582
578
  licenseServers: axinomDrmServers,
583
- licenseRequestHeaders: axinomDrmHeaders,
584
579
  duration: 30,
585
580
  },
586
581
 
@@ -170,6 +170,14 @@ describe('Mp4VttParser', () => {
170
170
  verifyHelper(cues, result);
171
171
  });
172
172
 
173
+ it('handles empty media segments', () => {
174
+ const parser = new shaka.text.Mp4VttParser();
175
+ parser.parseInit(vttInitSegment);
176
+ const time = {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0};
177
+ const result = parser.parseMedia(new Uint8Array(0), time);
178
+ verifyHelper([], result);
179
+ });
180
+
173
181
  it('rejects init segment with no vtt', () => {
174
182
  const error = shaka.test.Util.jasmineError(new shaka.util.Error(
175
183
  shaka.util.Error.Severity.CRITICAL,
@@ -776,11 +776,35 @@ describe('VttTextParser', () => {
776
776
  it('support escaped html payload', () => {
777
777
  verifyHelper(
778
778
  [
779
- {startTime: 20.1, endTime: 40.505, payload: '"Test & 1"\u{a0}'},
779
+ {
780
+ startTime: 20.1,
781
+ endTime: 40.505,
782
+ payload: '"Test & 1"\u{a0}',
783
+ },
784
+ {
785
+ startTime: 41,
786
+ endTime: 42,
787
+ payload: '',
788
+ nestedCues: [
789
+ {
790
+ startTime: 41,
791
+ endTime: 42,
792
+ payload: 'Test',
793
+ fontStyle: Cue.fontStyle.ITALIC,
794
+ },
795
+ {
796
+ startTime: 41,
797
+ endTime: 42,
798
+ payload: '&',
799
+ },
800
+ ],
801
+ },
780
802
  ],
781
803
  'WEBVTT\n\n' +
782
804
  '00:00:20.100 --> 00:00:40.505\n' +
783
- '&quot;Test &amp; 1&quot;&nbsp;',
805
+ '&quot;Test &amp; 1&quot;&nbsp;\n\n' +
806
+ '00:00:41.000 --> 00:00:42.000\n' +
807
+ '<i>Test</i>&amp;',
784
808
  {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
785
809
  });
786
810