shaka-player 3.2.6 → 3.2.9

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 (82) hide show
  1. package/.github/workflows/build-and-test.yaml +0 -1
  2. package/.github/workflows/release-please.yaml +4 -3
  3. package/.github/workflows/selenium-lab-tests.yaml +0 -1
  4. package/AUTHORS +1 -1
  5. package/CHANGELOG.md +39 -0
  6. package/CONTRIBUTORS +2 -1
  7. package/README.md +4 -4
  8. package/build/README.md +2 -2
  9. package/build/generateTsDefs.py +0 -2
  10. package/build/test.py +8 -2
  11. package/demo/common/assets.js +1 -1
  12. package/demo/demo.less +0 -1
  13. package/demo/main.js +3 -3
  14. package/dist/controls.css +2 -2
  15. package/dist/controls.css.map +1 -1
  16. package/dist/demo.compiled.debug.js +3 -3
  17. package/dist/demo.compiled.debug.map +2 -2
  18. package/dist/demo.compiled.js +3 -3
  19. package/dist/demo.compiled.map +2 -2
  20. package/dist/demo.css +1 -1
  21. package/dist/demo.css.map +1 -1
  22. package/dist/deps.js +1 -1
  23. package/dist/locales.js +28 -28
  24. package/dist/receiver.compiled.debug.js +1 -1
  25. package/dist/receiver.compiled.debug.map +1 -1
  26. package/dist/receiver.compiled.js +1 -1
  27. package/dist/receiver.compiled.map +1 -1
  28. package/dist/shaka-player.compiled.d.ts +1 -2
  29. package/dist/shaka-player.compiled.debug.d.ts +1 -2
  30. package/dist/shaka-player.compiled.debug.externs.js +1 -0
  31. package/dist/shaka-player.compiled.debug.js +213 -207
  32. package/dist/shaka-player.compiled.debug.map +4 -4
  33. package/dist/shaka-player.compiled.externs.js +1 -0
  34. package/dist/shaka-player.compiled.js +775 -769
  35. package/dist/shaka-player.compiled.map +4 -4
  36. package/dist/shaka-player.ui.d.ts +1 -2
  37. package/dist/shaka-player.ui.debug.d.ts +1 -2
  38. package/dist/shaka-player.ui.debug.externs.js +1 -0
  39. package/dist/shaka-player.ui.debug.js +241 -236
  40. package/dist/shaka-player.ui.debug.map +4 -4
  41. package/dist/shaka-player.ui.externs.js +1 -0
  42. package/dist/shaka-player.ui.js +898 -891
  43. package/dist/shaka-player.ui.map +4 -4
  44. package/karma.conf.js +4 -0
  45. package/lib/abr/simple_abr_manager.js +2 -1
  46. package/lib/dash/dash_parser.js +2 -3
  47. package/lib/hls/hls_parser.js +45 -18
  48. package/lib/media/drm_engine.js +3 -0
  49. package/lib/media/media_source_engine.js +7 -1
  50. package/lib/offline/indexeddb/storage_mechanism.js +4 -2
  51. package/lib/player.js +165 -107
  52. package/lib/util/config_utils.js +25 -0
  53. package/lib/util/error.js +7 -0
  54. package/lib/util/manifest_parser_utils.js +1 -1
  55. package/lib/util/mime_utils.js +62 -6
  56. package/lib/util/periods.js +5 -4
  57. package/lib/util/player_configuration.js +9 -14
  58. package/lib/util/stream_utils.js +5 -2
  59. package/package.json +6 -3
  60. package/test/cast/cast_utils_unit.js +1 -0
  61. package/test/dash/dash_parser_manifest_unit.js +0 -24
  62. package/test/hls/hls_live_unit.js +86 -7
  63. package/test/hls/manifest_text_parser_unit.js +19 -0
  64. package/test/media/media_source_engine_integration.js +1 -0
  65. package/test/media/media_source_engine_unit.js +4 -4
  66. package/test/media/streaming_engine_integration.js +2 -0
  67. package/test/offline/indexeddb_storage_unit.js +1 -1
  68. package/test/offline/storage_compatibility_unit.js +1 -1
  69. package/test/player_external.js +7 -1
  70. package/test/player_integration.js +6 -10
  71. package/test/player_src_equals_integration.js +81 -83
  72. package/test/player_unit.js +98 -1
  73. package/test/test/boot.js +9 -0
  74. package/test/test/externs/filters.js +4 -0
  75. package/test/test/util/simple_fakes.js +31 -2
  76. package/test/util/mime_utils_unit.js +54 -0
  77. package/test/util/periods_unit.js +79 -0
  78. package/ui/less/containers.less +1 -1
  79. package/ui/less/general.less +1 -1
  80. package/ui/less/range_elements.less +1 -0
  81. package/.github/pull_request_template.md +0 -38
  82. package/docs/tutorials/gsoc-ideas-list.md +0 -3
@@ -574,8 +574,8 @@ shaka.util.PeriodCombiner = class {
574
574
  // TODO(#1528): Consider changing this when we support codec switching.
575
575
  const hasCodec = outputStreams.some((s) => {
576
576
  return s.mimeType == stream.mimeType &&
577
- shaka.util.MimeUtils.getCodecBase(s.codecs) ==
578
- shaka.util.MimeUtils.getCodecBase(stream.codecs);
577
+ shaka.util.MimeUtils.getNormalizedCodec(s.codecs) ==
578
+ shaka.util.MimeUtils.getNormalizedCodec(stream.codecs);
579
579
  });
580
580
  if (!hasCodec) {
581
581
  continue;
@@ -1016,10 +1016,11 @@ shaka.util.PeriodCombiner = class {
1016
1016
  * @private
1017
1017
  */
1018
1018
  static areAVStreamsCompatible_(outputStream, candidate) {
1019
- const getCodecBase = (codecs) => shaka.util.MimeUtils.getCodecBase(codecs);
1019
+ const getCodec = (codecs) =>
1020
+ shaka.util.MimeUtils.getNormalizedCodec(codecs);
1020
1021
  // Check MIME type and codecs, which should always be the same.
1021
1022
  if (candidate.mimeType != outputStream.mimeType ||
1022
- getCodecBase(candidate.codecs) != getCodecBase(outputStream.codecs)) {
1023
+ getCodec(candidate.codecs) != getCodec(outputStream.codecs)) {
1023
1024
  return false;
1024
1025
  }
1025
1026
 
@@ -17,14 +17,6 @@ goog.require('shaka.util.ManifestParserUtils');
17
17
  goog.require('shaka.util.Platform');
18
18
 
19
19
 
20
- // TODO(vaage): Many times in our configs, we need to create an empty
21
- // implementation of a method, but to avoid closure from removing unused
22
- // parameters (and breaking our merge config code) we need to use each
23
- // parameter. Is there a better solution to this problem than what we are
24
- // doing now?
25
- //
26
- // NOTE: Chrome App Content Security Policy prohibits usage of new Function()
27
-
28
20
  /**
29
21
  * @final
30
22
  * @export
@@ -109,11 +101,10 @@ shaka.util.PlayerConfiguration = class {
109
101
  'urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb':
110
102
  'com.adobe.primetime',
111
103
  },
112
- // Need some operation in the callback or else closure may remove calls
113
- // to the function as it would be a no-op. The operation can't just be
114
- // a log message, because those are stripped in the compiled build.
115
104
  manifestPreprocessor: (element) => {
116
- return element;
105
+ return shaka.util.ConfigUtils.referenceParametersAndReturn(
106
+ [element],
107
+ element);
117
108
  },
118
109
  },
119
110
  hls: {
@@ -130,7 +121,9 @@ shaka.util.PlayerConfiguration = class {
130
121
  // log message, because those are stripped in the compiled build.
131
122
  failureCallback: (error) => {
132
123
  shaka.log.error('Unhandled streaming error', error);
133
- return [error];
124
+ return shaka.util.ConfigUtils.referenceParametersAndReturn(
125
+ [error],
126
+ undefined);
134
127
  },
135
128
  // When low latency streaming is enabled, rebufferingGoal will default to
136
129
  // 0.01 if not specified.
@@ -206,7 +199,9 @@ shaka.util.PlayerConfiguration = class {
206
199
  // to the function as it would be a no-op. The operation can't just be a
207
200
  // log message, because those are stripped in the compiled build.
208
201
  progressCallback: (content, progress) => {
209
- return [content, progress];
202
+ return shaka.util.ConfigUtils.referenceParametersAndReturn(
203
+ [content, progress],
204
+ undefined);
210
205
  },
211
206
 
212
207
  // By default we use persistent licenses as forces errors to surface if
@@ -283,12 +283,14 @@ shaka.util.StreamUtils = class {
283
283
  // both be considered the same codec: avc1.42c01e, avc1.4d401f
284
284
  let baseVideoCodec = '';
285
285
  if (variant.video) {
286
- baseVideoCodec = shaka.util.MimeUtils.getCodecBase(variant.video.codecs);
286
+ baseVideoCodec =
287
+ shaka.util.MimeUtils.getNormalizedCodec(variant.video.codecs);
287
288
  }
288
289
 
289
290
  let baseAudioCodec = '';
290
291
  if (variant.audio) {
291
- baseAudioCodec = shaka.util.MimeUtils.getCodecBase(variant.audio.codecs);
292
+ baseAudioCodec =
293
+ shaka.util.MimeUtils.getNormalizedCodec(variant.audio.codecs);
292
294
  }
293
295
 
294
296
  return baseVideoCodec + '-' + baseAudioCodec;
@@ -979,6 +981,7 @@ shaka.util.StreamUtils = class {
979
981
  track.channelsCount = audio.channelsCount;
980
982
  track.audioSamplingRate = audio.audioSamplingRate;
981
983
  track.audioBandwidth = audio.bandwidth || null;
984
+ track.spatialAudio = audio.spatialAudio;
982
985
  track.label = audio.label;
983
986
  track.audioRoles = audio.roles;
984
987
  }
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.6",
4
+ "version": "3.2.9",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -50,7 +50,7 @@
50
50
  "less": "https://gitpkg.now.sh/joeyparrish/less.js/packages/less?28c63a43",
51
51
  "less-plugin-clean-css": "github:austingardner/less-plugin-clean-css#4e9e77bf",
52
52
  "material-design-lite": "^1.3.0",
53
- "mux.js": "^5.14.1",
53
+ "mux.js": "^6.1.0",
54
54
  "open-sans-fonts": "^1.6.2",
55
55
  "postcss-less": "^6.0.0",
56
56
  "pwacompat": "^2.0.17",
@@ -96,6 +96,9 @@
96
96
  "prepublishOnly": "python build/checkversion.py && python build/all.py --force"
97
97
  },
98
98
  "dependencies": {
99
- "eme-encryption-scheme-polyfill": "^2.0.3"
99
+ "eme-encryption-scheme-polyfill": "^2.0.5"
100
+ },
101
+ "engines": {
102
+ "node": ">=14"
100
103
  }
101
104
  }
@@ -189,6 +189,7 @@ describe('CastUtils', () => {
189
189
  const fakeVideoStream = {
190
190
  mimeType: 'video/mp4',
191
191
  codecs: 'avc1.42c01e',
192
+ drmInfos: [],
192
193
  };
193
194
  const initSegmentUrl = '/base/test/test/assets/sintel-video-init.mp4';
194
195
  const videoSegmentUrl =
@@ -445,30 +445,6 @@ describe('DashParser Manifest', () => {
445
445
  expect(stream.closedCaptions).toEqual(expectedClosedCaptions);
446
446
  });
447
447
 
448
- it('Detects E-AC3 JOC content by SupplementalProperty', async () => {
449
- const idUri = 'tag:dolby.com,2018:dash:EC3_ExtensionType:2018';
450
- const source = [
451
- '<MPD>',
452
- ' <Period duration="PT30M">',
453
- ' <AdaptationSet mimeType="audio/mp4" lang="\u2603">',
454
- ' <Representation bandwidth="500">',
455
- ' <SupplementalProperty schemeIdUri="' + idUri + '" value="JOC"/>',
456
- ' <BaseURL>http://example.com</BaseURL>',
457
- ' <SegmentTemplate media="2.mp4" duration="1" />',
458
- ' </Representation>',
459
- ' </AdaptationSet>',
460
- ' </Period>',
461
- '</MPD>',
462
- ].join('\n');
463
-
464
- fakeNetEngine.setResponseText('dummy://foo', source);
465
-
466
- /** @type {shaka.extern.Manifest} */
467
- const manifest = await parser.start('dummy://foo', playerInterface);
468
- const stream = manifest.variants[0].audio;
469
- expect(stream.mimeType).toBe('audio/eac3-joc');
470
- });
471
-
472
448
  it('Detects spatial audio', async () => {
473
449
  const idUri = 'tag:dolby.com,2018:dash:EC3_ExtensionType:2018';
474
450
  const source = [
@@ -630,11 +630,13 @@ describe('HlsParser live', () => {
630
630
  expect(ref.startTime).not.toBeLessThan(rolloverOffset);
631
631
  });
632
632
 
633
+ // Test for https://github.com/shaka-project/shaka-player/issues/4223
633
634
  it('parses streams with partial and preload hinted segments', async () => {
634
635
  playerInterface.isLowLatencyMode = () => true;
635
636
  const mediaWithPartialSegments = [
636
637
  '#EXTM3U\n',
637
638
  '#EXT-X-TARGETDURATION:5\n',
639
+ '#EXT-X-PART-INF:PART-TARGET=1.5\n',
638
640
  '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
639
641
  '#EXT-X-MEDIA-SEQUENCE:0\n',
640
642
  // ref includes partialRef, partialRef2
@@ -668,6 +670,11 @@ describe('HlsParser live', () => {
668
670
  segmentDataStartTime + 4, /* baseUri= */ '', /* startByte= */ 200,
669
671
  /* endByte= */ 429);
670
672
 
673
+ const ref = ManifestParser.makeReference(
674
+ 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 4,
675
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 429,
676
+ /* timestampOffset= */ 0, [partialRef, partialRef2]);
677
+
671
678
  const partialRef3 = ManifestParser.makeReference(
672
679
  'test:/partial.mp4', segmentDataStartTime + 4,
673
680
  segmentDataStartTime + 6,
@@ -677,17 +684,12 @@ describe('HlsParser live', () => {
677
684
  // so its startTime and endTime are the same.
678
685
  const preloadRef = ManifestParser.makeReference(
679
686
  'test:/partial.mp4', segmentDataStartTime + 6,
680
- segmentDataStartTime + 6,
687
+ segmentDataStartTime + 7.5,
681
688
  /* baseUri= */ '', /* startByte= */ 210, /* endByte= */ null);
682
689
 
683
- const ref = ManifestParser.makeReference(
684
- 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 4,
685
- /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 429,
686
- /* timestampOffset= */ 0, [partialRef, partialRef2]);
687
-
688
690
  // ref2 is not fully published yet, so it doesn't have a segment uri.
689
691
  const ref2 = ManifestParser.makeReference(
690
- '', segmentDataStartTime + 4, segmentDataStartTime + 6,
692
+ '', segmentDataStartTime + 4, segmentDataStartTime + 7.5,
691
693
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
692
694
  /* timestampOffset= */ 0, [partialRef3, preloadRef]);
693
695
 
@@ -697,6 +699,83 @@ describe('HlsParser live', () => {
697
699
  ManifestParser.verifySegmentIndex(video, [ref, ref2]);
698
700
  });
699
701
 
702
+ // Test for https://github.com/shaka-project/shaka-player/issues/4223
703
+ it('ignores preload hinted segments without target duration', async () => {
704
+ playerInterface.isLowLatencyMode = () => true;
705
+
706
+ // Missing PART-TARGET, so preload hints are skipped.
707
+ const mediaWithPartialSegments = [
708
+ '#EXTM3U\n',
709
+ '#EXT-X-TARGETDURATION:5\n',
710
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
711
+ '#EXT-X-MEDIA-SEQUENCE:0\n',
712
+ '#EXTINF:4,\n',
713
+ // ref1
714
+ 'main.mp4\n',
715
+ // ref2 includes partialRef, but not preloadRef
716
+ // partialRef
717
+ '#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
718
+ // preloadRef
719
+ '#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210\n',
720
+ ].join('');
721
+
722
+ fakeNetEngine
723
+ .setResponseText('test:/master', master)
724
+ .setResponseText('test:/video', mediaWithPartialSegments)
725
+ .setResponseValue('test:/init.mp4', initSegmentData)
726
+ .setResponseValue('test:/main.mp4', segmentData)
727
+ .setResponseValue('test:/partial.mp4', segmentData)
728
+ .setResponseValue('test:/partial2.mp4', segmentData);
729
+
730
+ const ref1 = ManifestParser.makeReference(
731
+ 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 4,
732
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
733
+ /* timestampOffset= */ 0, []);
734
+
735
+ const partialRef = ManifestParser.makeReference(
736
+ 'test:/partial.mp4', segmentDataStartTime + 4,
737
+ segmentDataStartTime + 6,
738
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209);
739
+
740
+ // ref2 is not fully published yet, so it doesn't have a segment uri.
741
+ const ref2 = ManifestParser.makeReference(
742
+ '', segmentDataStartTime + 4, segmentDataStartTime + 6,
743
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209,
744
+ /* timestampOffset= */ 0, [partialRef]);
745
+
746
+ const manifest = await parser.start('test:/master', playerInterface);
747
+ const video = manifest.variants[0].video;
748
+ await video.createSegmentIndex();
749
+ ManifestParser.verifySegmentIndex(video, [ref1, ref2]);
750
+ });
751
+
752
+ // Test for https://github.com/shaka-project/shaka-player/issues/4185
753
+ it('does not fail on preload hints with LL mode off', async () => {
754
+ // LL mode must be off for this test!
755
+ playerInterface.isLowLatencyMode = () => false;
756
+
757
+ const mediaWithPartialSegments = [
758
+ '#EXTM3U\n',
759
+ '#EXT-X-TARGETDURATION:5\n',
760
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
761
+ '#EXT-X-PART-INF:PART-TARGET=1.5\n',
762
+ '#EXTINF:4,\n',
763
+ 'main.mp4\n',
764
+ '#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
765
+ '#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210\n',
766
+ ].join('');
767
+
768
+ fakeNetEngine
769
+ .setResponseText('test:/master', master)
770
+ .setResponseText('test:/video', mediaWithPartialSegments)
771
+ .setResponseValue('test:/init.mp4', initSegmentData)
772
+ .setResponseValue('test:/main.mp4', segmentData)
773
+ .setResponseValue('test:/partial.mp4', segmentData);
774
+
775
+ // If this throws, the test fails. Otherwise, it passes.
776
+ await parser.start('test:/master', playerInterface);
777
+ });
778
+
700
779
  describe('update', () => {
701
780
  it('adds new segments when they appear', async () => {
702
781
  const ref1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
@@ -238,6 +238,25 @@ describe('ManifestTextParser', () => {
238
238
  '#EXTM3U\n' +
239
239
  '#EXT-X-MEDIA:CODECS="avc1.64002a,mp4a.40.2",AUDIO="a1,a2"',
240
240
 
241
+ // manifest URI:
242
+ 'https://test/manifest.m3u8');
243
+
244
+ verifyPlaylist(
245
+ {
246
+ type: shaka.hls.PlaylistType.MASTER,
247
+ tags: [
248
+ new shaka.hls.Tag(/* id= */ 3, 'EXT-X-MEDIA',
249
+ [
250
+ new shaka.hls.Attribute('CODECS',
251
+ 'av01.0.08M.08,mp4a.40.2'),
252
+ ]),
253
+ ],
254
+ },
255
+
256
+ // playlist text:
257
+ '#EXTM3U\n' +
258
+ '#EXT-X-MEDIA:CODECS="av01.0.08M.08,mp4a.40.2"',
259
+
241
260
  // manifest URI:
242
261
  'https://test/manifest.m3u8');
243
262
  });
@@ -103,6 +103,7 @@ describe('MediaSourceEngine', () => {
103
103
  return {
104
104
  mimeType: streamMetadata.mimeType,
105
105
  codecs: streamMetadata.codecs,
106
+ drmInfos: [],
106
107
  };
107
108
  }
108
109
 
@@ -49,10 +49,10 @@ describe('MediaSourceEngine', () => {
49
49
  const buffer2 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (2));
50
50
  const buffer3 = /** @type {!ArrayBuffer} */ (/** @type {?} */ (3));
51
51
 
52
- const fakeVideoStream = {mimeType: 'video/foo'};
53
- const fakeAudioStream = {mimeType: 'audio/foo'};
54
- const fakeTextStream = {mimeType: 'text/foo'};
55
- const fakeTransportStream = {mimeType: 'tsMimetype'};
52
+ const fakeVideoStream = {mimeType: 'video/foo', drmInfos: []};
53
+ const fakeAudioStream = {mimeType: 'audio/foo', drmInfos: []};
54
+ const fakeTextStream = {mimeType: 'text/foo', drmInfos: []};
55
+ const fakeTransportStream = {mimeType: 'tsMimetype', drmInfos: []};
56
56
 
57
57
  let audioSourceBuffer;
58
58
  let videoSourceBuffer;
@@ -621,6 +621,7 @@ describe('StreamingEngine', () => {
621
621
  width: 600,
622
622
  height: 400,
623
623
  type: shaka.util.ManifestParserUtils.ContentType.VIDEO,
624
+ drmInfos: [],
624
625
  },
625
626
  audio: {
626
627
  id: 3,
@@ -630,6 +631,7 @@ describe('StreamingEngine', () => {
630
631
  codecs: 'mp4a.40.2',
631
632
  bandwidth: 192000,
632
633
  type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
634
+ drmInfos: [],
633
635
  },
634
636
  }],
635
637
  };
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- filterDescribe('IndexeddbStorageCell', () => window.indexedDB, () => {
7
+ filterDescribe('IndexeddbStorageCell', offlineSupported, () => {
8
8
  const IndexedDBUtils = shaka.test.IndexedDBUtils;
9
9
  const OfflineUtils = shaka.test.OfflineUtils;
10
10
  const Util = shaka.test.Util;
@@ -91,7 +91,7 @@ const compatibilityTestsMetadata = [
91
91
  },
92
92
  ];
93
93
 
94
- filterDescribe('Storage Compatibility', () => window.indexedDB, () => {
94
+ filterDescribe('Storage Compatibility', offlineSupported, () => {
95
95
  for (const metadata of compatibilityTestsMetadata) {
96
96
  describe(metadata.name, () => {
97
97
  makeTests(metadata);
@@ -120,7 +120,13 @@ describe('Player', () => {
120
120
  const networkingEngine = player.getNetworkingEngine();
121
121
  asset.applyFilters(networkingEngine);
122
122
 
123
- await player.load(asset.manifestUri);
123
+ // Rather than awaiting the load() method, catch any load() errors and
124
+ // wait on the 'canplay' event. This has the advantage that we will
125
+ // get better logging of the media state on a timeout, since that
126
+ // capabilitiy is built into the waiter for media element events.
127
+ player.load(asset.manifestUri).catch(fail);
128
+ await waiter.timeoutAfter(60).waitForEvent(video, 'canplay');
129
+
124
130
  if (asset.features) {
125
131
  const isLive = asset.features.includes(Feature.LIVE);
126
132
  expect(player.isLive()).toBe(isLive);
@@ -953,16 +953,16 @@ describe('Player', () => {
953
953
  });
954
954
  }); // describe('unloading')
955
955
 
956
- describe('chapters', () => {
957
- it('add external chapters in vtt format', async () => {
956
+ describe('addChaptersTrack', () => {
957
+ it('adds external chapters in vtt format', async () => {
958
958
  await player.load('test:sintel_no_text_compiled');
959
959
  const locationUri = new goog.Uri(location.href);
960
960
  const partialUri1 = new goog.Uri('/base/test/test/assets/chapters.vtt');
961
961
  const absoluteUri1 = locationUri.resolve(partialUri1);
962
962
  await player.addChaptersTrack(absoluteUri1.toString(), 'en');
963
963
 
964
- await shaka.test.Util.delay(1.5);
965
-
964
+ // Data should be available as soon as addChaptersTrack resolves.
965
+ // See https://github.com/shaka-project/shaka-player/issues/4186
966
966
  const chapters = player.getChapters('en');
967
967
  expect(chapters.length).toBe(3);
968
968
  const chapter1 = chapters[0];
@@ -982,8 +982,6 @@ describe('Player', () => {
982
982
  const absoluteUri2 = locationUri.resolve(partialUri2);
983
983
  await player.addChaptersTrack(absoluteUri2.toString(), 'en');
984
984
 
985
- await shaka.test.Util.delay(1.5);
986
-
987
985
  const chaptersUpdated = player.getChapters('en');
988
986
  expect(chaptersUpdated.length).toBe(6);
989
987
  const chapterUpdated1 = chaptersUpdated[0];
@@ -1012,15 +1010,13 @@ describe('Player', () => {
1012
1010
  expect(chapterUpdated6.endTime).toBe(61.349);
1013
1011
  });
1014
1012
 
1015
- it('add external chapters in srt format', async () => {
1013
+ it('adds external chapters in srt format', async () => {
1016
1014
  await player.load('test:sintel_no_text_compiled');
1017
1015
  const locationUri = new goog.Uri(location.href);
1018
1016
  const partialUri = new goog.Uri('/base/test/test/assets/chapters.srt');
1019
1017
  const absoluteUri = locationUri.resolve(partialUri);
1020
1018
  await player.addChaptersTrack(absoluteUri.toString(), 'es');
1021
1019
 
1022
- await shaka.test.Util.delay(1.5);
1023
-
1024
1020
  const chapters = player.getChapters('es');
1025
1021
  expect(chapters.length).toBe(3);
1026
1022
  const chapter1 = chapters[0];
@@ -1036,5 +1032,5 @@ describe('Player', () => {
1036
1032
  expect(chapter3.startTime).toBe(30);
1037
1033
  expect(chapter3.endTime).toBe(61.349);
1038
1034
  });
1039
- }); // describe('chapters')
1035
+ }); // describe('addChaptersTrack')
1040
1036
  });
@@ -319,90 +319,88 @@ describe('Player Src Equals', () => {
319
319
  expect(newTrack).toBeTruthy();
320
320
  });
321
321
 
322
- it('add external chapters in vtt format', async () => {
323
- await loadWithSrcEquals(SMALL_MP4_CONTENT_URI, /* startTime= */ null);
324
-
325
- const locationUri = new goog.Uri(location.href);
326
- const partialUri1 = new goog.Uri('/base/test/test/assets/chapters.vtt');
327
- const absoluteUri1 = locationUri.resolve(partialUri1);
328
- await player.addChaptersTrack(absoluteUri1.toString(), 'en');
329
-
330
- await shaka.test.Util.delay(1.5);
331
-
332
- const chapters = player.getChapters('en');
333
- expect(chapters.length).toBe(3);
334
- const chapter1 = chapters[0];
335
- expect(chapter1.title).toBe('Chapter 1');
336
- expect(chapter1.startTime).toBe(0);
337
- expect(chapter1.endTime).toBe(5);
338
- const chapter2 = chapters[1];
339
- expect(chapter2.title).toBe('Chapter 2');
340
- expect(chapter2.startTime).toBe(5);
341
- expect(chapter2.endTime).toBe(10);
342
- const chapter3 = chapters[2];
343
- expect(chapter3.title).toBe('Chapter 3');
344
- expect(chapter3.startTime).toBe(10);
345
- expect(chapter3.endTime).toBe(20);
346
-
347
- const partialUri2 = new goog.Uri('/base/test/test/assets/chapters2.vtt');
348
- const absoluteUri2 = locationUri.resolve(partialUri2);
349
- await player.addChaptersTrack(absoluteUri2.toString(), 'en');
350
-
351
- await shaka.test.Util.delay(1.5);
352
-
353
- const chaptersUpdated = player.getChapters('en');
354
- expect(chaptersUpdated.length).toBe(6);
355
- const chapterUpdated1 = chaptersUpdated[0];
356
- expect(chapterUpdated1.title).toBe('Chapter 1');
357
- expect(chapterUpdated1.startTime).toBe(0);
358
- expect(chapterUpdated1.endTime).toBe(5);
359
- const chapterUpdated2 = chaptersUpdated[1];
360
- expect(chapterUpdated2.title).toBe('Chapter 2');
361
- expect(chapterUpdated2.startTime).toBe(5);
362
- expect(chapterUpdated2.endTime).toBe(10);
363
- const chapterUpdated3 = chaptersUpdated[2];
364
- expect(chapterUpdated3.title).toBe('Chapter 3');
365
- expect(chapterUpdated3.startTime).toBe(10);
366
- expect(chapterUpdated3.endTime).toBe(20);
367
- const chapterUpdated4 = chaptersUpdated[3];
368
- expect(chapterUpdated4.title).toBe('Chapter 4');
369
- expect(chapterUpdated4.startTime).toBe(20);
370
- expect(chapterUpdated4.endTime).toBe(30);
371
- const chapterUpdated5 = chaptersUpdated[4];
372
- expect(chapterUpdated5.title).toBe('Chapter 5');
373
- expect(chapterUpdated5.startTime).toBe(30);
374
- expect(chapterUpdated5.endTime).toBe(40);
375
- const chapterUpdated6 = chaptersUpdated[5];
376
- expect(chapterUpdated6.title).toBe('Chapter 6');
377
- expect(chapterUpdated6.startTime).toBe(40);
378
- expect(chapterUpdated6.endTime).toBe(61.349);
379
- });
380
-
381
- it('add external chapters in srt format', async () => {
382
- await loadWithSrcEquals(SMALL_MP4_CONTENT_URI, /* startTime= */ null);
383
-
384
- const locationUri = new goog.Uri(location.href);
385
- const partialUri = new goog.Uri('/base/test/test/assets/chapters.srt');
386
- const absoluteUri = locationUri.resolve(partialUri);
387
- await player.addChaptersTrack(absoluteUri.toString(), 'es');
388
-
389
- await shaka.test.Util.delay(1.5);
322
+ describe('addChaptersTrack', () => {
323
+ it('adds external chapters in vtt format', async () => {
324
+ await loadWithSrcEquals(SMALL_MP4_CONTENT_URI, /* startTime= */ null);
325
+
326
+ const locationUri = new goog.Uri(location.href);
327
+ const partialUri1 = new goog.Uri('/base/test/test/assets/chapters.vtt');
328
+ const absoluteUri1 = locationUri.resolve(partialUri1);
329
+ await player.addChaptersTrack(absoluteUri1.toString(), 'en');
330
+
331
+ // Data should be available as soon as addChaptersTrack resolves.
332
+ // See https://github.com/shaka-project/shaka-player/issues/4186
333
+ const chapters = player.getChapters('en');
334
+ expect(chapters.length).toBe(3);
335
+ const chapter1 = chapters[0];
336
+ expect(chapter1.title).toBe('Chapter 1');
337
+ expect(chapter1.startTime).toBe(0);
338
+ expect(chapter1.endTime).toBe(5);
339
+ const chapter2 = chapters[1];
340
+ expect(chapter2.title).toBe('Chapter 2');
341
+ expect(chapter2.startTime).toBe(5);
342
+ expect(chapter2.endTime).toBe(10);
343
+ const chapter3 = chapters[2];
344
+ expect(chapter3.title).toBe('Chapter 3');
345
+ expect(chapter3.startTime).toBe(10);
346
+ expect(chapter3.endTime).toBe(20);
347
+
348
+ const partialUri2 = new goog.Uri('/base/test/test/assets/chapters2.vtt');
349
+ const absoluteUri2 = locationUri.resolve(partialUri2);
350
+ await player.addChaptersTrack(absoluteUri2.toString(), 'en');
351
+
352
+ const chaptersUpdated = player.getChapters('en');
353
+ expect(chaptersUpdated.length).toBe(6);
354
+ const chapterUpdated1 = chaptersUpdated[0];
355
+ expect(chapterUpdated1.title).toBe('Chapter 1');
356
+ expect(chapterUpdated1.startTime).toBe(0);
357
+ expect(chapterUpdated1.endTime).toBe(5);
358
+ const chapterUpdated2 = chaptersUpdated[1];
359
+ expect(chapterUpdated2.title).toBe('Chapter 2');
360
+ expect(chapterUpdated2.startTime).toBe(5);
361
+ expect(chapterUpdated2.endTime).toBe(10);
362
+ const chapterUpdated3 = chaptersUpdated[2];
363
+ expect(chapterUpdated3.title).toBe('Chapter 3');
364
+ expect(chapterUpdated3.startTime).toBe(10);
365
+ expect(chapterUpdated3.endTime).toBe(20);
366
+ const chapterUpdated4 = chaptersUpdated[3];
367
+ expect(chapterUpdated4.title).toBe('Chapter 4');
368
+ expect(chapterUpdated4.startTime).toBe(20);
369
+ expect(chapterUpdated4.endTime).toBe(30);
370
+ const chapterUpdated5 = chaptersUpdated[4];
371
+ expect(chapterUpdated5.title).toBe('Chapter 5');
372
+ expect(chapterUpdated5.startTime).toBe(30);
373
+ expect(chapterUpdated5.endTime).toBe(40);
374
+ const chapterUpdated6 = chaptersUpdated[5];
375
+ expect(chapterUpdated6.title).toBe('Chapter 6');
376
+ expect(chapterUpdated6.startTime).toBe(40);
377
+ expect(chapterUpdated6.endTime).toBe(61.349);
378
+ });
390
379
 
391
- const chapters = player.getChapters('es');
392
- expect(chapters.length).toBe(3);
393
- const chapter1 = chapters[0];
394
- expect(chapter1.title).toBe('Chapter 1');
395
- expect(chapter1.startTime).toBe(0);
396
- expect(chapter1.endTime).toBe(5);
397
- const chapter2 = chapters[1];
398
- expect(chapter2.title).toBe('Chapter 2');
399
- expect(chapter2.startTime).toBe(5);
400
- expect(chapter2.endTime).toBe(30);
401
- const chapter3 = chapters[2];
402
- expect(chapter3.title).toBe('Chapter 3');
403
- expect(chapter3.startTime).toBe(30);
404
- expect(chapter3.endTime).toBe(61.349);
405
- });
380
+ it('add external chapters in srt format', async () => {
381
+ await loadWithSrcEquals(SMALL_MP4_CONTENT_URI, /* startTime= */ null);
382
+
383
+ const locationUri = new goog.Uri(location.href);
384
+ const partialUri = new goog.Uri('/base/test/test/assets/chapters.srt');
385
+ const absoluteUri = locationUri.resolve(partialUri);
386
+ await player.addChaptersTrack(absoluteUri.toString(), 'es');
387
+
388
+ const chapters = player.getChapters('es');
389
+ expect(chapters.length).toBe(3);
390
+ const chapter1 = chapters[0];
391
+ expect(chapter1.title).toBe('Chapter 1');
392
+ expect(chapter1.startTime).toBe(0);
393
+ expect(chapter1.endTime).toBe(5);
394
+ const chapter2 = chapters[1];
395
+ expect(chapter2.title).toBe('Chapter 2');
396
+ expect(chapter2.startTime).toBe(5);
397
+ expect(chapter2.endTime).toBe(30);
398
+ const chapter3 = chapters[2];
399
+ expect(chapter3.title).toBe('Chapter 3');
400
+ expect(chapter3.startTime).toBe(30);
401
+ expect(chapter3.endTime).toBe(61.349);
402
+ });
403
+ }); // describe('addChaptersTrack')
406
404
 
407
405
  // Since we are not in-charge of streaming, calling |retryStreaming| should
408
406
  // have no effect.