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
@@ -35,12 +35,9 @@ goog.require('shaka.offline.indexeddb.StorageMechanism');
35
35
  goog.require('shaka.polyfill.Aria');
36
36
  goog.require('shaka.polyfill.EncryptionScheme');
37
37
  goog.require('shaka.polyfill.Fullscreen');
38
- goog.require('shaka.polyfill.MathRound');
39
38
  goog.require('shaka.polyfill.MediaSource');
40
39
  goog.require('shaka.polyfill.MediaCapabilities');
41
40
  goog.require('shaka.polyfill.Orientation');
42
- goog.require('shaka.polyfill.PatchedMediaKeysApple');
43
- goog.require('shaka.polyfill.PatchedMediaKeysMs');
44
41
  goog.require('shaka.polyfill.PatchedMediaKeysNop');
45
42
  goog.require('shaka.polyfill.PatchedMediaKeysWebkit');
46
43
  goog.require('shaka.polyfill.PiPWebkit');
@@ -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 =
@@ -805,6 +805,50 @@ describe('DashParser ContentProtection', () => {
805
805
  });
806
806
  });
807
807
 
808
+ describe('getClearKeyLicenseUrl', () => {
809
+ it('valid clearkey:Laurl node', () => {
810
+ const input = {
811
+ init: null,
812
+ keyId: null,
813
+ schemeUri: '',
814
+ node: strToXml([
815
+ '<test xmlns:clearkey="http://dashif.org/guidelines/clearKey">',
816
+ ' <clearkey:Laurl ',
817
+ ' Lic_type="EME-1.0">www.example.com</clearkey:Laurl>',
818
+ '</test>',
819
+ ].join('\n')),
820
+ };
821
+ const actual = ContentProtection.getClearKeyLicenseUrl(input);
822
+ expect(actual).toBe('www.example.com');
823
+ });
824
+
825
+ it('clearkey:Laurl without license url', () => {
826
+ const input = {
827
+ init: null,
828
+ keyId: null,
829
+ schemeUri: '',
830
+ node: strToXml([
831
+ '<test xmlns:clearkey="http://dashif.org/guidelines/clearKey">',
832
+ ' <clearkey:Laurl Lic_type="EME-1.0"></clearkey:Laurl>',
833
+ '</test>',
834
+ ].join('\n')),
835
+ };
836
+ const actual = ContentProtection.getClearKeyLicenseUrl(input);
837
+ expect(actual).toBe('');
838
+ });
839
+
840
+ it('no clearkey:Laurl node', () => {
841
+ const input = {
842
+ init: null,
843
+ keyId: null,
844
+ schemeUri: '',
845
+ node: strToXml('<test></test>'),
846
+ };
847
+ const actual = ContentProtection.getClearKeyLicenseUrl(input);
848
+ expect(actual).toBe('');
849
+ });
850
+ });
851
+
808
852
  describe('getPlayReadyLicenseURL', () => {
809
853
  it('mspro', () => {
810
854
  const laurl = [
@@ -447,30 +447,6 @@ describe('DashParser Manifest', () => {
447
447
  expect(stream.closedCaptions).toEqual(expectedClosedCaptions);
448
448
  });
449
449
 
450
- it('Detects E-AC3 JOC content by SupplementalProperty', async () => {
451
- const idUri = 'tag:dolby.com,2018:dash:EC3_ExtensionType:2018';
452
- const source = [
453
- '<MPD>',
454
- ' <Period duration="PT30M">',
455
- ' <AdaptationSet mimeType="audio/mp4" lang="\u2603">',
456
- ' <Representation bandwidth="500">',
457
- ' <SupplementalProperty schemeIdUri="' + idUri + '" value="JOC"/>',
458
- ' <BaseURL>http://example.com</BaseURL>',
459
- ' <SegmentTemplate media="2.mp4" duration="1" />',
460
- ' </Representation>',
461
- ' </AdaptationSet>',
462
- ' </Period>',
463
- '</MPD>',
464
- ].join('\n');
465
-
466
- fakeNetEngine.setResponseText('dummy://foo', source);
467
-
468
- /** @type {shaka.extern.Manifest} */
469
- const manifest = await parser.start('dummy://foo', playerInterface);
470
- const stream = manifest.variants[0].audio;
471
- expect(stream.mimeType).toBe('audio/eac3-joc');
472
- });
473
-
474
450
  it('Detects spatial audio', async () => {
475
451
  const idUri = 'tag:dolby.com,2018:dash:EC3_ExtensionType:2018';
476
452
  const source = [
@@ -106,9 +106,8 @@ describe('DashParser SegmentTemplate', () => {
106
106
  's2.mp4', 50, 60, baseUri);
107
107
  expectedRef2.timestampOffset = -10;
108
108
 
109
- const iterator = stream.segmentIndex[Symbol.iterator]();
110
- const ref1 = iterator.seek(45);
111
- const ref2 = iterator.seek(55);
109
+ const ref1 = stream.segmentIndex.getIteratorForTime(45).next().value;
110
+ const ref2 = stream.segmentIndex.getIteratorForTime(55).next().value;
112
111
  expect(ref1).toEqual(expectedRef1);
113
112
  expect(ref2).toEqual(expectedRef2);
114
113
  });
@@ -445,7 +444,7 @@ describe('DashParser SegmentTemplate', () => {
445
444
  await variants[2].video.createSegmentIndex();
446
445
 
447
446
  const getRefAt = (stream, time) => {
448
- return stream.segmentIndex[Symbol.iterator]().seek(time);
447
+ return stream.segmentIndex.getIteratorForTime(time).next().value;
449
448
  };
450
449
 
451
450
  expect(getRefAt(variants[0].video, 0)).toEqual(
@@ -93,7 +93,8 @@ describe('Demo', () => {
93
93
  .add('preferredVariantRole')
94
94
  .add('playRangeStart')
95
95
  .add('playRangeEnd')
96
- .add('manifest.dash.keySystemsByURI');
96
+ .add('manifest.dash.keySystemsByURI')
97
+ .add('manifest.hls.mediaPlaylistFullMimeType');
97
98
 
98
99
  /**
99
100
  * @param {!Object} section
@@ -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,57 +539,6 @@ 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
-
635
542
  it('parses streams with partial and preload hinted segments', async () => {
636
543
  playerInterface.isLowLatencyMode = () => true;
637
544
  const mediaWithPartialSegments = [
@@ -661,35 +568,32 @@ describe('HlsParser live', () => {
661
568
  .setResponseValue('test:/partial.mp4', segmentData)
662
569
  .setResponseValue('test:/partial2.mp4', segmentData);
663
570
 
664
- const partialRef = ManifestParser.makeReference(
665
- 'test:/partial.mp4', segmentDataStartTime, segmentDataStartTime + 2,
571
+ const partialRef = makeReference(
572
+ 'test:/partial.mp4', 0, 2, /* syncTime= */ null,
666
573
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 199);
667
574
 
668
- const partialRef2 = ManifestParser.makeReference(
669
- 'test:/partial2.mp4', segmentDataStartTime + 2,
670
- segmentDataStartTime + 4, /* baseUri= */ '', /* startByte= */ 200,
671
- /* endByte= */ 429);
575
+ const partialRef2 = makeReference(
576
+ 'test:/partial2.mp4', 2, 4, /* syncTime= */ null,
577
+ /* baseUri= */ '', /* startByte= */ 200, /* endByte= */ 429);
672
578
 
673
- const partialRef3 = ManifestParser.makeReference(
674
- 'test:/partial.mp4', segmentDataStartTime + 4,
675
- segmentDataStartTime + 6,
579
+ const partialRef3 = makeReference(
580
+ 'test:/partial.mp4', 4, 6, /* syncTime= */ null,
676
581
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 209);
677
582
 
678
583
  // A preload hinted partial segment doesn't have duration information,
679
584
  // so its startTime and endTime are the same.
680
- const preloadRef = ManifestParser.makeReference(
681
- 'test:/partial.mp4', segmentDataStartTime + 6,
682
- segmentDataStartTime + 6,
585
+ const preloadRef = makeReference(
586
+ 'test:/partial.mp4', 6, 6, /* syncTime= */ null,
683
587
  /* baseUri= */ '', /* startByte= */ 210, /* endByte= */ null);
684
588
 
685
- const ref = ManifestParser.makeReference(
686
- 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 4,
589
+ const ref = makeReference(
590
+ 'test:/main.mp4', 0, 4, /* syncTime= */ null,
687
591
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ 429,
688
592
  /* timestampOffset= */ 0, [partialRef, partialRef2]);
689
593
 
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, 6, /* syncTime= */ null,
693
597
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
694
598
  /* timestampOffset= */ 0, [partialRef3, preloadRef]);
695
599
 
@@ -699,18 +603,44 @@ describe('HlsParser live', () => {
699
603
  ManifestParser.verifySegmentIndex(video, [ref, ref2]);
700
604
  });
701
605
 
606
+ // Test for https://github.com/shaka-project/shaka-player/issues/4185
607
+ it('does not fail on preload hints with LL mode off', async () => {
608
+ // LL mode must be off for this test!
609
+ playerInterface.isLowLatencyMode = () => false;
610
+
611
+ const mediaWithPartialSegments = [
612
+ '#EXTM3U\n',
613
+ '#EXT-X-TARGETDURATION:5\n',
614
+ '#EXTINF:4,\n',
615
+ 'main.mp4\n',
616
+ '#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
617
+ '#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210\n',
618
+ ].join('');
619
+
620
+ fakeNetEngine
621
+ .setResponseText('test:/master', master)
622
+ .setResponseText('test:/video', mediaWithPartialSegments);
623
+
624
+ // If this throws, the test fails. Otherwise, it passes.
625
+ await parser.start('test:/master', playerInterface);
626
+ });
627
+
702
628
  describe('update', () => {
703
629
  it('adds new segments when they appear', async () => {
704
- const ref1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
705
- const ref2 = ManifestParser.makeReference('test:/main2.mp4', 4, 6);
630
+ const ref1 = makeReference(
631
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
632
+ const ref2 = makeReference(
633
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
706
634
 
707
635
  await testUpdate(
708
636
  master, media, [ref1], mediaWithAdditionalSegment, [ref1, ref2]);
709
637
  });
710
638
 
711
639
  it('evicts removed segments', async () => {
712
- const ref1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
713
- const ref2 = ManifestParser.makeReference('test:/main2.mp4', 4, 6);
640
+ const ref1 = makeReference(
641
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
642
+ const ref2 = makeReference(
643
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
714
644
 
715
645
  await testUpdate(
716
646
  master, mediaWithAdditionalSegment, [ref1, ref2],
@@ -718,12 +648,13 @@ describe('HlsParser live', () => {
718
648
  });
719
649
 
720
650
  it('handles updates with redirects', async () => {
721
- const oldRef1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
651
+ const oldRef1 = makeReference(
652
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
722
653
 
723
- const newRef1 =
724
- ManifestParser.makeReference('test:/redirected/main.mp4', 2, 4);
725
- const newRef2 =
726
- ManifestParser.makeReference('test:/redirected/main2.mp4', 4, 6);
654
+ const newRef1 = makeReference(
655
+ 'test:/redirected/main.mp4', 0, 2, /* syncTime= */ null);
656
+ const newRef2 = makeReference(
657
+ 'test:/redirected/main2.mp4', 2, 4, /* syncTime= */ null);
727
658
 
728
659
  let playlistFetchCount = 0;
729
660
 
@@ -750,8 +681,8 @@ describe('HlsParser live', () => {
750
681
  .setResponseValue('test:/init.mp4', initSegmentData)
751
682
  .setResponseValue('test:/main.mp4', segmentData);
752
683
 
753
- const expectedRef = ManifestParser.makeReference(
754
- 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 2);
684
+ const expectedRef = makeReference(
685
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
755
686
  // In live content, we do not set timestampOffset.
756
687
  expectedRef.timestampOffset = 0;
757
688
 
@@ -768,12 +699,11 @@ describe('HlsParser live', () => {
768
699
  .setResponseValue('test:/init.mp4', initSegmentData)
769
700
  .setResponseValue('test:/main.mp4', segmentData);
770
701
 
771
- const ref1 = ManifestParser.makeReference(
772
- 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 2);
702
+ const ref1 = makeReference(
703
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
773
704
 
774
- const ref2 = ManifestParser.makeReference(
775
- 'test:/main2.mp4', segmentDataStartTime + 2,
776
- segmentDataStartTime + 4);
705
+ const ref2 = makeReference(
706
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
777
707
 
778
708
  const manifest = await parser.start('test:/master', playerInterface);
779
709
  const video = manifest.variants[0].video;
@@ -809,11 +739,11 @@ describe('HlsParser live', () => {
809
739
  .setResponseValue('test:/main.mp4', segmentData)
810
740
  .setResponseValue('test:/main2.mp4', segmentData);
811
741
 
812
- const ref1 = ManifestParser.makeReference('test:/main.mp4',
813
- segmentDataStartTime, segmentDataStartTime + 2);
742
+ const ref1 = makeReference(
743
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
814
744
 
815
- const ref2 = ManifestParser.makeReference('test:/main2.mp4',
816
- segmentDataStartTime + 2, segmentDataStartTime + 4);
745
+ const ref2 = makeReference(
746
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
817
747
 
818
748
  const manifest =
819
749
  await parser.start('test:/master', playerInterface);
@@ -846,57 +776,6 @@ describe('HlsParser live', () => {
846
776
  shaka.net.NetworkingEngine.RequestType.SEGMENT);
847
777
  });
848
778
 
849
- it('parses start time from ts segments', async () => {
850
- const tsMediaPlaylist =
851
- mediaWithRemovedSegment.replace(/\.mp4/g, '.ts');
852
-
853
- fakeNetEngine
854
- .setResponseText('test:/master', master)
855
- .setResponseText('test:/video', tsMediaPlaylist)
856
- .setResponseValue('test:/main2.ts', tsSegmentData);
857
-
858
- const expectedRef = ManifestParser.makeReference(
859
- 'test:/main2.ts', segmentDataStartTime, segmentDataStartTime + 2);
860
- // In live content, we do not set timestampOffset.
861
- expectedRef.timestampOffset = 0;
862
-
863
- const manifest = await parser.start('test:/master', playerInterface);
864
- const video = manifest.variants[0].video;
865
- await video.createSegmentIndex();
866
- ManifestParser.verifySegmentIndex(video, [expectedRef]);
867
- });
868
-
869
- it('gets start time of segments with byte range', async () => {
870
- // Nit: this value is an implementation detail of the fix for #1106
871
- const partialEndByte = expectedStartByte + 2048 - 1;
872
-
873
- fakeNetEngine
874
- .setResponseText('test:/master', master)
875
- .setResponseText('test:/video', mediaWithByteRange)
876
- .setResponseValue('test:/init.mp4', initSegmentData)
877
- .setResponseValue('test:/main.mp4', segmentData);
878
-
879
- const expectedRef = ManifestParser.makeReference(
880
- /* uri= */ 'test:/main.mp4',
881
- /* start= */ segmentDataStartTime,
882
- /* end= */ segmentDataStartTime + 2,
883
- /* baseUri= */ '',
884
- expectedStartByte,
885
- expectedEndByte); // Complete segment reference
886
-
887
- const manifest = await parser.start('test:/master', playerInterface);
888
- const video = manifest.variants[0].video;
889
- await video.createSegmentIndex();
890
- ManifestParser.verifySegmentIndex(video, [expectedRef]);
891
-
892
- // There should have been a range request for this segment to get the
893
- // start time.
894
- fakeNetEngine.expectRangeRequest(
895
- 'test:/main.mp4',
896
- expectedStartByte,
897
- partialEndByte); // partial segment request
898
- });
899
-
900
779
  it('request playlist delta updates to skip segments', async () => {
901
780
  const mediaWithDeltaUpdates = [
902
781
  '#EXTM3U\n',
@@ -961,9 +840,12 @@ describe('HlsParser live', () => {
961
840
  ].join('');
962
841
 
963
842
  playerInterface.isLowLatencyMode = () => true;
964
- const ref1 = ManifestParser.makeReference('test:/main.mp4', 2, 4);
965
- const ref2 = ManifestParser.makeReference('test:/main2.mp4', 4, 6);
966
- const ref3 = ManifestParser.makeReference('test:/main3.mp4', 6, 8);
843
+ const ref1 = makeReference(
844
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null);
845
+ const ref2 = makeReference(
846
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null);
847
+ const ref3 = makeReference(
848
+ 'test:/main3.mp4', 4, 6, /* syncTime= */ null);
967
849
  // With 'SKIPPED-SEGMENTS', ref1 is skipped from the playlist,
968
850
  // and ref1 should be in the SegmentReferences list.
969
851
  // ref3 should be appended to the SegmentReferences list.
@@ -1003,29 +885,29 @@ describe('HlsParser live', () => {
1003
885
 
1004
886
  playerInterface.isLowLatencyMode = () => true;
1005
887
 
1006
- const ref1 = ManifestParser.makeReference(
1007
- 'test:/main.mp4', segmentDataStartTime, segmentDataStartTime + 2,
888
+ const ref1 = makeReference(
889
+ 'test:/main.mp4', 0, 2, /* syncTime= */ null,
1008
890
  /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
1009
891
  /* timestampOffset= */ 0);
1010
892
 
1011
893
  // Expect the timestamp offset to be set for the segment after the
1012
894
  // EXT-X-DISCONTINUITY tag.
1013
- const ref2 = ManifestParser.makeReference(
1014
- 'test:/main2.mp4', segmentDataStartTime + 2,
1015
- segmentDataStartTime + 4, /* baseUri= */ '', /* startByte= */ 0,
1016
- /* endByte= */ null, /* timestampOffset= */ 2);
895
+ const ref2 = makeReference(
896
+ 'test:/main2.mp4', 2, 4, /* syncTime= */ null,
897
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
898
+ /* timestampOffset= */ 0);
1017
899
 
1018
900
  // Expect the timestamp offset to be set for the segment, with the
1019
901
  // EXT-X-DISCONTINUITY tag skipped in the playlist.
1020
- const ref3 = ManifestParser.makeReference(
1021
- 'test:/main3.mp4', segmentDataStartTime + 4,
1022
- segmentDataStartTime + 6, /* baseUri= */ '', /* startByte= */ 0,
1023
- /* endByte= */ null, /* timestampOffset= */ 2);
902
+ const ref3 = makeReference(
903
+ 'test:/main3.mp4', 4, 6, /* syncTime= */ null,
904
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
905
+ /* timestampOffset= */ 0);
1024
906
 
1025
- const ref4 = ManifestParser.makeReference(
1026
- 'test:/main4.mp4', segmentDataStartTime + 6,
1027
- segmentDataStartTime + 8, /* baseUri= */ '', /* startByte= */ 0,
1028
- /* endByte= */ null, /* timestampOffset= */ 2);
907
+ const ref4 = makeReference(
908
+ 'test:/main4.mp4', 6, 8, /* syncTime= */ null,
909
+ /* baseUri= */ '', /* startByte= */ 0, /* endByte= */ null,
910
+ /* timestampOffset= */ 0);
1029
911
 
1030
912
  // With 'SKIPPED-SEGMENTS', ref1, ref2 are skipped from the playlist,
1031
913
  // and ref1,ref2 should be in the SegmentReferences list.
@@ -1036,4 +918,23 @@ describe('HlsParser live', () => {
1036
918
  });
1037
919
  }); // describe('update')
1038
920
  }); // describe('playlist type LIVE')
921
+
922
+ /**
923
+ * @param {string} uri A relative URI to http://example.com
924
+ * @param {number} start
925
+ * @param {number} end
926
+ * @param {?number} syncTime
927
+ * @param {string=} baseUri
928
+ * @param {number=} startByte
929
+ * @param {?number=} endByte
930
+ * @param {number=} timestampOffset
931
+ * @param {!Array.<!shaka.media.SegmentReference>=} partialReferences
932
+ * @param {?string=} tilesLayout
933
+ * @return {!shaka.media.SegmentReference}
934
+ */
935
+ function makeReference(uri, start, end, syncTime, baseUri, startByte, endByte,
936
+ timestampOffset, partialReferences, tilesLayout) {
937
+ return ManifestParser.makeReference(uri, start, end, baseUri, startByte,
938
+ endByte, timestampOffset, partialReferences, tilesLayout, syncTime);
939
+ }
1039
940
  }); // describe('HlsParser live')