shaka-player 3.3.5 → 4.0.2

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 (184) hide show
  1. package/.github/config.yml +1 -0
  2. package/.github/workflows/demo-version-index.yaml +8 -0
  3. package/.github/workflows/release-please.yaml +18 -2
  4. package/.github/workflows/sync-labels.yaml +33 -0
  5. package/.github/workflows/update-issues.yaml +29 -0
  6. package/.github/workflows/validate-pr-title.yaml +35 -0
  7. package/AUTHORS +1 -0
  8. package/CHANGELOG.md +215 -41
  9. package/CONTRIBUTORS +1 -0
  10. package/README.md +14 -11
  11. package/app-engine/demo-version-index/README.md +3 -3
  12. package/app-engine/demo-version-index/app.yaml +27 -1
  13. package/app-engine/demo-version-index/generate.py +164 -0
  14. package/app-engine/demo-version-index/main.py +4 -155
  15. package/app-engine/demo-version-index/requirements.txt +0 -1
  16. package/build/checkversion.py +1 -1
  17. package/build/compiler.py +1 -1
  18. package/build/misspellings.txt +1 -0
  19. package/build/shaka-lab.yaml +0 -2
  20. package/build/types/polyfill +0 -3
  21. package/demo/common/asset.js +17 -1
  22. package/demo/common/assets.js +29 -0
  23. package/demo/common/message_ids.js +6 -3
  24. package/demo/config.js +10 -11
  25. package/demo/custom.js +39 -0
  26. package/demo/demo.less +0 -1
  27. package/demo/demo_utils.js +0 -1
  28. package/demo/locales/en.json +6 -3
  29. package/demo/locales/source.json +22 -10
  30. package/demo/main.js +9 -6
  31. package/demo/search.js +2 -1
  32. package/dist/controls.css +3 -3
  33. package/dist/controls.css.map +1 -1
  34. package/dist/demo.compiled.debug.js +71 -64
  35. package/dist/demo.compiled.debug.map +3 -3
  36. package/dist/demo.compiled.js +71 -64
  37. package/dist/demo.compiled.map +3 -3
  38. package/dist/demo.css +1 -1
  39. package/dist/demo.css.map +1 -1
  40. package/dist/deps.js +17 -20
  41. package/dist/locales.js +33 -31
  42. package/dist/receiver.compiled.debug.js +32 -28
  43. package/dist/receiver.compiled.debug.map +3 -3
  44. package/dist/receiver.compiled.js +32 -28
  45. package/dist/receiver.compiled.map +3 -3
  46. package/dist/shaka-player.compiled.d.ts +311 -314
  47. package/dist/shaka-player.compiled.debug.d.ts +311 -314
  48. package/dist/shaka-player.compiled.debug.externs.js +126 -126
  49. package/dist/shaka-player.compiled.debug.js +430 -484
  50. package/dist/shaka-player.compiled.debug.map +4 -4
  51. package/dist/shaka-player.compiled.externs.js +126 -126
  52. package/dist/shaka-player.compiled.js +829 -845
  53. package/dist/shaka-player.compiled.map +4 -4
  54. package/dist/shaka-player.ui.d.ts +357 -358
  55. package/dist/shaka-player.ui.debug.d.ts +357 -358
  56. package/dist/shaka-player.ui.debug.externs.js +134 -126
  57. package/dist/shaka-player.ui.debug.js +489 -541
  58. package/dist/shaka-player.ui.debug.map +4 -4
  59. package/dist/shaka-player.ui.externs.js +134 -126
  60. package/dist/shaka-player.ui.js +988 -1000
  61. package/dist/shaka-player.ui.map +4 -4
  62. package/docs/tutorials/config.md +0 -2
  63. package/docs/tutorials/drm-config.md +5 -0
  64. package/docs/tutorials/fairplay.md +7 -22
  65. package/docs/tutorials/faq.md +0 -11
  66. package/docs/tutorials/index.json +2 -8
  67. package/docs/tutorials/plugins.md +1 -3
  68. package/docs/tutorials/upgrade.md +85 -11
  69. package/externs/polyfill.js +15 -0
  70. package/externs/shaka/manifest.js +5 -1
  71. package/externs/shaka/net.js +12 -0
  72. package/externs/shaka/offline.js +5 -1
  73. package/externs/shaka/player.js +39 -21
  74. package/externs/shaka/text.js +12 -12
  75. package/externs/sourcebuffer.js +15 -0
  76. package/lib/abr/simple_abr_manager.js +2 -1
  77. package/lib/ads/client_side_ad.js +13 -2
  78. package/lib/ads/client_side_ad_manager.js +22 -4
  79. package/lib/cast/cast_utils.js +0 -1
  80. package/lib/dash/content_protection.js +85 -5
  81. package/lib/dash/dash_parser.js +1 -0
  82. package/lib/hls/hls_parser.js +390 -747
  83. package/lib/hls/manifest_text_parser.js +2 -3
  84. package/lib/media/drm_engine.js +105 -37
  85. package/lib/media/gap_jumping_controller.js +10 -45
  86. package/lib/media/media_source_engine.js +150 -30
  87. package/lib/media/playhead.js +2 -5
  88. package/lib/media/presentation_timeline.js +1 -2
  89. package/lib/media/segment_index.js +13 -46
  90. package/lib/media/segment_reference.js +47 -1
  91. package/lib/media/streaming_engine.js +28 -11
  92. package/lib/media/time_ranges_utils.js +4 -9
  93. package/lib/net/networking_engine.js +3 -0
  94. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  95. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  96. package/lib/offline/manifest_converter.js +1 -0
  97. package/lib/offline/storage.js +8 -41
  98. package/lib/player.js +17 -201
  99. package/lib/polyfill/media_capabilities.js +12 -6
  100. package/lib/polyfill/mediasource.js +0 -28
  101. package/lib/polyfill/patchedmediakeys_nop.js +2 -0
  102. package/lib/polyfill/patchedmediakeys_webkit.js +2 -0
  103. package/lib/text/cue.js +0 -6
  104. package/lib/text/lrc_text_parser.js +8 -0
  105. package/lib/text/mp4_ttml_parser.js +8 -0
  106. package/lib/text/mp4_vtt_parser.js +8 -0
  107. package/lib/text/sbv_text_parser.js +8 -0
  108. package/lib/text/simple_text_displayer.js +1 -7
  109. package/lib/text/srt_text_parser.js +8 -0
  110. package/lib/text/ssa_text_parser.js +8 -0
  111. package/lib/text/text_engine.js +19 -3
  112. package/lib/text/ttml_text_parser.js +8 -0
  113. package/lib/text/ui_text_displayer.js +1 -7
  114. package/lib/text/vtt_text_parser.js +27 -5
  115. package/lib/text/web_vtt_generator.js +1 -7
  116. package/lib/util/error.js +9 -13
  117. package/lib/util/fairplay_utils.js +109 -0
  118. package/lib/util/functional.js +0 -42
  119. package/lib/util/mime_utils.js +16 -5
  120. package/lib/util/platform.js +45 -0
  121. package/lib/util/player_configuration.js +17 -6
  122. package/lib/util/pssh.js +23 -4
  123. package/lib/util/stream_utils.js +92 -22
  124. package/lib/util/uint8array_utils.js +0 -16
  125. package/lib/util/xml_utils.js +1 -1
  126. package/package.json +5 -2
  127. package/roadmap.md +19 -19
  128. package/shaka-player.uncompiled.js +0 -3
  129. package/test/dash/dash_parser_content_protection_unit.js +44 -0
  130. package/test/dash/dash_parser_segment_template_unit.js +3 -4
  131. package/test/demo/demo_unit.js +2 -1
  132. package/test/hls/hls_live_unit.js +155 -230
  133. package/test/hls/hls_parser_unit.js +515 -432
  134. package/test/media/drm_engine_unit.js +86 -120
  135. package/test/media/media_source_engine_integration.js +25 -3
  136. package/test/media/media_source_engine_unit.js +3 -2
  137. package/test/media/playhead_unit.js +27 -191
  138. package/test/media/segment_index_unit.js +15 -25
  139. package/test/media/streaming_engine_integration.js +2 -39
  140. package/test/media/streaming_engine_unit.js +3 -2
  141. package/test/media/time_ranges_utils_unit.js +0 -5
  142. package/test/offline/manifest_convert_unit.js +34 -4
  143. package/test/offline/offline_manifest_parser_unit.js +1 -0
  144. package/test/offline/storage_integration.js +5 -4
  145. package/test/player_external.js +0 -6
  146. package/test/player_integration.js +16 -0
  147. package/test/player_unit.js +26 -0
  148. package/test/test/util/fake_media_source_engine.js +11 -4
  149. package/test/test/util/manifest_generator.js +3 -1
  150. package/test/test/util/manifest_parser_util.js +4 -1
  151. package/test/test/util/offline_utils.js +1 -0
  152. package/test/test/util/streaming_engine_util.js +1 -0
  153. package/test/test/util/test_scheme.js +24 -1
  154. package/test/test/util/util.js +4 -4
  155. package/test/text/cue_integration.js +2 -2
  156. package/test/text/lrc_text_parser_unit.js +6 -7
  157. package/test/text/mp4_ttml_parser_unit.js +6 -4
  158. package/test/text/mp4_vtt_parser_unit.js +6 -5
  159. package/test/text/sbv_text_parser_unit.js +5 -6
  160. package/test/text/srt_text_parser_unit.js +5 -6
  161. package/test/text/ssa_text_parser_unit.js +17 -29
  162. package/test/text/text_engine_unit.js +45 -5
  163. package/test/text/ttml_text_parser_unit.js +77 -77
  164. package/test/text/vtt_text_parser_unit.js +116 -59
  165. package/test/ui/ui_integration.js +0 -16
  166. package/test/ui/ui_unit.js +27 -0
  167. package/test/util/cmcd_manager_unit.js +3 -0
  168. package/test/util/stream_utils_unit.js +23 -7
  169. package/ui/controls.js +65 -40
  170. package/ui/fullscreen_button.js +26 -6
  171. package/ui/less/containers.less +4 -4
  172. package/ui/less/general.less +1 -1
  173. package/ui/less/range_elements.less +1 -0
  174. package/ui/locales/en.json +1 -0
  175. package/ui/locales/source.json +5 -0
  176. package/ui/resolution_selection.js +31 -33
  177. package/ui/ui.js +0 -17
  178. package/.github/pull_request_template.md +0 -10
  179. package/docs/tutorials/upgrade-v2-5.md +0 -441
  180. package/docs/tutorials/upgrade-v3.md +0 -38
  181. package/lib/polyfill/mathround.js +0 -49
  182. package/lib/polyfill/patchedmediakeys_apple.js +0 -744
  183. package/lib/polyfill/patchedmediakeys_ms.js +0 -698
  184. package/test/util/functional_unit.js +0 -82
@@ -28,14 +28,6 @@ describe('HlsParser live', () => {
28
28
  let segmentData;
29
29
  /** @type {!Uint8Array} */
30
30
  let selfInitializingSegmentData;
31
- /** @type {!Uint8Array} */
32
- let tsSegmentData;
33
- /** @type {!Uint8Array} */
34
- let pastRolloverSegmentData;
35
- /** @type {number} */
36
- let rolloverOffset;
37
- /** @type {number} */
38
- let segmentDataStartTime;
39
31
 
40
32
  beforeEach(() => {
41
33
  // TODO: use StreamGenerator?
@@ -66,36 +58,6 @@ describe('HlsParser live', () => {
66
58
  0x00, 0x00, 0x00, 0x00, // baseMediaDecodeTime first 4 bytes
67
59
  0x00, 0x00, 0x07, 0xd0, // baseMediaDecodeTime last 4 bytes (2000)
68
60
  ]);
69
- tsSegmentData = new Uint8Array([
70
- 0x47, // TS sync byte (fixed value)
71
- 0x41, 0x01, // not corrupt, payload follows, packet ID 257
72
- 0x10, // not scrambled, no adaptation field, payload only, seq #0
73
- 0x00, 0x00, 0x01, // PES start code (fixed value)
74
- 0xe0, // stream ID (video stream 0)
75
- 0x00, 0x00, // PES packet length (doesn't matter)
76
- 0x80, // marker bits (fixed value), not scrambled, not priority
77
- 0x80, // PTS only, no DTS, other flags 0 (don't matter)
78
- 0x05, // remaining PES header length == 5 (one timestamp)
79
- 0x21, 0x00, 0x0b, 0x7e, 0x41, // PTS = 180000, encoded into 5 bytes
80
- ]);
81
- // 180000 divided by TS timescale (90000) = segment starts at 2s.
82
- segmentDataStartTime = 2;
83
-
84
- pastRolloverSegmentData = new Uint8Array([
85
- 0x00, 0x00, 0x00, 0x24, // size (36)
86
- 0x6D, 0x6F, 0x6F, 0x66, // type (moof)
87
- 0x00, 0x00, 0x00, 0x1C, // traf size (28)
88
- 0x74, 0x72, 0x61, 0x66, // type (traf)
89
- 0x00, 0x00, 0x00, 0x14, // tfdt size (20)
90
- 0x74, 0x66, 0x64, 0x74, // type (tfdt)
91
- 0x01, 0x00, 0x00, 0x00, // version and flags
92
- 0x00, 0x00, 0x00, 0x00, // baseMediaDecodeTime first 4 bytes
93
- 0x0b, 0x60, 0xbc, 0x28, // baseMediaDecodeTime last 4 bytes (190889000)
94
- ]);
95
-
96
- // The timestamp above would roll over twice, so this rollover offset should
97
- // be applied.
98
- rolloverOffset = (0x200000000 * 2) / 90000;
99
61
 
100
62
  selfInitializingSegmentData =
101
63
  shaka.util.Uint8ArrayUtils.concat(initSegmentData, segmentData);
@@ -221,8 +183,10 @@ describe('HlsParser live', () => {
221
183
 
222
184
  describe('update', () => {
223
185
  it('adds new segments when they appear', async () => {
224
- const ref1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
225
- const ref2 = ManifestParser.makeReference('test:/main2.mp4', 4, 6);
186
+ const ref1 = makeReference(
187
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
188
+ const ref2 = makeReference(
189
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
226
190
 
227
191
  await testUpdate(
228
192
  master, media, [ref1], mediaWithAdditionalSegment, [ref1, ref2]);
@@ -236,8 +200,10 @@ describe('HlsParser live', () => {
236
200
  ].join('');
237
201
 
238
202
  const masterWithTwoVariants = master + secondVariant;
239
- const ref1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
240
- const ref2 = ManifestParser.makeReference('test:/main2.mp4', 4, 6);
203
+ const ref1 = makeReference(
204
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
205
+ const ref2 = makeReference(
206
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
241
207
 
242
208
  await testUpdate(
243
209
  masterWithTwoVariants, media, [ref1], mediaWithAdditionalSegment,
@@ -257,8 +223,10 @@ describe('HlsParser live', () => {
257
223
  ].join('');
258
224
 
259
225
  const masterWithAudio = masterlist + audio;
260
- const ref1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
261
- const ref2 = ManifestParser.makeReference('test:/main2.mp4', 4, 6);
226
+ const ref1 = makeReference(
227
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
228
+ const ref2 = makeReference(
229
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
262
230
 
263
231
  await testUpdate(
264
232
  masterWithAudio, media, [ref1], mediaWithAdditionalSegment,
@@ -278,9 +246,12 @@ describe('HlsParser live', () => {
278
246
 
279
247
  const updatedMedia1 = media + newSegment1;
280
248
  const updatedMedia2 = updatedMedia1 + newSegment2;
281
- const ref1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
282
- const ref2 = ManifestParser.makeReference('test:/main2.mp4', 4, 6);
283
- const ref3 = ManifestParser.makeReference('test:/main3.mp4', 6, 8);
249
+ const ref1 = makeReference(
250
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
251
+ const ref2 = makeReference(
252
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
253
+ const ref3 = makeReference(
254
+ 'test:/main3.mp4', 4, 6, /* syncTime= */ null);
284
255
 
285
256
  fakeNetEngine
286
257
  .setResponseText('test:/master', master)
@@ -386,19 +357,6 @@ describe('HlsParser live', () => {
386
357
  'main.mp4\n',
387
358
  ].join('');
388
359
 
389
- const mediaWithByteRange = [
390
- '#EXTM3U\n',
391
- '#EXT-X-TARGETDURATION:5\n',
392
- '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
393
- '#EXT-X-MEDIA-SEQUENCE:0\n',
394
- '#EXT-X-BYTERANGE:121090@616\n',
395
- '#EXTINF:2,\n',
396
- 'main.mp4\n',
397
- ].join('');
398
-
399
- const expectedStartByte = 616;
400
- const expectedEndByte = 121705;
401
-
402
360
  const mediaWithAdditionalSegment = [
403
361
  '#EXTM3U\n',
404
362
  '#EXT-X-TARGETDURATION:5\n',
@@ -563,17 +521,17 @@ describe('HlsParser live', () => {
563
521
  .setResponseValue('test:/main.mp4', segmentData)
564
522
  .setResponseValue('test:/main2.mp4', segmentData);
565
523
 
566
- const ref1 = ManifestParser.makeReference(
567
- 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 2,
524
+ const ref1 = makeReference(
525
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null,
568
526
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
569
527
  /* timestampOffset= */ 0);
570
528
 
571
529
  // Expect the timestamp offset to be set for the segment after the
572
530
  // EXT-X-DISCONTINUITY tag.
573
- const ref2 = ManifestParser.makeReference(
574
- 'test:/main2.mp4', segmentDataStartTime + 2, segmentDataStartTime + 4,
531
+ const ref2 = makeReference(
532
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null,
575
533
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
576
- /* timestampOffset= */ 2);
534
+ /* timestampOffset= */ 0);
577
535
 
578
536
  const manifest = await parser.start('test:/master', playerInterface);
579
537
  const video = manifest.variants[0].video;
@@ -581,62 +539,13 @@ describe('HlsParser live', () => {
581
539
  ManifestParser.verifySegmentIndex(video, [ref1, ref2]);
582
540
  });
583
541
 
584
- it('offsets VTT text with rolled over TS timestamps', async () => {
585
- const masterWithVtt = [
586
- '#EXTM3U\n',
587
- '#EXT-X-MEDIA:TYPE=SUBTITLES,LANGUAGE="fra",URI="text",',
588
- 'GROUP-ID="sub1"\n',
589
- '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
590
- 'RESOLUTION=960x540,FRAME-RATE=60,SUBTITLES="sub1"\n',
591
- 'video\n',
592
- ].join('');
593
-
594
- const textPlaylist = [
595
- '#EXTM3U\n',
596
- '#EXT-X-TARGETDURATION:5\n',
597
- '#EXT-X-MEDIA-SEQUENCE:0\n',
598
- '#EXTINF:2,\n',
599
- 'main.vtt\n',
600
- ].join('');
601
-
602
- const vtt = [
603
- 'WEBVTT\n',
604
- '\n',
605
- '00:00.000 --> 00:01.000\n',
606
- 'Hello, world!\n',
607
- ].join('');
608
-
609
- fakeNetEngine
610
- .setResponseText('test:/master', masterWithVtt)
611
- .setResponseText('test:/video', media)
612
- .setResponseText('test:/text', textPlaylist)
613
- .setResponseValue('test:/init.mp4', initSegmentData)
614
- .setResponseValue('test:/main.mp4', pastRolloverSegmentData)
615
- .setResponseText('test:/main.vtt', vtt);
616
-
617
- const manifest = await parser.start('test:/master', playerInterface);
618
- const textStream = manifest.textStreams[0];
619
- await textStream.createSegmentIndex();
620
- goog.asserts.assert(textStream.segmentIndex, 'Null segmentIndex!');
621
-
622
- let ref = Array.from(textStream.segmentIndex)[0];
623
- expect(ref).not.toBe(null);
624
- expect(ref.startTime).not.toBeLessThan(rolloverOffset);
625
-
626
- const videoStream = manifest.variants[0].video;
627
- await videoStream.createSegmentIndex();
628
- goog.asserts.assert(videoStream.segmentIndex, 'Null segmentIndex!');
629
-
630
- ref = Array.from(videoStream.segmentIndex)[0];
631
- expect(ref).not.toBe(null);
632
- expect(ref.startTime).not.toBeLessThan(rolloverOffset);
633
- });
634
-
542
+ // Test for https://github.com/shaka-project/shaka-player/issues/4223
635
543
  it('parses streams with partial and preload hinted segments', async () => {
636
544
  playerInterface.isLowLatencyMode = () => true;
637
545
  const mediaWithPartialSegments = [
638
546
  '#EXTM3U\n',
639
547
  '#EXT-X-TARGETDURATION:5\n',
548
+ '#EXT-X-PART-INF:PART-TARGET=1.5\n',
640
549
  '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
641
550
  '#EXT-X-MEDIA-SEQUENCE:0\n',
642
551
  // ref includes partialRef, partialRef2
@@ -661,35 +570,30 @@ describe('HlsParser live', () => {
661
570
  .setResponseValue('test:/partial.mp4', segmentData)
662
571
  .setResponseValue('test:/partial2.mp4', segmentData);
663
572
 
664
- const partialRef = ManifestParser.makeReference(
665
- 'test:/partial.mp4', segmentDataStartTime, segmentDataStartTime + 2,
573
+ const partialRef = makeReference(
574
+ 'test:/partial.mp4', 0, 2, /* syncTime= */ null,
666
575
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 199);
667
576
 
668
- const partialRef2 = ManifestParser.makeReference(
669
- 'test:/partial2.mp4', segmentDataStartTime + 2,
670
- segmentDataStartTime + 4, /* baseUri= */ '', /* startByte= */ 200,
671
- /* endByte= */ 429);
577
+ const partialRef2 = makeReference(
578
+ 'test:/partial2.mp4', 2, 4, /* syncTime= */ null,
579
+ /* baseUri= */ '', /* startByte= */ 200, /* endByte= */ 429);
580
+
581
+ const ref = makeReference(
582
+ 'test:/main.mp4', 0, 4, /* syncTime= */ null,
583
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 429,
584
+ /* timestampOffset= */ 0, [partialRef, partialRef2]);
672
585
 
673
- const partialRef3 = ManifestParser.makeReference(
674
- 'test:/partial.mp4', segmentDataStartTime + 4,
675
- segmentDataStartTime + 6,
586
+ const partialRef3 = makeReference(
587
+ 'test:/partial.mp4', 4, 6, /* syncTime= */ null,
676
588
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209);
677
589
 
678
- // A preload hinted partial segment doesn't have duration information,
679
- // so its startTime and endTime are the same.
680
- const preloadRef = ManifestParser.makeReference(
681
- 'test:/partial.mp4', segmentDataStartTime + 6,
682
- segmentDataStartTime + 6,
590
+ const preloadRef = makeReference(
591
+ 'test:/partial.mp4', 6, 7.5, /* syncTime= */ null,
683
592
  /* baseUri= */ '', /* startByte= */ 210, /* endByte= */ null);
684
593
 
685
- const ref = ManifestParser.makeReference(
686
- 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 4,
687
- /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 429,
688
- /* timestampOffset= */ 0, [partialRef, partialRef2]);
689
-
690
594
  // ref2 is not fully published yet, so it doesn't have a segment uri.
691
- const ref2 = ManifestParser.makeReference(
692
- '', segmentDataStartTime + 4, segmentDataStartTime + 6,
595
+ const ref2 = makeReference(
596
+ '', 4, 7.5, /* syncTime= */ null,
693
597
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
694
598
  /* timestampOffset= */ 0, [partialRef3, preloadRef]);
695
599
 
@@ -699,18 +603,23 @@ describe('HlsParser live', () => {
699
603
  ManifestParser.verifySegmentIndex(video, [ref, ref2]);
700
604
  });
701
605
 
702
- // Test for https://github.com/shaka-project/shaka-player/issues/4185
703
- it('does not fail on preload hints with LL mode off', async () => {
704
- // LL mode must be off for this test!
705
- playerInterface.isLowLatencyMode = () => false;
606
+ // Test for https://github.com/shaka-project/shaka-player/issues/4223
607
+ it('ignores preload hinted segments without target duration', async () => {
608
+ playerInterface.isLowLatencyMode = () => true;
706
609
 
610
+ // Missing PART-TARGET, so preload hints are skipped.
707
611
  const mediaWithPartialSegments = [
708
612
  '#EXTM3U\n',
709
613
  '#EXT-X-TARGETDURATION:5\n',
710
614
  '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
615
+ '#EXT-X-MEDIA-SEQUENCE:0\n',
711
616
  '#EXTINF:4,\n',
617
+ // ref1
712
618
  'main.mp4\n',
619
+ // ref2 includes partialRef, but not preloadRef
620
+ // partialRef
713
621
  '#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
622
+ // preloadRef
714
623
  '#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210\n',
715
624
  ].join('');
716
625
 
@@ -719,7 +628,48 @@ describe('HlsParser live', () => {
719
628
  .setResponseText('test:/video', mediaWithPartialSegments)
720
629
  .setResponseValue('test:/init.mp4', initSegmentData)
721
630
  .setResponseValue('test:/main.mp4', segmentData)
722
- .setResponseValue('test:/partial.mp4', segmentData);
631
+ .setResponseValue('test:/partial.mp4', segmentData)
632
+ .setResponseValue('test:/partial2.mp4', segmentData);
633
+
634
+ const ref = makeReference(
635
+ 'test:/main.mp4', 0, 4, /* syncTime= */ null,
636
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
637
+ /* timestampOffset= */ 0, []);
638
+
639
+ const partialRef = makeReference(
640
+ 'test:/partial.mp4', 4, 6, /* syncTime= */ null,
641
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209);
642
+
643
+ // ref2 is not fully published yet, so it doesn't have a segment uri.
644
+ const ref2 = makeReference(
645
+ '', 4, 6, /* syncTime= */ null,
646
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209,
647
+ /* timestampOffset= */ 0, [partialRef]);
648
+
649
+ const manifest = await parser.start('test:/master', playerInterface);
650
+ const video = manifest.variants[0].video;
651
+ await video.createSegmentIndex();
652
+ ManifestParser.verifySegmentIndex(video, [ref, ref2]);
653
+ });
654
+
655
+ // Test for https://github.com/shaka-project/shaka-player/issues/4185
656
+ it('does not fail on preload hints with LL mode off', async () => {
657
+ // LL mode must be off for this test!
658
+ playerInterface.isLowLatencyMode = () => false;
659
+
660
+ const mediaWithPartialSegments = [
661
+ '#EXTM3U\n',
662
+ '#EXT-X-TARGETDURATION:5\n',
663
+ '#EXT-X-PART-INF:PART-TARGET=1.5\n',
664
+ '#EXTINF:4,\n',
665
+ 'main.mp4\n',
666
+ '#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
667
+ '#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210\n',
668
+ ].join('');
669
+
670
+ fakeNetEngine
671
+ .setResponseText('test:/master', master)
672
+ .setResponseText('test:/video', mediaWithPartialSegments);
723
673
 
724
674
  // If this throws, the test fails. Otherwise, it passes.
725
675
  await parser.start('test:/master', playerInterface);
@@ -727,16 +677,20 @@ describe('HlsParser live', () => {
727
677
 
728
678
  describe('update', () => {
729
679
  it('adds new segments when they appear', async () => {
730
- const ref1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
731
- const ref2 = ManifestParser.makeReference('test:/main2.mp4', 4, 6);
680
+ const ref1 = makeReference(
681
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
682
+ const ref2 = makeReference(
683
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
732
684
 
733
685
  await testUpdate(
734
686
  master, media, [ref1], mediaWithAdditionalSegment, [ref1, ref2]);
735
687
  });
736
688
 
737
689
  it('evicts removed segments', async () => {
738
- const ref1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
739
- const ref2 = ManifestParser.makeReference('test:/main2.mp4', 4, 6);
690
+ const ref1 = makeReference(
691
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
692
+ const ref2 = makeReference(
693
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
740
694
 
741
695
  await testUpdate(
742
696
  master, mediaWithAdditionalSegment, [ref1, ref2],
@@ -744,12 +698,13 @@ describe('HlsParser live', () => {
744
698
  });
745
699
 
746
700
  it('handles updates with redirects', async () => {
747
- const oldRef1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
701
+ const oldRef1 = makeReference(
702
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
748
703
 
749
- const newRef1 =
750
- ManifestParser.makeReference('test:/redirected/main.mp4', 2, 4);
751
- const newRef2 =
752
- ManifestParser.makeReference('test:/redirected/main2.mp4', 4, 6);
704
+ const newRef1 = makeReference(
705
+ 'test:/redirected/main.mp4', 0, 2, /* syncTime= */ null);
706
+ const newRef2 = makeReference(
707
+ 'test:/redirected/main2.mp4', 2, 4, /* syncTime= */ null);
753
708
 
754
709
  let playlistFetchCount = 0;
755
710
 
@@ -776,8 +731,8 @@ describe('HlsParser live', () => {
776
731
  .setResponseValue('test:/init.mp4', initSegmentData)
777
732
  .setResponseValue('test:/main.mp4', segmentData);
778
733
 
779
- const expectedRef = ManifestParser.makeReference(
780
- 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 2);
734
+ const expectedRef = makeReference(
735
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
781
736
  // In live content, we do not set timestampOffset.
782
737
  expectedRef.timestampOffset = 0;
783
738
 
@@ -794,12 +749,11 @@ describe('HlsParser live', () => {
794
749
  .setResponseValue('test:/init.mp4', initSegmentData)
795
750
  .setResponseValue('test:/main.mp4', segmentData);
796
751
 
797
- const ref1 = ManifestParser.makeReference(
798
- 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 2);
752
+ const ref1 = makeReference(
753
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
799
754
 
800
- const ref2 = ManifestParser.makeReference(
801
- 'test:/main2.mp4', segmentDataStartTime + 2,
802
- segmentDataStartTime + 4);
755
+ const ref2 = makeReference(
756
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
803
757
 
804
758
  const manifest = await parser.start('test:/master', playerInterface);
805
759
  const video = manifest.variants[0].video;
@@ -835,11 +789,11 @@ describe('HlsParser live', () => {
835
789
  .setResponseValue('test:/main.mp4', segmentData)
836
790
  .setResponseValue('test:/main2.mp4', segmentData);
837
791
 
838
- const ref1 = ManifestParser.makeReference('test:/main.mp4',
839
- segmentDataStartTime, segmentDataStartTime + 2);
792
+ const ref1 = makeReference(
793
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
840
794
 
841
- const ref2 = ManifestParser.makeReference('test:/main2.mp4',
842
- segmentDataStartTime + 2, segmentDataStartTime + 4);
795
+ const ref2 = makeReference(
796
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
843
797
 
844
798
  const manifest =
845
799
  await parser.start('test:/master', playerInterface);
@@ -872,57 +826,6 @@ describe('HlsParser live', () => {
872
826
  shaka.net.NetworkingEngine.RequestType.SEGMENT);
873
827
  });
874
828
 
875
- it('parses start time from ts segments', async () => {
876
- const tsMediaPlaylist =
877
- mediaWithRemovedSegment.replace(/\.mp4/g, '.ts');
878
-
879
- fakeNetEngine
880
- .setResponseText('test:/master', master)
881
- .setResponseText('test:/video', tsMediaPlaylist)
882
- .setResponseValue('test:/main2.ts', tsSegmentData);
883
-
884
- const expectedRef = ManifestParser.makeReference(
885
- 'test:/main2.ts', segmentDataStartTime, segmentDataStartTime + 2);
886
- // In live content, we do not set timestampOffset.
887
- expectedRef.timestampOffset = 0;
888
-
889
- const manifest = await parser.start('test:/master', playerInterface);
890
- const video = manifest.variants[0].video;
891
- await video.createSegmentIndex();
892
- ManifestParser.verifySegmentIndex(video, [expectedRef]);
893
- });
894
-
895
- it('gets start time of segments with byte range', async () => {
896
- // Nit: this value is an implementation detail of the fix for #1106
897
- const partialEndByte = expectedStartByte + 2048 - 1;
898
-
899
- fakeNetEngine
900
- .setResponseText('test:/master', master)
901
- .setResponseText('test:/video', mediaWithByteRange)
902
- .setResponseValue('test:/init.mp4', initSegmentData)
903
- .setResponseValue('test:/main.mp4', segmentData);
904
-
905
- const expectedRef = ManifestParser.makeReference(
906
- /* uri= */ 'test:/main.mp4',
907
- /* start= */ segmentDataStartTime,
908
- /* end= */ segmentDataStartTime + 2,
909
- /* baseUri= */ '',
910
- expectedStartByte,
911
- expectedEndByte); // Complete segment reference
912
-
913
- const manifest = await parser.start('test:/master', playerInterface);
914
- const video = manifest.variants[0].video;
915
- await video.createSegmentIndex();
916
- ManifestParser.verifySegmentIndex(video, [expectedRef]);
917
-
918
- // There should have been a range request for this segment to get the
919
- // start time.
920
- fakeNetEngine.expectRangeRequest(
921
- 'test:/main.mp4',
922
- expectedStartByte,
923
- partialEndByte); // partial segment request
924
- });
925
-
926
829
  it('request playlist delta updates to skip segments', async () => {
927
830
  const mediaWithDeltaUpdates = [
928
831
  '#EXTM3U\n',
@@ -987,9 +890,12 @@ describe('HlsParser live', () => {
987
890
  ].join('');
988
891
 
989
892
  playerInterface.isLowLatencyMode = () => true;
990
- const ref1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
991
- const ref2 = ManifestParser.makeReference('test:/main2.mp4', 4, 6);
992
- const ref3 = ManifestParser.makeReference('test:/main3.mp4', 6, 8);
893
+ const ref1 = makeReference(
894
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
895
+ const ref2 = makeReference(
896
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
897
+ const ref3 = makeReference(
898
+ 'test:/main3.mp4', 4, 6, /* syncTime= */ null);
993
899
  // With 'SKIPPED-SEGMENTS', ref1 is skipped from the playlist,
994
900
  // and ref1 should be in the SegmentReferences list.
995
901
  // ref3 should be appended to the SegmentReferences list.
@@ -1029,29 +935,29 @@ describe('HlsParser live', () => {
1029
935
 
1030
936
  playerInterface.isLowLatencyMode = () => true;
1031
937
 
1032
- const ref1 = ManifestParser.makeReference(
1033
- 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 2,
938
+ const ref1 = makeReference(
939
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null,
1034
940
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
1035
941
  /* timestampOffset= */ 0);
1036
942
 
1037
943
  // Expect the timestamp offset to be set for the segment after the
1038
944
  // EXT-X-DISCONTINUITY tag.
1039
- const ref2 = ManifestParser.makeReference(
1040
- 'test:/main2.mp4', segmentDataStartTime + 2,
1041
- segmentDataStartTime + 4, /* baseUri= */ '', /* startByte= */ 0,
1042
- /* endByte= */ null, /* timestampOffset= */ 2);
945
+ const ref2 = makeReference(
946
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null,
947
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
948
+ /* timestampOffset= */ 0);
1043
949
 
1044
950
  // Expect the timestamp offset to be set for the segment, with the
1045
951
  // EXT-X-DISCONTINUITY tag skipped in the playlist.
1046
- const ref3 = ManifestParser.makeReference(
1047
- 'test:/main3.mp4', segmentDataStartTime + 4,
1048
- segmentDataStartTime + 6, /* baseUri= */ '', /* startByte= */ 0,
1049
- /* endByte= */ null, /* timestampOffset= */ 2);
952
+ const ref3 = makeReference(
953
+ 'test:/main3.mp4', 4, 6, /* syncTime= */ null,
954
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
955
+ /* timestampOffset= */ 0);
1050
956
 
1051
- const ref4 = ManifestParser.makeReference(
1052
- 'test:/main4.mp4', segmentDataStartTime + 6,
1053
- segmentDataStartTime + 8, /* baseUri= */ '', /* startByte= */ 0,
1054
- /* endByte= */ null, /* timestampOffset= */ 2);
957
+ const ref4 = makeReference(
958
+ 'test:/main4.mp4', 6, 8, /* syncTime= */ null,
959
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
960
+ /* timestampOffset= */ 0);
1055
961
 
1056
962
  // With 'SKIPPED-SEGMENTS', ref1, ref2 are skipped from the playlist,
1057
963
  // and ref1,ref2 should be in the SegmentReferences list.
@@ -1062,4 +968,23 @@ describe('HlsParser live', () => {
1062
968
  });
1063
969
  }); // describe('update')
1064
970
  }); // describe('playlist type LIVE')
971
+
972
+ /**
973
+ * @param {string} uri A relative URI to http://example.com
974
+ * @param {number} start
975
+ * @param {number} end
976
+ * @param {?number} syncTime
977
+ * @param {string=} baseUri
978
+ * @param {number=} startByte
979
+ * @param {?number=} endByte
980
+ * @param {number=} timestampOffset
981
+ * @param {!Array.<!shaka.media.SegmentReference>=} partialReferences
982
+ * @param {?string=} tilesLayout
983
+ * @return {!shaka.media.SegmentReference}
984
+ */
985
+ function makeReference(uri, start, end, syncTime, baseUri, startByte, endByte,
986
+ timestampOffset, partialReferences, tilesLayout) {
987
+ return ManifestParser.makeReference(uri, start, end, baseUri, startByte,
988
+ endByte, timestampOffset, partialReferences, tilesLayout, syncTime);
989
+ }
1065
990
  }); // describe('HlsParser live')