shaka-player 3.3.4 → 4.0.1

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 (201) hide show
  1. package/.github/config.yml +1 -0
  2. package/.github/workflows/build-and-test.yaml +0 -1
  3. package/.github/workflows/demo-version-index.yaml +8 -0
  4. package/.github/workflows/release-please.yaml +19 -3
  5. package/.github/workflows/selenium-lab-tests.yaml +0 -1
  6. package/.github/workflows/sync-labels.yaml +33 -0
  7. package/.github/workflows/update-issues.yaml +29 -0
  8. package/.github/workflows/validate-pr-title.yaml +35 -0
  9. package/AUTHORS +1 -0
  10. package/CHANGELOG.md +209 -28
  11. package/CONTRIBUTORS +1 -0
  12. package/README.md +10 -7
  13. package/app-engine/demo-version-index/README.md +3 -3
  14. package/app-engine/demo-version-index/app.yaml +27 -1
  15. package/app-engine/demo-version-index/generate.py +164 -0
  16. package/app-engine/demo-version-index/main.py +4 -155
  17. package/app-engine/demo-version-index/requirements.txt +0 -1
  18. package/build/README.md +2 -2
  19. package/build/compiler.py +1 -1
  20. package/build/generateTsDefs.py +0 -2
  21. package/build/misspellings.txt +1 -0
  22. package/build/shaka-lab.yaml +0 -2
  23. package/build/test.py +7 -1
  24. package/build/types/core +0 -1
  25. package/build/types/polyfill +0 -3
  26. package/demo/common/asset.js +17 -1
  27. package/demo/common/assets.js +29 -0
  28. package/demo/common/message_ids.js +6 -3
  29. package/demo/config.js +10 -11
  30. package/demo/custom.js +39 -0
  31. package/demo/demo_utils.js +0 -1
  32. package/demo/locales/en.json +6 -3
  33. package/demo/locales/source.json +22 -10
  34. package/demo/main.js +9 -6
  35. package/demo/search.js +2 -1
  36. package/dist/controls.css +1 -1
  37. package/dist/demo.compiled.debug.js +71 -64
  38. package/dist/demo.compiled.debug.map +3 -3
  39. package/dist/demo.compiled.js +71 -64
  40. package/dist/demo.compiled.map +3 -3
  41. package/dist/demo.css +1 -1
  42. package/dist/demo.css.map +1 -1
  43. package/dist/deps.js +16 -20
  44. package/dist/locales.js +33 -31
  45. package/dist/receiver.compiled.debug.js +32 -28
  46. package/dist/receiver.compiled.debug.map +3 -3
  47. package/dist/receiver.compiled.js +32 -28
  48. package/dist/receiver.compiled.map +3 -3
  49. package/dist/shaka-player.compiled.d.ts +78 -82
  50. package/dist/shaka-player.compiled.debug.d.ts +78 -82
  51. package/dist/shaka-player.compiled.debug.externs.js +127 -126
  52. package/dist/shaka-player.compiled.debug.js +471 -523
  53. package/dist/shaka-player.compiled.debug.map +4 -4
  54. package/dist/shaka-player.compiled.externs.js +127 -126
  55. package/dist/shaka-player.compiled.js +844 -858
  56. package/dist/shaka-player.compiled.map +4 -4
  57. package/dist/shaka-player.ui.d.ts +80 -82
  58. package/dist/shaka-player.ui.debug.d.ts +80 -82
  59. package/dist/shaka-player.ui.debug.externs.js +135 -126
  60. package/dist/shaka-player.ui.debug.js +531 -581
  61. package/dist/shaka-player.ui.debug.map +4 -4
  62. package/dist/shaka-player.ui.externs.js +135 -126
  63. package/dist/shaka-player.ui.js +991 -1001
  64. package/dist/shaka-player.ui.map +4 -4
  65. package/docs/tutorials/config.md +0 -2
  66. package/docs/tutorials/drm-config.md +5 -0
  67. package/docs/tutorials/fairplay.md +7 -22
  68. package/docs/tutorials/faq.md +0 -11
  69. package/docs/tutorials/index.json +2 -8
  70. package/docs/tutorials/plugins.md +1 -3
  71. package/docs/tutorials/upgrade.md +85 -11
  72. package/externs/polyfill.js +15 -0
  73. package/externs/shaka/manifest.js +5 -1
  74. package/externs/shaka/net.js +12 -0
  75. package/externs/shaka/offline.js +5 -1
  76. package/externs/shaka/player.js +39 -21
  77. package/externs/shaka/text.js +12 -12
  78. package/externs/sourcebuffer.js +15 -0
  79. package/karma.conf.js +4 -0
  80. package/lib/ads/client_side_ad.js +13 -2
  81. package/lib/ads/client_side_ad_manager.js +22 -4
  82. package/lib/cast/cast_utils.js +0 -1
  83. package/lib/dash/content_protection.js +85 -5
  84. package/lib/dash/dash_parser.js +3 -3
  85. package/lib/hls/hls_parser.js +391 -747
  86. package/lib/hls/manifest_text_parser.js +2 -3
  87. package/lib/media/drm_engine.js +102 -37
  88. package/lib/media/gap_jumping_controller.js +10 -45
  89. package/lib/media/media_source_engine.js +157 -31
  90. package/lib/media/playhead.js +2 -5
  91. package/lib/media/presentation_timeline.js +1 -2
  92. package/lib/media/segment_index.js +13 -46
  93. package/lib/media/segment_reference.js +47 -1
  94. package/lib/media/streaming_engine.js +28 -11
  95. package/lib/media/time_ranges_utils.js +4 -9
  96. package/lib/net/networking_engine.js +3 -0
  97. package/lib/offline/indexeddb/storage_mechanism.js +4 -2
  98. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  99. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  100. package/lib/offline/manifest_converter.js +1 -0
  101. package/lib/offline/storage.js +100 -132
  102. package/lib/player.js +181 -307
  103. package/lib/polyfill/media_capabilities.js +12 -6
  104. package/lib/polyfill/mediasource.js +0 -28
  105. package/lib/polyfill/patchedmediakeys_nop.js +2 -0
  106. package/lib/polyfill/patchedmediakeys_webkit.js +2 -0
  107. package/lib/text/cue.js +0 -6
  108. package/lib/text/lrc_text_parser.js +8 -0
  109. package/lib/text/mp4_ttml_parser.js +8 -0
  110. package/lib/text/mp4_vtt_parser.js +8 -0
  111. package/lib/text/sbv_text_parser.js +8 -0
  112. package/lib/text/simple_text_displayer.js +1 -7
  113. package/lib/text/srt_text_parser.js +8 -0
  114. package/lib/text/ssa_text_parser.js +8 -0
  115. package/lib/text/text_engine.js +19 -3
  116. package/lib/text/ttml_text_parser.js +8 -0
  117. package/lib/text/ui_text_displayer.js +1 -7
  118. package/lib/text/vtt_text_parser.js +27 -5
  119. package/lib/text/web_vtt_generator.js +1 -7
  120. package/lib/util/config_utils.js +25 -0
  121. package/lib/util/error.js +16 -13
  122. package/lib/util/fairplay_utils.js +109 -0
  123. package/lib/util/functional.js +0 -42
  124. package/lib/util/manifest_parser_utils.js +1 -1
  125. package/lib/util/mime_utils.js +50 -1
  126. package/lib/util/periods.js +5 -4
  127. package/lib/util/platform.js +45 -0
  128. package/lib/util/player_configuration.js +26 -20
  129. package/lib/util/pssh.js +23 -4
  130. package/lib/util/stream_utils.js +96 -24
  131. package/lib/util/uint8array_utils.js +0 -16
  132. package/lib/util/xml_utils.js +1 -1
  133. package/package.json +4 -1
  134. package/roadmap.md +19 -19
  135. package/shaka-player.uncompiled.js +0 -3
  136. package/test/cast/cast_utils_unit.js +1 -0
  137. package/test/dash/dash_parser_content_protection_unit.js +44 -0
  138. package/test/dash/dash_parser_manifest_unit.js +0 -24
  139. package/test/dash/dash_parser_segment_template_unit.js +3 -4
  140. package/test/demo/demo_unit.js +2 -1
  141. package/test/hls/hls_live_unit.js +121 -220
  142. package/test/hls/hls_parser_unit.js +515 -432
  143. package/test/hls/manifest_text_parser_unit.js +19 -0
  144. package/test/media/drm_engine_unit.js +86 -120
  145. package/test/media/media_source_engine_integration.js +26 -3
  146. package/test/media/media_source_engine_unit.js +7 -6
  147. package/test/media/playhead_unit.js +27 -191
  148. package/test/media/segment_index_unit.js +15 -25
  149. package/test/media/streaming_engine_integration.js +4 -39
  150. package/test/media/streaming_engine_unit.js +3 -2
  151. package/test/media/time_ranges_utils_unit.js +0 -5
  152. package/test/offline/indexeddb_storage_unit.js +1 -1
  153. package/test/offline/manifest_convert_unit.js +34 -4
  154. package/test/offline/offline_manifest_parser_unit.js +1 -0
  155. package/test/offline/storage_compatibility_unit.js +1 -1
  156. package/test/offline/storage_integration.js +5 -4
  157. package/test/player_external.js +7 -7
  158. package/test/player_integration.js +22 -10
  159. package/test/player_src_equals_integration.js +81 -83
  160. package/test/player_unit.js +124 -1
  161. package/test/test/boot.js +9 -0
  162. package/test/test/externs/filters.js +4 -0
  163. package/test/test/util/fake_media_source_engine.js +11 -4
  164. package/test/test/util/manifest_generator.js +3 -1
  165. package/test/test/util/manifest_parser_util.js +4 -1
  166. package/test/test/util/offline_utils.js +1 -0
  167. package/test/test/util/simple_fakes.js +31 -2
  168. package/test/test/util/streaming_engine_util.js +1 -0
  169. package/test/test/util/test_scheme.js +24 -1
  170. package/test/test/util/util.js +4 -4
  171. package/test/text/cue_integration.js +2 -2
  172. package/test/text/lrc_text_parser_unit.js +6 -7
  173. package/test/text/mp4_ttml_parser_unit.js +6 -4
  174. package/test/text/mp4_vtt_parser_unit.js +6 -5
  175. package/test/text/sbv_text_parser_unit.js +5 -6
  176. package/test/text/srt_text_parser_unit.js +5 -6
  177. package/test/text/ssa_text_parser_unit.js +17 -29
  178. package/test/text/text_engine_unit.js +45 -5
  179. package/test/text/ttml_text_parser_unit.js +77 -77
  180. package/test/text/vtt_text_parser_unit.js +116 -59
  181. package/test/ui/ui_integration.js +0 -16
  182. package/test/ui/ui_unit.js +27 -0
  183. package/test/util/cmcd_manager_unit.js +3 -0
  184. package/test/util/mime_utils_unit.js +54 -0
  185. package/test/util/periods_unit.js +79 -0
  186. package/test/util/stream_utils_unit.js +23 -7
  187. package/ui/controls.js +65 -40
  188. package/ui/fullscreen_button.js +26 -6
  189. package/ui/less/containers.less +3 -3
  190. package/ui/locales/en.json +1 -0
  191. package/ui/locales/source.json +5 -0
  192. package/ui/resolution_selection.js +31 -33
  193. package/ui/ui.js +0 -17
  194. package/docs/tutorials/gsoc-ideas-list.md +0 -3
  195. package/docs/tutorials/upgrade-v2-5.md +0 -441
  196. package/docs/tutorials/upgrade-v3.md +0 -38
  197. package/lib/polyfill/mathround.js +0 -49
  198. package/lib/polyfill/patchedmediakeys_apple.js +0 -744
  199. package/lib/polyfill/patchedmediakeys_ms.js +0 -698
  200. package/lib/util/mutex.js +0 -52
  201. package/test/util/functional_unit.js +0 -82
@@ -116,13 +116,21 @@ describe('Player', () => {
116
116
  jasmine.createSpy('destroy').and.returnValue(Promise.resolve()),
117
117
  setUseEmbeddedText: jasmine.createSpy('setUseEmbeddedText'),
118
118
  getUseEmbeddedText: jasmine.createSpy('getUseEmbeddedText'),
119
+ setSegmentRelativeVttTiming:
120
+ jasmine.createSpy('setSegmentRelativeVttTiming'),
119
121
  getTextDisplayer: () => textDisplayer,
120
122
  ended: jasmine.createSpy('ended').and.returnValue(false),
121
123
  };
122
124
 
123
125
  player.createDrmEngine = () => drmEngine;
124
126
  player.createNetworkingEngine = () => networkingEngine;
125
- player.createPlayhead = () => playhead;
127
+ player.createPlayhead = (startTime) => {
128
+ const callableSetStartTime =
129
+ shaka.test.Util.spyFunc(playhead.setStartTime);
130
+ callableSetStartTime(startTime);
131
+ playhead.setStartTime.calls.reset();
132
+ return playhead;
133
+ };
126
134
  player.createMediaSourceEngine = () => mediaSourceEngine;
127
135
  player.createStreamingEngine = () => streamingEngine;
128
136
  }
@@ -154,6 +162,7 @@ describe('Player', () => {
154
162
  window.MediaSource.isTypeSupported = originalIsTypeSupported;
155
163
  shaka.media.ManifestParser.unregisterParserByMime(fakeMimeType);
156
164
  navigator.mediaCapabilities.decodingInfo = originalDecodingInfo;
165
+ onError.calls.reset();
157
166
  }
158
167
  });
159
168
 
@@ -1130,6 +1139,8 @@ describe('Player', () => {
1130
1139
  pixelAspectRatio: '59:54',
1131
1140
  hdr: null,
1132
1141
  mimeType: 'video/mp4',
1142
+ audioMimeType: 'audio/mp4',
1143
+ videoMimeType: 'video/mp4',
1133
1144
  codecs: 'avc1.4d401f, mp4a.40.2',
1134
1145
  audioCodec: 'mp4a.40.2',
1135
1146
  videoCodec: 'avc1.4d401f',
@@ -1164,6 +1175,8 @@ describe('Player', () => {
1164
1175
  pixelAspectRatio: '59:54',
1165
1176
  hdr: null,
1166
1177
  mimeType: 'video/mp4',
1178
+ audioMimeType: 'audio/mp4',
1179
+ videoMimeType: 'video/mp4',
1167
1180
  codecs: 'avc1.4d401f, mp4a.40.2',
1168
1181
  audioCodec: 'mp4a.40.2',
1169
1182
  videoCodec: 'avc1.4d401f',
@@ -1198,6 +1211,8 @@ describe('Player', () => {
1198
1211
  pixelAspectRatio: '59:54',
1199
1212
  hdr: null,
1200
1213
  mimeType: 'video/mp4',
1214
+ audioMimeType: 'audio/mp4',
1215
+ videoMimeType: 'video/mp4',
1201
1216
  codecs: 'avc1.4d401f, mp4a.40.2',
1202
1217
  audioCodec: 'mp4a.40.2',
1203
1218
  videoCodec: 'avc1.4d401f',
@@ -1232,6 +1247,8 @@ describe('Player', () => {
1232
1247
  pixelAspectRatio: '59:54',
1233
1248
  hdr: null,
1234
1249
  mimeType: 'video/mp4',
1250
+ audioMimeType: 'audio/mp4',
1251
+ videoMimeType: 'video/mp4',
1235
1252
  codecs: 'avc1.4d401f, mp4a.40.2',
1236
1253
  audioCodec: 'mp4a.40.2',
1237
1254
  videoCodec: 'avc1.4d401f',
@@ -1266,6 +1283,8 @@ describe('Player', () => {
1266
1283
  pixelAspectRatio: '59:54',
1267
1284
  hdr: null,
1268
1285
  mimeType: 'video/mp4',
1286
+ audioMimeType: 'audio/mp4',
1287
+ videoMimeType: 'video/mp4',
1269
1288
  codecs: 'avc1.4d401f, mp4a.40.2',
1270
1289
  audioCodec: 'mp4a.40.2',
1271
1290
  videoCodec: 'avc1.4d401f',
@@ -1300,6 +1319,8 @@ describe('Player', () => {
1300
1319
  pixelAspectRatio: '59:54',
1301
1320
  hdr: null,
1302
1321
  mimeType: 'video/mp4',
1322
+ audioMimeType: 'audio/mp4',
1323
+ videoMimeType: 'video/mp4',
1303
1324
  codecs: 'avc1.4d401f, mp4a.40.2',
1304
1325
  audioCodec: 'mp4a.40.2',
1305
1326
  videoCodec: 'avc1.4d401f',
@@ -1334,6 +1355,8 @@ describe('Player', () => {
1334
1355
  pixelAspectRatio: '59:54',
1335
1356
  hdr: null,
1336
1357
  mimeType: 'video/mp4',
1358
+ audioMimeType: 'audio/mp4',
1359
+ videoMimeType: 'video/mp4',
1337
1360
  codecs: 'avc1.4d401f, mp4a.40.2',
1338
1361
  audioCodec: 'mp4a.40.2',
1339
1362
  videoCodec: 'avc1.4d401f',
@@ -1368,6 +1391,8 @@ describe('Player', () => {
1368
1391
  pixelAspectRatio: '59:54',
1369
1392
  hdr: null,
1370
1393
  mimeType: 'video/mp4',
1394
+ audioMimeType: 'audio/mp4',
1395
+ videoMimeType: 'video/mp4',
1371
1396
  codecs: 'avc1.4d401f, mp4a.40.2',
1372
1397
  audioCodec: 'mp4a.40.2',
1373
1398
  videoCodec: 'avc1.4d401f',
@@ -1399,6 +1424,8 @@ describe('Player', () => {
1399
1424
  label: 'Spanish',
1400
1425
  kind: 'caption',
1401
1426
  mimeType: 'text/vtt',
1427
+ audioMimeType: null,
1428
+ videoMimeType: null,
1402
1429
  codecs: null,
1403
1430
  audioCodec: null,
1404
1431
  videoCodec: null,
@@ -1433,6 +1460,8 @@ describe('Player', () => {
1433
1460
  label: 'English',
1434
1461
  kind: 'caption',
1435
1462
  mimeType: 'application/ttml+xml',
1463
+ audioMimeType: null,
1464
+ videoMimeType: null,
1436
1465
  codecs: null,
1437
1466
  audioCodec: null,
1438
1467
  videoCodec: null,
@@ -1467,6 +1496,8 @@ describe('Player', () => {
1467
1496
  label: 'English',
1468
1497
  kind: 'caption',
1469
1498
  mimeType: 'application/ttml+xml',
1499
+ audioMimeType: null,
1500
+ videoMimeType: null,
1470
1501
  codecs: null,
1471
1502
  audioCodec: null,
1472
1503
  videoCodec: null,
@@ -1504,6 +1535,8 @@ describe('Player', () => {
1504
1535
  label: null,
1505
1536
  kind: null,
1506
1537
  mimeType: 'image/jpeg',
1538
+ audioMimeType: null,
1539
+ videoMimeType: null,
1507
1540
  codecs: null,
1508
1541
  audioCodec: null,
1509
1542
  videoCodec: null,
@@ -2632,6 +2665,51 @@ describe('Player', () => {
2632
2665
  expect(activeVariant.id).toBe(1);
2633
2666
  });
2634
2667
 
2668
+ // Regression test for https://github.com/shaka-project/shaka-player/issues/4190
2669
+ it('throws only one RESTRICTIONS_CANNOT_BE_MET error', async () => {
2670
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2671
+ manifest.addVariant(0, (variant) => {
2672
+ variant.addVideo(1, (stream) => {
2673
+ stream.keyIds = new Set(['abc']);
2674
+ });
2675
+ });
2676
+ });
2677
+
2678
+ // Check that error is RESTRICTIONS_CANNOT_BE_MET
2679
+ onError.and.callFake((e) => {
2680
+ const error = e.detail;
2681
+ shaka.test.Util.expectToEqualError(
2682
+ error,
2683
+ new shaka.util.Error(
2684
+ shaka.util.Error.Severity.CRITICAL,
2685
+ shaka.util.Error.Category.MANIFEST,
2686
+ shaka.util.Error.Code.RESTRICTIONS_CANNOT_BE_MET, {
2687
+ hasAppRestrictions: false,
2688
+ missingKeys: ['abc'],
2689
+ restrictedKeyStatuses: [],
2690
+ }));
2691
+ });
2692
+
2693
+ await player.load(fakeManifestUri, 0, fakeMimeType);
2694
+ const activeVariant = getActiveVariantTrack();
2695
+ expect(activeVariant.id).toBe(0);
2696
+
2697
+ abrManager.chooseIndex = 0;
2698
+ abrManager.chooseVariant.calls.reset();
2699
+
2700
+ onKeyStatus({'abc': 'output-restricted'});
2701
+
2702
+ // Ensure that RESTRICTIONS_CANNOT_BE_MET is thrown once
2703
+ expect(onError).toHaveBeenCalledTimes(1);
2704
+
2705
+ // It does not call chooseVariant
2706
+ expect(abrManager.chooseVariant).not.toHaveBeenCalled();
2707
+
2708
+ // The first variant is disallowed.
2709
+ expect(manifest.variants[0].id).toBe(0);
2710
+ expect(manifest.variants[0].allowedByKeySystem).toBe(false);
2711
+ });
2712
+
2635
2713
  it('doesn\'t switch if the active stream isn\'t restricted', async () => {
2636
2714
  manifest = shaka.test.ManifestGenerator.generate((manifest) => {
2637
2715
  manifest.addVariant(0, (variant) => {
@@ -3638,6 +3716,51 @@ describe('Player', () => {
3638
3716
  });
3639
3717
  });
3640
3718
 
3719
+ describe('config streaming.startAtSegmentBoundary', () => {
3720
+ // Test for https://github.com/shaka-project/shaka-player/issues/4188
3721
+ // In that issue, using streaming.startAtSegmentBoundary in v4.0.0 caused
3722
+ // an exception due to the use of a removed method.
3723
+ it('adjusts start time', async () => {
3724
+ player.configure('streaming.startAtSegmentBoundary', true);
3725
+
3726
+ // In order to adjust the start time to a segment boundary, we need
3727
+ // segment descriptions in the segment index. So create a non-default
3728
+ // fake manifest.
3729
+ const timeline = new shaka.media.PresentationTimeline(300, 0);
3730
+ timeline.setStatic(true);
3731
+ // This duration is used by useSegmentTemplate below to decide how many
3732
+ // references to generate.
3733
+ timeline.setDuration(300);
3734
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
3735
+ manifest.presentationTimeline = timeline;
3736
+ manifest.addVariant(0, (variant) => {
3737
+ variant.addVideo(1, (stream) => {
3738
+ stream.useSegmentTemplate(
3739
+ '$Number$.mp4', /* segmentDuration= */ 10);
3740
+ });
3741
+ });
3742
+ });
3743
+
3744
+ await player.load(fakeManifestUri, 12, fakeMimeType);
3745
+
3746
+ expect(playhead.setStartTime).toHaveBeenCalledWith(10);
3747
+ });
3748
+
3749
+ it('does not fail with no segments', async () => {
3750
+ player.configure('streaming.startAtSegmentBoundary', true);
3751
+
3752
+ // Without useSegmentTemplate in the fake manifest, the call to
3753
+ // getIteratorForTime() in Player produces a null iterator. Using the
3754
+ // default fake manifest should cover that case. But just to make sure,
3755
+ // verify that we have no segments before calling load().
3756
+ const variant = manifest.variants[0];
3757
+ expect(variant.video.segmentIndex.getIteratorForTime(0)).toBeNull();
3758
+ expect(variant.audio.segmentIndex.getIteratorForTime(0)).toBeNull();
3759
+
3760
+ await player.load(fakeManifestUri, 0, fakeMimeType);
3761
+ });
3762
+ });
3763
+
3641
3764
  /**
3642
3765
  * Gets the currently active variant track.
3643
3766
  * @return {shaka.extern.Track}
package/test/test/boot.js CHANGED
@@ -242,6 +242,15 @@ window.xfilterDescribe = (describeName, cond, describeBody) => {
242
242
  window['describe'] = oldDescribe;
243
243
  };
244
244
 
245
+ /**
246
+ * A very short alias for filtering offline integration tests.
247
+ *
248
+ * @return {boolean}
249
+ */
250
+ window.offlineSupported = () => {
251
+ return shaka.offline.StorageMuxer.support();
252
+ };
253
+
245
254
  /**
246
255
  * Load node modules used in testing and install them into window.
247
256
  * @return {!Promise}
@@ -38,3 +38,7 @@ var filterDescribe = function(name, cond, callback) {};
38
38
  * @param {function()} callback
39
39
  */
40
40
  var xfilterDescribe = function(name, cond, callback) {};
41
+
42
+
43
+ /** @return {boolean} */
44
+ var offlineSupported = function() {};
@@ -107,8 +107,8 @@ shaka.test.FakeMediaSourceEngine = class {
107
107
 
108
108
  /** @type {!jasmine.Spy} */
109
109
  this.setStreamProperties = jasmine.createSpy('setStreamProperties')
110
- .and.callFake((type, offset, end) =>
111
- this.setStreamPropertiesImpl_(type, offset, end));
110
+ .and.callFake((type, offset, end, sequenceMode) =>
111
+ this.setStreamPropertiesImpl_(type, offset, end, sequenceMode));
112
112
 
113
113
  /** @type {!jasmine.Spy} */
114
114
  this.remove = jasmine.createSpy('remove')
@@ -125,6 +125,10 @@ shaka.test.FakeMediaSourceEngine = class {
125
125
  this.getTextDisplayer =
126
126
  jasmine.createSpy('getTextDisplayer')
127
127
  .and.returnValue(new shaka.test.FakeTextDisplayer());
128
+
129
+ /** @type {!jasmine.Spy} */
130
+ this.setSegmentRelativeVttTiming =
131
+ jasmine.createSpy('setSegmentRelativeVttTiming').and.stub();
128
132
  }
129
133
 
130
134
  /** @override */
@@ -355,14 +359,17 @@ shaka.test.FakeMediaSourceEngine = class {
355
359
  * @param {string} type
356
360
  * @param {number} offset
357
361
  * @param {number} appendWindowEnd
362
+ * @param {boolean} sequenceMode
358
363
  * @return {!Promise}
359
364
  * @private
360
365
  */
361
- setStreamPropertiesImpl_(type, offset, appendWindowEnd) {
366
+ setStreamPropertiesImpl_(type, offset, appendWindowEnd, sequenceMode) {
362
367
  if (!this.segments[type]) {
363
368
  throw new Error('unexpected type');
364
369
  }
365
- this.timestampOffsets_[type] = offset;
370
+ if (!sequenceMode) {
371
+ this.timestampOffsets_[type] = offset;
372
+ }
366
373
  // Don't use |appendWindowEnd|.
367
374
  return Promise.resolve();
368
375
  }
@@ -95,6 +95,8 @@ shaka.test.ManifestGenerator.Manifest = class {
95
95
  this.offlineSessionIds = [];
96
96
  /** @type {number} */
97
97
  this.minBufferTime = 0;
98
+ /** @type {boolean} */
99
+ this.sequenceMode = false;
98
100
 
99
101
  /** @type {shaka.extern.Manifest} */
100
102
  const foo = this;
@@ -421,7 +423,7 @@ shaka.test.ManifestGenerator.DrmInfo = class {
421
423
  if (!this.initData) {
422
424
  this.initData = [];
423
425
  }
424
- this.initData.push({initData: buffer, initDataType: type, keyId: null});
426
+ this.initData.push({initData: buffer, initDataType: type});
425
427
  }
426
428
 
427
429
  /**
@@ -51,11 +51,12 @@ shaka.test.ManifestParser = class {
51
51
  * @param {number=} timestampOffset
52
52
  * @param {!Array.<!shaka.media.SegmentReference>=} partialReferences
53
53
  * @param {?string=} tilesLayout
54
+ * @param {?number=} syncTime
54
55
  * @return {!shaka.media.SegmentReference}
55
56
  */
56
57
  static makeReference(uri, start, end, baseUri = '',
57
58
  startByte = 0, endByte = null, timestampOffset = 0,
58
- partialReferences = [], tilesLayout = '') {
59
+ partialReferences = [], tilesLayout = '', syncTime = null) {
59
60
  const getUris = () => uri.length ? [baseUri + uri] : [];
60
61
 
61
62
  // If a test wants to verify these, they can be set explicitly after
@@ -80,6 +81,8 @@ shaka.test.ManifestParser = class {
80
81
  appendWindowEnd,
81
82
  partialReferences,
82
83
  tilesLayout,
84
+ /* tileDuration= */ undefined,
85
+ syncTime,
83
86
  );
84
87
  }
85
88
  };
@@ -20,6 +20,7 @@ shaka.test.OfflineUtils = class {
20
20
  streams: [],
21
21
  sessionIds: [],
22
22
  size: 1024,
23
+ sequenceMode: false,
23
24
  };
24
25
  }
25
26
 
@@ -152,9 +152,27 @@ shaka.test.FakeVideo = class {
152
152
  constructor(currentTime) {
153
153
  /** @const {!Object.<string, !Function>} */
154
154
  this.on = {}; // event listeners
155
+
155
156
  /** @type {!Array.<!TextTrack>} */
156
157
  this.textTracks = [];
157
158
 
159
+ // In a real video element, textTracks is an event target.
160
+ // Since Player listens to events on textTracks, we need to fake that
161
+ // interface.
162
+ this.textTracksEventTarget = new shaka.util.FakeEventTarget();
163
+ this.textTracks.addEventListener =
164
+ // eslint-disable-next-line no-restricted-syntax
165
+ this.textTracksEventTarget.addEventListener.bind(
166
+ this.textTracksEventTarget);
167
+ this.textTracks.removeEventListener =
168
+ // eslint-disable-next-line no-restricted-syntax
169
+ this.textTracksEventTarget.removeEventListener.bind(
170
+ this.textTracksEventTarget);
171
+ this.textTracks.dispatchEvent =
172
+ // eslint-disable-next-line no-restricted-syntax
173
+ this.textTracksEventTarget.dispatchEvent.bind(
174
+ this.textTracksEventTarget);
175
+
158
176
  this.currentTime = currentTime || 0;
159
177
  this.readyState = 0;
160
178
  this.playbackRate = 1;
@@ -173,6 +191,10 @@ shaka.test.FakeVideo = class {
173
191
  jasmine.createSpy('addTextTrack').and.callFake((kind, id) => {
174
192
  const track = new shaka.test.FakeTextTrack();
175
193
  this.textTracks.push(track);
194
+
195
+ const trackEvent = new shaka.util.FakeEvent('addtrack', {track});
196
+ this.textTracksEventTarget.dispatchEvent(trackEvent);
197
+
176
198
  return track;
177
199
  });
178
200
 
@@ -308,11 +330,18 @@ shaka.test.FakePlayhead = class {
308
330
  /** @type {!jasmine.Spy} */
309
331
  this.setRebufferingGoal = jasmine.createSpy('setRebufferingGoal');
310
332
 
333
+ /** @private {number} */
334
+ this.startTime_ = 0;
335
+
311
336
  /** @type {!jasmine.Spy} */
312
- this.setStartTime = jasmine.createSpy('setStartTime');
337
+ this.setStartTime = jasmine.createSpy('setStartTime')
338
+ .and.callFake((value) => {
339
+ this.startTime_ = value;
340
+ });
313
341
 
314
342
  /** @type {!jasmine.Spy} */
315
- this.getTime = jasmine.createSpy('getTime').and.returnValue(0);
343
+ this.getTime = jasmine.createSpy('getTime')
344
+ .and.callFake(() => this.startTime_);
316
345
 
317
346
  /** @type {!jasmine.Spy} */
318
347
  this.setBuffering = jasmine.createSpy('setBuffering');
@@ -275,6 +275,7 @@ shaka.test.StreamingEngineUtil = class {
275
275
  variants: [],
276
276
  textStreams: [],
277
277
  imageStreams: [],
278
+ sequenceMode: false,
278
279
  };
279
280
 
280
281
  /** @type {shaka.extern.Variant} */
@@ -51,7 +51,8 @@ let ExtraMetadataType;
51
51
  * textLanguages: (!Array.<string>|undefined),
52
52
  * duration: number,
53
53
  * licenseServers: (!Object.<string, string>|undefined),
54
- * licenseRequestHeaders: (!Object.<string, string>|undefined)
54
+ * licenseRequestHeaders: (!Object.<string, string>|undefined),
55
+ * sequenceMode: boolean
55
56
  * }}
56
57
  */
57
58
  let MetadataType;
@@ -278,6 +279,7 @@ shaka.test.TestScheme = class {
278
279
 
279
280
  const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
280
281
  manifest.presentationTimeline.setDuration(data.duration);
282
+ manifest.sequenceMode = data.sequenceMode;
281
283
 
282
284
  const videoResolutions = data.videoResolutions || [undefined];
283
285
  const audioLanguages = data.audioLanguages ||
@@ -511,6 +513,16 @@ shaka.test.TestScheme.DATA = {
511
513
  audio: sintelAudioSegment,
512
514
  text: vttSegment,
513
515
  duration: 30,
516
+ sequenceMode: false,
517
+ },
518
+
519
+ // Like 'sintel', but flagged as sequence mode.
520
+ 'sintel_sequence': {
521
+ video: sintelVideoSegment,
522
+ audio: sintelAudioSegment,
523
+ text: vttSegment,
524
+ duration: 30,
525
+ sequenceMode: true,
514
526
  },
515
527
 
516
528
  // Like 'sintel', but much longer to test buffering and seeking.
@@ -518,6 +530,7 @@ shaka.test.TestScheme.DATA = {
518
530
  video: sintelVideoSegment,
519
531
  audio: sintelAudioSegment,
520
532
  duration: 300,
533
+ sequenceMode: false,
521
534
  },
522
535
 
523
536
  // Like 'sintel' above, but with languages and delayed setup.
@@ -534,6 +547,7 @@ shaka.test.TestScheme.DATA = {
534
547
  language: 'fa', // Necessary to repro #1696
535
548
  }),
536
549
  duration: 30,
550
+ sequenceMode: false,
537
551
  },
538
552
 
539
553
  'sintel_multi_lingual_multi_res': {
@@ -547,17 +561,20 @@ shaka.test.TestScheme.DATA = {
547
561
  audioLanguages: ['en', 'es'],
548
562
  textLanguages: ['zh', 'fr'],
549
563
  duration: 30,
564
+ sequenceMode: false,
550
565
  },
551
566
 
552
567
  'sintel_audio_only': {
553
568
  audio: sintelAudioSegment,
554
569
  duration: 30,
570
+ sequenceMode: false,
555
571
  },
556
572
 
557
573
  'sintel_no_text': {
558
574
  video: sintelVideoSegment,
559
575
  audio: sintelAudioSegment,
560
576
  duration: 30,
577
+ sequenceMode: false,
561
578
  },
562
579
 
563
580
  // https://github.com/shaka-project/shaka-player/issues/2553
@@ -566,6 +583,7 @@ shaka.test.TestScheme.DATA = {
566
583
  text: vttSegment,
567
584
  textLanguages: ['de', 'de'], // one of these is the "forced subs" track
568
585
  duration: 30,
586
+ sequenceMode: false,
569
587
  },
570
588
 
571
589
  'sintel-enc': {
@@ -574,6 +592,7 @@ shaka.test.TestScheme.DATA = {
574
592
  text: vttSegment,
575
593
  licenseServers: widevineDrmServers,
576
594
  duration: 30,
595
+ sequenceMode: false,
577
596
  },
578
597
 
579
598
  'multidrm': {
@@ -583,6 +602,7 @@ shaka.test.TestScheme.DATA = {
583
602
  licenseServers: axinomDrmServers,
584
603
  licenseRequestHeaders: axinomDrmHeaders,
585
604
  duration: 30,
605
+ sequenceMode: false,
586
606
  },
587
607
 
588
608
  'multidrm_no_init_data': {
@@ -595,6 +615,7 @@ shaka.test.TestScheme.DATA = {
595
615
  licenseServers: axinomDrmServers,
596
616
  licenseRequestHeaders: axinomDrmHeaders,
597
617
  duration: 30,
618
+ sequenceMode: false,
598
619
  },
599
620
 
600
621
  'cea-708_ts': {
@@ -608,6 +629,7 @@ shaka.test.TestScheme.DATA = {
608
629
  mimeType: 'application/cea-608',
609
630
  },
610
631
  duration: 30,
632
+ sequenceMode: false,
611
633
  },
612
634
 
613
635
  'cea-708_mp4': {
@@ -622,6 +644,7 @@ shaka.test.TestScheme.DATA = {
622
644
  closedCaptions: new Map([['CC1', 'en']]),
623
645
  },
624
646
  duration: 30,
647
+ sequenceMode: false,
625
648
  },
626
649
  };
627
650
 
@@ -453,13 +453,13 @@ shaka.test.Util = class {
453
453
  */
454
454
  shaka.test.Util.customMatchers_ = {
455
455
  // Custom matcher for Element objects.
456
- toEqualElement: (util, customEqualityTesters) => {
456
+ toEqualElement: (util) => {
457
457
  return {
458
458
  compare: shaka.test.Util.expectToEqualElementCompare_,
459
459
  };
460
460
  },
461
461
  // Custom matcher for working with spies.
462
- toHaveBeenCalledOnceMore: (util, customEqualityTesters) => {
462
+ toHaveBeenCalledOnceMore: (util) => {
463
463
  return {
464
464
  compare: (actual, expected) => {
465
465
  const callCount = actual.calls.count();
@@ -479,7 +479,7 @@ shaka.test.Util.customMatchers_ = {
479
479
  },
480
480
  };
481
481
  },
482
- toHaveBeenCalledOnceMoreWith: (util, customEqualityTesters) => {
482
+ toHaveBeenCalledOnceMoreWith: (util) => {
483
483
  return {
484
484
  compare: (actual, expected) => {
485
485
  const callCount = actual.calls.count();
@@ -492,7 +492,7 @@ shaka.test.Util.customMatchers_ = {
492
492
  if (callCount != 1) {
493
493
  result.pass = false;
494
494
  result.message = 'Expected to be called once, not ' + callCount;
495
- } else if (!util.equals(callArgs, expected, customEqualityTesters)) {
495
+ } else if (!util.equals(callArgs, expected)) {
496
496
  result.pass = false;
497
497
  result.message =
498
498
  'Expected to be called with ' + expected + ' not ' + callArgs;
@@ -19,7 +19,7 @@ describe('Cue', () => {
19
19
  'WEBVTT\n\n' +
20
20
  '00:00:20.000 --> 00:00:40.000\n' +
21
21
  'Test',
22
- {periodStart: 7, segmentStart: 10, segmentEnd: 60});
22
+ {periodStart: 7, segmentStart: 10, segmentEnd: 60, vttOffset: 7});
23
23
  expect(cues.length).toBe(1);
24
24
  expect(cues[0].startTime).toBe(27);
25
25
  expect(cues[0].endTime).toBe(47);
@@ -34,7 +34,7 @@ describe('Cue', () => {
34
34
  'ID1\n' +
35
35
  '00:00:20.000 --> 00:00:40.000 align:middle size:56% vertical:lr\n' +
36
36
  'Test',
37
- {periodStart: 0, segmentStart: 0, segmentEnd: 0});
37
+ {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
38
38
  expect(cues.length).toBe(1);
39
39
  });
40
40
 
@@ -8,7 +8,7 @@ describe('LrcTextParser', () => {
8
8
  it('supports no cues', () => {
9
9
  verifyHelper([],
10
10
  '',
11
- {periodStart: 0, segmentStart: 0, segmentEnd: 0});
11
+ {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
12
12
  });
13
13
 
14
14
  it('handles a blank line at the start of the file', () => {
@@ -18,7 +18,7 @@ describe('LrcTextParser', () => {
18
18
  ],
19
19
  '\n\n' +
20
20
  '[00:00.00]Test',
21
- {periodStart: 0, segmentStart: 0, segmentEnd: 0});
21
+ {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
22
22
  });
23
23
 
24
24
  it('handles a blank line at the end of the file', () => {
@@ -28,7 +28,7 @@ describe('LrcTextParser', () => {
28
28
  ],
29
29
  '[00:00.00]Test' +
30
30
  '\n\n',
31
- {periodStart: 0, segmentStart: 0, segmentEnd: 0});
31
+ {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
32
32
  });
33
33
 
34
34
  it('handles no blank line at the end of the file', () => {
@@ -37,8 +37,7 @@ describe('LrcTextParser', () => {
37
37
  {startTime: 0, endTime: 2, payload: 'Test'},
38
38
  ],
39
39
  '[00:00.00]Test',
40
- {periodStart: 0, segmentStart: 0, segmentEnd: 0,
41
- });
40
+ {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
42
41
  });
43
42
 
44
43
  it('supports multiple cues', () => {
@@ -51,7 +50,7 @@ describe('LrcTextParser', () => {
51
50
  '[00:00.00]Test\n' +
52
51
  '[00:10.00]Test2\n' +
53
52
  '[00:20.00]Test3',
54
- {periodStart: 0, segmentStart: 0, segmentEnd: 0});
53
+ {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
55
54
  });
56
55
 
57
56
  it('supports different time formats', () => {
@@ -70,7 +69,7 @@ describe('LrcTextParser', () => {
70
69
  '[00:30,1]Test4\n' +
71
70
  '[00:40,001]Test5\n' +
72
71
  '[00:50,02]Test6',
73
- {periodStart: 0, segmentStart: 0, segmentEnd: 0});
72
+ {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
74
73
  });
75
74
 
76
75
  /**
@@ -41,7 +41,7 @@ describe('Mp4TtmlParser', () => {
41
41
  it('handles media segments with multiple mdats', () => {
42
42
  const parser = new shaka.text.Mp4TtmlParser();
43
43
  parser.parseInit(ttmlInitSegment);
44
- const time = {periodStart: 0, segmentStart: 0, segmentEnd: 0};
44
+ const time = {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0};
45
45
  const ret = parser.parseMedia(ttmlSegmentMultipleMDAT, time);
46
46
  // Bodies.
47
47
  expect(ret.length).toBe(2);
@@ -54,8 +54,10 @@ describe('Mp4TtmlParser', () => {
54
54
  });
55
55
 
56
56
  it('accounts for offset', () => {
57
- const time1 = {periodStart: 0, segmentStart: 0, segmentEnd: 0};
58
- const time2 = {periodStart: 7, segmentStart: 0, segmentEnd: 0};
57
+ const time1 =
58
+ {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0};
59
+ const time2 =
60
+ {periodStart: 7, segmentStart: 0, segmentEnd: 0, vttOffset: 7};
59
61
 
60
62
  const parser = new shaka.text.Mp4TtmlParser();
61
63
  parser.parseInit(ttmlInitSegment);
@@ -159,7 +161,7 @@ describe('Mp4TtmlParser', () => {
159
161
  ];
160
162
  const parser = new shaka.text.Mp4TtmlParser();
161
163
  parser.parseInit(ttmlInitSegment);
162
- const time = {periodStart: 0, segmentStart: 0, segmentEnd: 0};
164
+ const time = {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0};
163
165
  const result = parser.parseMedia(ttmlSegment, time);
164
166
  shaka.test.TtmlUtils.verifyHelper(
165
167
  cues, result, {startTime: 23, endTime: 53.5});