shaka-player 3.3.4 → 4.0.0

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/workflows/build-and-test.yaml +0 -1
  2. package/.github/workflows/demo-version-index.yaml +8 -0
  3. package/.github/workflows/release-please.yaml +23 -2
  4. package/.github/workflows/selenium-lab-tests.yaml +0 -1
  5. package/.github/workflows/sync-labels.yaml +33 -0
  6. package/.github/workflows/update-issues.yaml +29 -0
  7. package/.github/workflows/validate-pr-title.yaml +35 -0
  8. package/AUTHORS +1 -0
  9. package/CHANGELOG.md +198 -32
  10. package/CONTRIBUTORS +1 -0
  11. package/README.md +10 -7
  12. package/app-engine/demo-version-index/README.md +3 -3
  13. package/app-engine/demo-version-index/app.yaml +27 -1
  14. package/app-engine/demo-version-index/generate.py +164 -0
  15. package/app-engine/demo-version-index/main.py +4 -155
  16. package/app-engine/demo-version-index/requirements.txt +0 -1
  17. package/build/README.md +2 -2
  18. package/build/compiler.py +1 -1
  19. package/build/generateTsDefs.py +0 -2
  20. package/build/shaka-lab.yaml +0 -2
  21. package/build/test.py +7 -1
  22. package/build/types/core +0 -1
  23. package/build/types/polyfill +0 -3
  24. package/demo/common/asset.js +17 -1
  25. package/demo/common/assets.js +29 -0
  26. package/demo/common/message_ids.js +6 -3
  27. package/demo/config.js +10 -11
  28. package/demo/custom.js +39 -0
  29. package/demo/demo_utils.js +0 -1
  30. package/demo/locales/en.json +6 -3
  31. package/demo/locales/source.json +22 -10
  32. package/demo/main.js +9 -6
  33. package/demo/search.js +2 -1
  34. package/dist/controls.css +1 -1
  35. package/dist/demo.compiled.debug.js +71 -64
  36. package/dist/demo.compiled.debug.map +3 -3
  37. package/dist/demo.compiled.js +71 -64
  38. package/dist/demo.compiled.map +3 -3
  39. package/dist/demo.css +1 -1
  40. package/dist/demo.css.map +1 -1
  41. package/dist/deps.js +16 -20
  42. package/dist/locales.js +31 -29
  43. package/dist/receiver.compiled.debug.js +32 -28
  44. package/dist/receiver.compiled.debug.map +3 -3
  45. package/dist/receiver.compiled.js +32 -28
  46. package/dist/receiver.compiled.map +3 -3
  47. package/dist/shaka-player.compiled.d.ts +78 -83
  48. package/dist/shaka-player.compiled.debug.d.ts +78 -83
  49. package/dist/shaka-player.compiled.debug.externs.js +126 -126
  50. package/dist/shaka-player.compiled.debug.js +426 -483
  51. package/dist/shaka-player.compiled.debug.map +4 -4
  52. package/dist/shaka-player.compiled.externs.js +126 -126
  53. package/dist/shaka-player.compiled.js +838 -856
  54. package/dist/shaka-player.compiled.map +4 -4
  55. package/dist/shaka-player.ui.d.ts +80 -83
  56. package/dist/shaka-player.ui.debug.d.ts +80 -83
  57. package/dist/shaka-player.ui.debug.externs.js +134 -126
  58. package/dist/shaka-player.ui.debug.js +488 -543
  59. package/dist/shaka-player.ui.debug.map +4 -4
  60. package/dist/shaka-player.ui.externs.js +134 -126
  61. package/dist/shaka-player.ui.js +980 -994
  62. package/dist/shaka-player.ui.map +4 -4
  63. package/docs/tutorials/config.md +0 -2
  64. package/docs/tutorials/drm-config.md +5 -0
  65. package/docs/tutorials/fairplay.md +7 -22
  66. package/docs/tutorials/faq.md +0 -11
  67. package/docs/tutorials/index.json +2 -8
  68. package/docs/tutorials/plugins.md +1 -3
  69. package/docs/tutorials/upgrade.md +83 -11
  70. package/externs/polyfill.js +15 -0
  71. package/externs/shaka/manifest.js +5 -1
  72. package/externs/shaka/net.js +12 -0
  73. package/externs/shaka/offline.js +5 -1
  74. package/externs/shaka/player.js +39 -32
  75. package/externs/shaka/text.js +12 -12
  76. package/externs/sourcebuffer.js +15 -0
  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 -1
  82. package/lib/hls/hls_parser.js +378 -743
  83. package/lib/hls/manifest_text_parser.js +2 -3
  84. package/lib/media/drm_engine.js +102 -53
  85. package/lib/media/gap_jumping_controller.js +10 -45
  86. package/lib/media/media_source_engine.js +87 -15
  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 +29 -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 +100 -132
  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 +24 -2
  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 +2 -0
  120. package/lib/util/platform.js +45 -0
  121. package/lib/util/player_configuration.js +12 -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 +1 -1
  127. package/roadmap.md +19 -19
  128. package/shaka-player.uncompiled.js +0 -3
  129. package/test/cast/cast_utils_unit.js +1 -0
  130. package/test/dash/dash_parser_content_protection_unit.js +44 -0
  131. package/test/dash/dash_parser_manifest_unit.js +0 -24
  132. package/test/dash/dash_parser_segment_template_unit.js +3 -4
  133. package/test/demo/demo_unit.js +2 -1
  134. package/test/hls/hls_live_unit.js +99 -220
  135. package/test/hls/hls_parser_unit.js +515 -432
  136. package/test/media/drm_engine_unit.js +86 -120
  137. package/test/media/media_source_engine_integration.js +26 -3
  138. package/test/media/media_source_engine_unit.js +7 -6
  139. package/test/media/playhead_unit.js +27 -191
  140. package/test/media/segment_index_unit.js +15 -25
  141. package/test/media/streaming_engine_integration.js +4 -39
  142. package/test/media/streaming_engine_unit.js +3 -2
  143. package/test/media/time_ranges_utils_unit.js +0 -5
  144. package/test/offline/manifest_convert_unit.js +34 -4
  145. package/test/offline/offline_manifest_parser_unit.js +1 -0
  146. package/test/offline/storage_integration.js +5 -4
  147. package/test/player_external.js +0 -6
  148. package/test/player_integration.js +16 -0
  149. package/test/player_unit.js +26 -0
  150. package/test/test/util/fake_media_source_engine.js +11 -4
  151. package/test/test/util/manifest_generator.js +3 -1
  152. package/test/test/util/manifest_parser_util.js +4 -1
  153. package/test/test/util/offline_utils.js +1 -0
  154. package/test/test/util/streaming_engine_util.js +1 -0
  155. package/test/test/util/test_scheme.js +24 -1
  156. package/test/test/util/util.js +4 -4
  157. package/test/text/cue_integration.js +2 -2
  158. package/test/text/lrc_text_parser_unit.js +6 -7
  159. package/test/text/mp4_ttml_parser_unit.js +6 -4
  160. package/test/text/mp4_vtt_parser_unit.js +6 -5
  161. package/test/text/sbv_text_parser_unit.js +5 -6
  162. package/test/text/srt_text_parser_unit.js +5 -6
  163. package/test/text/ssa_text_parser_unit.js +17 -29
  164. package/test/text/text_engine_unit.js +45 -5
  165. package/test/text/ttml_text_parser_unit.js +77 -77
  166. package/test/text/vtt_text_parser_unit.js +55 -57
  167. package/test/ui/ui_integration.js +0 -16
  168. package/test/ui/ui_unit.js +27 -0
  169. package/test/util/cmcd_manager_unit.js +3 -0
  170. package/test/util/stream_utils_unit.js +23 -7
  171. package/ui/controls.js +65 -40
  172. package/ui/fullscreen_button.js +26 -6
  173. package/ui/less/containers.less +3 -3
  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/docs/tutorials/upgrade-v2-5.md +0 -441
  179. package/docs/tutorials/upgrade-v3.md +0 -38
  180. package/lib/polyfill/mathround.js +0 -49
  181. package/lib/polyfill/patchedmediakeys_apple.js +0 -744
  182. package/lib/polyfill/patchedmediakeys_ms.js +0 -698
  183. package/lib/util/mutex.js +0 -52
  184. package/test/util/functional_unit.js +0 -82
package/lib/player.js CHANGED
@@ -43,7 +43,6 @@ goog.require('shaka.util.Error');
43
43
  goog.require('shaka.util.EventManager');
44
44
  goog.require('shaka.util.FakeEvent');
45
45
  goog.require('shaka.util.FakeEventTarget');
46
- goog.require('shaka.util.Functional');
47
46
  goog.require('shaka.util.IDestroyable');
48
47
  goog.require('shaka.util.LanguageUtils');
49
48
  goog.require('shaka.util.ManifestParserUtils');
@@ -301,22 +300,6 @@ goog.requireType('shaka.routing.Payload');
301
300
  */
302
301
 
303
302
 
304
- /**
305
- * @event shaka.Player.LargeGapEvent
306
- * @description Fired when the playhead enters a large gap. If the
307
- * <code>streaming.jumpLargeGaps</code> configuration is set, the default
308
- * action of this event is to jump the gap; this can be prevented by calling
309
- * <code>preventDefault()</code> on the event object.
310
- * @property {string} type
311
- * 'largegap'
312
- * @property {number} currentTime
313
- * The current time of the playhead.
314
- * @property {number} gapSize
315
- * The size of the gap, in seconds.
316
- * @exportDoc
317
- */
318
-
319
-
320
303
  /**
321
304
  * @event shaka.Player.ManifestParsedEvent
322
305
  * @description Fired after the manifest has been parsed, but before anything
@@ -576,8 +559,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
576
559
  this.adManager_ = null;
577
560
 
578
561
  if (shaka.Player.adManagerFactory_) {
579
- this.adManager_ =
580
- shaka.util.Functional.callFactory(shaka.Player.adManagerFactory_);
562
+ this.adManager_ = shaka.Player.adManagerFactory_();
581
563
  }
582
564
 
583
565
  // If the browser comes back online after being offline, then try to play
@@ -847,10 +829,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
847
829
  return false;
848
830
  }
849
831
 
850
- // We do not support iOS 9, 10, or 11, nor those same versions of desktop
851
- // Safari.
832
+ // We do not support iOS 9, 10, 11 or 12, nor those same versions of
833
+ // desktop Safari.
852
834
  const safariVersion = shaka.util.Platform.safariVersion();
853
- if (safariVersion && safariVersion < 12) {
835
+ if (safariVersion && safariVersion < 13) {
854
836
  return false;
855
837
  }
856
838
 
@@ -1560,8 +1542,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1560
1542
  // text displayer and streaming engine are always in sync, wait until they
1561
1543
  // are both initialized before setting the initial value.
1562
1544
  const textDisplayerFactory = this.config_.textDisplayFactory;
1563
- const textDisplayer =
1564
- shaka.util.Functional.callFactory(textDisplayerFactory);
1545
+ const textDisplayer = textDisplayerFactory();
1565
1546
  this.lastTextFactory_ = textDisplayerFactory;
1566
1547
 
1567
1548
  const mediaSourceEngine = this.createMediaSourceEngine(
@@ -1571,6 +1552,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1571
1552
  (metadata, offset, endTime) => {
1572
1553
  this.processTimedMetadataMediaSrc_(metadata, offset, endTime);
1573
1554
  });
1555
+ const {segmentRelativeVttTiming} = this.config_.manifest;
1556
+ mediaSourceEngine.setSegmentRelativeVttTiming(segmentRelativeVttTiming);
1574
1557
 
1575
1558
  // Wait for media source engine to finish opening. This promise should
1576
1559
  // NEVER be rejected as per the media source engine implementation.
@@ -1632,7 +1615,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1632
1615
  this.config_.manifest.retryParameters,
1633
1616
  has.mimeType);
1634
1617
  goog.asserts.assert(this.parserFactory_, 'Must have manifest parser');
1635
- this.parser_ = shaka.util.Functional.callFactory(this.parserFactory_);
1618
+ this.parser_ = this.parserFactory_();
1636
1619
 
1637
1620
  const manifestConfig =
1638
1621
  shaka.util.ObjectUtils.cloneObject(this.config_.manifest);
@@ -1918,13 +1901,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1918
1901
  const abrFactory = this.config_.abrFactory;
1919
1902
  if (!this.abrManager_ || this.abrManagerFactory_ != abrFactory) {
1920
1903
  this.abrManagerFactory_ = abrFactory;
1921
- this.abrManager_ = shaka.util.Functional.callFactory(abrFactory);
1922
- if (typeof this.abrManager_.playbackRateChanged != 'function') {
1923
- shaka.Deprecate.deprecateFeature(4,
1924
- 'AbrManager',
1925
- 'Please use an AbrManager with playbackRateChanged function.');
1926
- this.abrManager_.playbackRateChanged = (rate) => {};
1927
- }
1904
+ this.abrManager_ = abrFactory();
1928
1905
  this.abrManager_.configure(this.config_.abr);
1929
1906
  }
1930
1907
 
@@ -2683,8 +2660,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2683
2660
  this.manifest_,
2684
2661
  this.config_.streaming,
2685
2662
  startTime,
2686
- () => this.onSeek_(),
2687
- (event) => this.dispatchEvent(event));
2663
+ () => this.onSeek_());
2688
2664
  }
2689
2665
 
2690
2666
  /**
@@ -2943,17 +2919,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2943
2919
 
2944
2920
  goog.asserts.assert(typeof(config) == 'object', 'Should be an object!');
2945
2921
 
2946
- // Deprecate 'manifest.dash.defaultPresentationDelay' configuration.
2947
- if (config['manifest'] && config['manifest']['dash'] &&
2948
- 'defaultPresentationDelay' in config['manifest']['dash']) {
2949
- shaka.Deprecate.deprecateFeature(4,
2950
- 'manifest.dash.defaultPresentationDelay configuration',
2951
- 'Please Use manifest.defaultPresentationDelay instead.');
2952
- config['manifest']['defaultPresentationDelay'] =
2953
- config['manifest']['dash']['defaultPresentationDelay'];
2954
- delete config['manifest']['dash']['defaultPresentationDelay'];
2955
- }
2956
-
2957
2922
  // If lowLatencyMode is enabled, and inaccurateManifestTolerance and
2958
2923
  // rebufferingGoal are not specified, set inaccurateManifestTolerance to 0
2959
2924
  // and rebufferingGoal to 0.01 by default for low latency streaming.
@@ -3020,10 +2985,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3020
2985
  }
3021
2986
 
3022
2987
  if (this.mediaSourceEngine_) {
2988
+ const {segmentRelativeVttTiming} = this.config_.manifest;
2989
+ this.mediaSourceEngine_.setSegmentRelativeVttTiming(
2990
+ segmentRelativeVttTiming);
2991
+
3023
2992
  const textDisplayerFactory = this.config_.textDisplayFactory;
3024
2993
  if (this.lastTextFactory_ != textDisplayerFactory) {
3025
- const displayer =
3026
- shaka.util.Functional.callFactory(textDisplayerFactory);
2994
+ const displayer = textDisplayerFactory();
3027
2995
  this.mediaSourceEngine_.setTextDisplayer(displayer);
3028
2996
  this.lastTextFactory_ = textDisplayerFactory;
3029
2997
 
@@ -4408,158 +4376,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4408
4376
  return this.stats_.getBlob();
4409
4377
  }
4410
4378
 
4411
- /**
4412
- * Adds the given text track to the loaded manifest. <code>load()</code> must
4413
- * resolve before calling. The presentation must have a duration.
4414
- *
4415
- * This returns the created track, which can immediately be selected by the
4416
- * application. The track will not be automatically selected.
4417
- *
4418
- * @param {string} uri
4419
- * @param {string} language
4420
- * @param {string} kind
4421
- * @param {string=} mimeType
4422
- * @param {string=} codec
4423
- * @param {string=} label
4424
- * @param {boolean=} forced
4425
- * @return {shaka.extern.Track}
4426
- * @export
4427
- */
4428
- addTextTrack(uri, language, kind, mimeType, codec, label, forced = false) {
4429
- shaka.Deprecate.deprecateFeature(4,
4430
- 'addTextTrack',
4431
- 'Please use an addTextTrackAsync.');
4432
- if (this.loadMode_ != shaka.Player.LoadMode.MEDIA_SOURCE &&
4433
- this.loadMode_ != shaka.Player.LoadMode.SRC_EQUALS) {
4434
- shaka.log.error(
4435
- 'Must call load() and wait for it to resolve before adding text ' +
4436
- 'tracks.');
4437
- throw new shaka.util.Error(
4438
- shaka.util.Error.Severity.RECOVERABLE,
4439
- shaka.util.Error.Category.PLAYER,
4440
- shaka.util.Error.Code.CONTENT_NOT_LOADED);
4441
- }
4442
-
4443
- if (!mimeType) {
4444
- // Try using the uri extension.
4445
- const extension = shaka.media.ManifestParser.getExtension(uri);
4446
- mimeType = shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_[extension];
4447
-
4448
- if (!mimeType) {
4449
- shaka.log.error(
4450
- 'The mimeType has not been provided and it could not be deduced ' +
4451
- 'from its extension.');
4452
- throw new shaka.util.Error(
4453
- shaka.util.Error.Severity.RECOVERABLE,
4454
- shaka.util.Error.Category.TEXT,
4455
- shaka.util.Error.Code.TEXT_COULD_NOT_GUESS_MIME_TYPE,
4456
- extension);
4457
- }
4458
- }
4459
-
4460
- if (this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS) {
4461
- if (mimeType != 'text/vtt') {
4462
- shaka.log.error('Only WebVTT is supported when using src=');
4463
- throw new shaka.util.Error(
4464
- shaka.util.Error.Severity.RECOVERABLE,
4465
- shaka.util.Error.Category.TEXT,
4466
- shaka.util.Error.Code.TEXT_ONLY_WEBVTT_SRC_EQUALS,
4467
- mimeType);
4468
- }
4469
- if (forced) {
4470
- // See: https://github.com/whatwg/html/issues/4472
4471
- kind = 'forced';
4472
- }
4473
- const trackElement =
4474
- /** @type {!HTMLTrackElement} */(document.createElement('track'));
4475
- trackElement.src = this.cmcdManager_.appendTextTrackData(uri);
4476
- trackElement.label = label || '';
4477
- trackElement.kind = kind;
4478
- trackElement.srclang = language;
4479
- // Because we're pulling in the text track file via Javascript, the
4480
- // same-origin policy applies. If you'd like to have a player served
4481
- // from one domain, but the text track served from another, you'll
4482
- // need to enable CORS in order to do so. In addition to enabling CORS
4483
- // on the server serving the text tracks, you will need to add the
4484
- // crossorigin attribute to the video element itself.
4485
- if (!this.video_.getAttribute('crossorigin')) {
4486
- this.video_.setAttribute('crossorigin', 'anonymous');
4487
- }
4488
- this.video_.appendChild(trackElement);
4489
- const textTracks = this.getTextTracks();
4490
- const srcTrack = textTracks.find((t) => {
4491
- return t.language == language &&
4492
- t.label == (label || '') &&
4493
- t.kind == kind;
4494
- });
4495
- if (srcTrack) {
4496
- this.onTracksChanged_();
4497
- return srcTrack;
4498
- }
4499
- // This should not happen, but there are browser implementations that may
4500
- // not support the Track element.
4501
- shaka.log.error('Cannot add this text when loaded with src=');
4502
- throw new shaka.util.Error(
4503
- shaka.util.Error.Severity.RECOVERABLE,
4504
- shaka.util.Error.Category.TEXT,
4505
- shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_TEXT_TO_SRC_EQUALS);
4506
- }
4507
-
4508
- const ContentType = shaka.util.ManifestParserUtils.ContentType;
4509
-
4510
- const duration = this.manifest_.presentationTimeline.getDuration();
4511
- if (duration == Infinity) {
4512
- throw new shaka.util.Error(
4513
- shaka.util.Error.Severity.RECOVERABLE,
4514
- shaka.util.Error.Category.MANIFEST,
4515
- shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_TEXT_TO_LIVE_STREAM);
4516
- }
4517
-
4518
- /** @type {shaka.extern.Stream} */
4519
- const stream = {
4520
- id: this.nextExternalStreamId_++,
4521
- originalId: null,
4522
- createSegmentIndex: () => Promise.resolve(),
4523
- segmentIndex: shaka.media.SegmentIndex.forSingleSegment(
4524
- /* startTime= */ 0,
4525
- /* duration= */ duration,
4526
- /* uris= */ [uri]),
4527
- mimeType: mimeType || '',
4528
- codecs: codec || '',
4529
- kind: kind,
4530
- encrypted: false,
4531
- drmInfos: [],
4532
- keyIds: new Set(),
4533
- language: language,
4534
- label: label || null,
4535
- type: ContentType.TEXT,
4536
- primary: false,
4537
- trickModeVideo: null,
4538
- emsgSchemeIdUris: null,
4539
- roles: [],
4540
- forced: !!forced,
4541
- channelsCount: null,
4542
- audioSamplingRate: null,
4543
- spatialAudio: false,
4544
- closedCaptions: null,
4545
- };
4546
-
4547
- const fullMimeType = shaka.util.MimeUtils.getFullType(
4548
- stream.mimeType, stream.codecs);
4549
- const supported = shaka.text.TextEngine.isTypeSupported(fullMimeType);
4550
- if (!supported) {
4551
- throw new shaka.util.Error(
4552
- shaka.util.Error.Severity.CRITICAL,
4553
- shaka.util.Error.Category.TEXT,
4554
- shaka.util.Error.Code.MISSING_TEXT_PLUGIN,
4555
- mimeType);
4556
- }
4557
-
4558
- this.manifest_.textStreams.push(stream);
4559
- this.onTracksChanged_();
4560
- return shaka.util.StreamUtils.textStreamToTrack(stream);
4561
- }
4562
-
4563
4379
  /**
4564
4380
  * Adds the given text track to the loaded manifest. <code>load()</code> must
4565
4381
  * resolve before calling. The presentation must have a duration.
@@ -4864,6 +4680,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4864
4680
  periodStart: 0,
4865
4681
  segmentStart: 0,
4866
4682
  segmentEnd: this.video_.duration,
4683
+ vttOffset: 0,
4867
4684
  };
4868
4685
  const data = shaka.util.BufferUtils.toUint8(buffer);
4869
4686
  const cues = obj.parseMedia(data, time);
@@ -6516,7 +6333,6 @@ shaka.Player.EventName = {
6516
6333
  Emsg: 'emsg',
6517
6334
  Error: 'error',
6518
6335
  ExpirationUpdated: 'expirationupdated',
6519
- LargeGap: 'largegap',
6520
6336
  Loaded: 'loaded',
6521
6337
  Loading: 'loading',
6522
6338
  ManifestParsed: 'manifestparsed',
@@ -6576,7 +6392,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
6576
6392
  * @define {string} A version number taken from git at compile time.
6577
6393
  * @export
6578
6394
  */
6579
- shaka.Player.version = 'v3.3.4-uncompiled';
6395
+ shaka.Player.version = 'v4.0.0-uncompiled';
6580
6396
 
6581
6397
  // Initialize the deprecation system using the version string we just set
6582
6398
  // on the player.
@@ -24,8 +24,8 @@ shaka.polyfill.MediaCapabilities = class {
24
24
  * @export
25
25
  */
26
26
  static install() {
27
- // Since MediaCapabilities is not fully supported on Chromecast yet, we
28
- // should always install polyfill for Chromecast.
27
+ // Since MediaCapabilities is not fully supported on some Chromecast yet,
28
+ // we should always install polyfill for all Chromecast not Android-based.
29
29
  // TODO: re-evaluate MediaCapabilities in the future versions of Chromecast.
30
30
  // Since MediaCapabilities implementation is buggy in Apple browsers, we
31
31
  // should always install polyfill for Apple browsers.
@@ -37,10 +37,16 @@ shaka.polyfill.MediaCapabilities = class {
37
37
  // See: https://github.com/shaka-project/shaka-player/issues/3582
38
38
  // TODO: re-evaluate MediaCapabilities in the future versions of PS5
39
39
  // Browsers.
40
- if (!shaka.util.Platform.isChromecast() &&
41
- !shaka.util.Platform.isApple() &&
42
- !shaka.util.Platform.isPS5() &&
43
- navigator.mediaCapabilities) {
40
+ let canUseNativeMCap = true;
41
+ if (shaka.util.Platform.isApple() ||
42
+ shaka.util.Platform.isPS5() ||
43
+ shaka.util.Platform.isChromecast()) {
44
+ canUseNativeMCap = false;
45
+ }
46
+ if (shaka.util.Platform.isAndroidCastDevice()) {
47
+ canUseNativeMCap = true;
48
+ }
49
+ if (canUseNativeMCap && navigator.mediaCapabilities) {
44
50
  shaka.log.info(
45
51
  'MediaCapabilities: Native mediaCapabilities support found.');
46
52
  return;
@@ -38,11 +38,6 @@ shaka.polyfill.MediaSource = class {
38
38
  // Chromecast cannot make accurate determinations via isTypeSupported.
39
39
  shaka.polyfill.MediaSource.patchCastIsTypeSupported_();
40
40
  } else if (safariVersion) {
41
- // TS content is broken on Safari in general.
42
- // See https://github.com/shaka-project/shaka-player/issues/743
43
- // and https://bugs.webkit.org/show_bug.cgi?id=165342
44
- shaka.polyfill.MediaSource.rejectTsContent_();
45
-
46
41
  // NOTE: shaka.Player.isBrowserSupported() has its own restrictions on
47
42
  // Safari version.
48
43
  if (safariVersion <= 12) {
@@ -127,29 +122,6 @@ shaka.polyfill.MediaSource = class {
127
122
  };
128
123
  }
129
124
 
130
- /**
131
- * Patch isTypeSupported() to reject TS content. Used to avoid TS-related MSE
132
- * bugs on Safari.
133
- *
134
- * @private
135
- */
136
- static rejectTsContent_() {
137
- const originalIsTypeSupported = MediaSource.isTypeSupported;
138
-
139
- MediaSource.isTypeSupported = (mimeType) => {
140
- // Parse the basic MIME type from its parameters.
141
- const pieces = mimeType.split(/ *; */);
142
- const basicMimeType = pieces[0];
143
- const container = basicMimeType.split('/')[1];
144
-
145
- if (container.toLowerCase() == 'mp2t') {
146
- return false;
147
- }
148
-
149
- return originalIsTypeSupported(mimeType);
150
- };
151
- }
152
-
153
125
  /**
154
126
  * Patch |MediaSource.isTypeSupported| to always reject |codec|. This is used
155
127
  * when we know that we are on a platform that does not work well with a given
@@ -49,6 +49,8 @@ shaka.polyfill.PatchedMediaKeysNop = class {
49
49
  // These are not usable, but allow Player.isBrowserSupported to pass.
50
50
  window.MediaKeys = PatchedMediaKeysNop.MediaKeys;
51
51
  window.MediaKeySystemAccess = PatchedMediaKeysNop.MediaKeySystemAccess;
52
+
53
+ window.shakaMediaKeysPolyfill = true;
52
54
  }
53
55
 
54
56
  /**
@@ -72,6 +72,8 @@ shaka.polyfill.PatchedMediaKeysWebkit = class {
72
72
  PatchedMediaKeysWebkit.setMediaKeys;
73
73
  window.MediaKeys = PatchedMediaKeysWebkit.MediaKeys;
74
74
  window.MediaKeySystemAccess = PatchedMediaKeysWebkit.MediaKeySystemAccess;
75
+
76
+ window.shakaMediaKeysPolyfill = true;
75
77
  }
76
78
 
77
79
  /**
package/lib/text/cue.js CHANGED
@@ -234,12 +234,6 @@ shaka.text.Cue = class {
234
234
  */
235
235
  this.lineBreak = false;
236
236
 
237
- /**
238
- * @override
239
- * @exportInterface
240
- */
241
- this.spacer = false;
242
-
243
237
  /**
244
238
  * @override
245
239
  * @exportInterface
@@ -28,6 +28,14 @@ shaka.text.LrcTextParser = class {
28
28
  goog.asserts.assert(false, 'LRC does not have init segments');
29
29
  }
30
30
 
31
+ /**
32
+ * @override
33
+ * @export
34
+ */
35
+ setSequenceMode(sequenceMode) {
36
+ // Unused.
37
+ }
38
+
31
39
  /**
32
40
  * @override
33
41
  * @export
@@ -55,6 +55,14 @@ shaka.text.Mp4TtmlParser = class {
55
55
  }
56
56
  }
57
57
 
58
+ /**
59
+ * @override
60
+ * @export
61
+ */
62
+ setSequenceMode(sequenceMode) {
63
+ // Unused.
64
+ }
65
+
58
66
  /**
59
67
  * @override
60
68
  * @export
@@ -84,6 +84,14 @@ shaka.text.Mp4VttParser = class {
84
84
  }
85
85
  }
86
86
 
87
+ /**
88
+ * @override
89
+ * @export
90
+ */
91
+ setSequenceMode(sequenceMode) {
92
+ // Unused.
93
+ }
94
+
87
95
  /**
88
96
  * @override
89
97
  * @export
@@ -27,6 +27,14 @@ shaka.text.SbvTextParser = class {
27
27
  goog.asserts.assert(false, 'SubViewer does not have init segments');
28
28
  }
29
29
 
30
+ /**
31
+ * @override
32
+ * @export
33
+ */
34
+ setSequenceMode(sequenceMode) {
35
+ // Unused.
36
+ }
37
+
30
38
  /**
31
39
  * @override
32
40
  * @export
@@ -12,7 +12,6 @@
12
12
  goog.provide('shaka.text.SimpleTextDisplayer');
13
13
 
14
14
  goog.require('goog.asserts');
15
- goog.require('shaka.Deprecate');
16
15
  goog.require('shaka.log');
17
16
  goog.require('shaka.text.Cue');
18
17
 
@@ -108,12 +107,7 @@ shaka.text.SimpleTextDisplayer = class {
108
107
  return `${acc}</${tag}>`;
109
108
  }, '');
110
109
 
111
- if (cue.lineBreak || cue.spacer) {
112
- if (cue.spacer) {
113
- shaka.Deprecate.deprecateFeature(4,
114
- 'shaka.extern.Cue',
115
- 'Please use lineBreak instead of spacer.');
116
- }
110
+ if (cue.lineBreak) {
117
111
  // This is a vertical lineBreak, so insert a newline.
118
112
  return '\n';
119
113
  } else if (cue.nestedCues.length) {
@@ -35,6 +35,14 @@ shaka.text.SrtTextParser = class {
35
35
  goog.asserts.assert(false, 'SRT does not have init segments');
36
36
  }
37
37
 
38
+ /**
39
+ * @override
40
+ * @export
41
+ */
42
+ setSequenceMode(sequenceMode) {
43
+ // Unused.
44
+ }
45
+
38
46
  /**
39
47
  * @override
40
48
  * @export
@@ -28,6 +28,14 @@ shaka.text.SsaTextParser = class {
28
28
  goog.asserts.assert(false, 'SSA does not have init segments');
29
29
  }
30
30
 
31
+ /**
32
+ * @override
33
+ * @export
34
+ */
35
+ setSequenceMode(sequenceMode) {
36
+ // Unused.
37
+ }
38
+
31
39
  /**
32
40
  * @override
33
41
  * @export
@@ -7,9 +7,9 @@
7
7
  goog.provide('shaka.text.TextEngine');
8
8
 
9
9
  goog.require('goog.asserts');
10
+ goog.require('shaka.log');
10
11
  goog.require('shaka.text.Cue');
11
12
  goog.require('shaka.util.BufferUtils');
12
- goog.require('shaka.util.Functional');
13
13
  goog.require('shaka.util.IDestroyable');
14
14
  goog.require('shaka.util.MimeUtils');
15
15
  goog.requireType('shaka.cea.ICaptionDecoder');
@@ -30,6 +30,9 @@ shaka.text.TextEngine = class {
30
30
  /** @private {shaka.extern.TextDisplayer} */
31
31
  this.displayer_ = displayer;
32
32
 
33
+ /** @private {boolean} */
34
+ this.segmentRelativeVttTiming_ = false;
35
+
33
36
  /** @private {number} */
34
37
  this.timestampOffset_ = 0;
35
38
 
@@ -128,8 +131,10 @@ shaka.text.TextEngine = class {
128
131
  * called at least once before appendBuffer.
129
132
  *
130
133
  * @param {string} mimeType
134
+ * @param {boolean} sequenceMode
135
+ * @param {boolean} segmentRelativeVttTiming
131
136
  */
132
- initParser(mimeType) {
137
+ initParser(mimeType, sequenceMode, segmentRelativeVttTiming) {
133
138
  // No parser for CEA, which is extracted from video and side-loaded
134
139
  // into TextEngine and TextDisplayer.
135
140
  if (mimeType == shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE ||
@@ -140,7 +145,14 @@ shaka.text.TextEngine = class {
140
145
  const factory = shaka.text.TextEngine.parserMap_[mimeType];
141
146
  goog.asserts.assert(
142
147
  factory, 'Text type negotiation should have happened already');
143
- this.parser_ = shaka.util.Functional.callFactory(factory);
148
+ this.parser_ = factory();
149
+ if (this.parser_.setSequenceMode) {
150
+ this.parser_.setSequenceMode(sequenceMode);
151
+ } else {
152
+ shaka.log.alwaysWarn(
153
+ 'Text parsers should have a "setSequenceMode" method!');
154
+ }
155
+ this.segmentRelativeVttTiming_ = segmentRelativeVttTiming;
144
156
  }
145
157
 
146
158
  /**
@@ -166,11 +178,15 @@ shaka.text.TextEngine = class {
166
178
  return;
167
179
  }
168
180
 
181
+ const vttOffset = this.segmentRelativeVttTiming_ ?
182
+ startTime : this.timestampOffset_;
183
+
169
184
  /** @type {shaka.extern.TextParser.TimeContext} **/
170
185
  const time = {
171
186
  periodStart: this.timestampOffset_,
172
187
  segmentStart: startTime,
173
188
  segmentEnd: endTime,
189
+ vttOffset: vttOffset,
174
190
  };
175
191
 
176
192
  // Parse the buffer and add the new cues.
@@ -30,6 +30,14 @@ shaka.text.TtmlTextParser = class {
30
30
  goog.asserts.assert(false, 'TTML does not have init segments');
31
31
  }
32
32
 
33
+ /**
34
+ * @override
35
+ * @export
36
+ */
37
+ setSequenceMode(sequenceMode) {
38
+ // Unused.
39
+ }
40
+
33
41
  /**
34
42
  * @override
35
43
  * @export
@@ -8,7 +8,6 @@
8
8
  goog.provide('shaka.text.UITextDisplayer');
9
9
 
10
10
  goog.require('goog.asserts');
11
- goog.require('shaka.Deprecate');
12
11
  goog.require('shaka.text.Cue');
13
12
  goog.require('shaka.text.CueRegion');
14
13
  goog.require('shaka.util.Dom');
@@ -343,12 +342,7 @@ shaka.text.UITextDisplayer = class {
343
342
  createCue_(cue, parents) {
344
343
  const isNested = parents.length > 1;
345
344
  let type = isNested ? 'span' : 'div';
346
- if (cue.lineBreak || cue.spacer) {
347
- if (cue.spacer) {
348
- shaka.Deprecate.deprecateFeature(4,
349
- 'shaka.extern.Cue',
350
- 'Please use lineBreak instead of spacer.');
351
- }
345
+ if (cue.lineBreak) {
352
346
  type = 'br';
353
347
  }
354
348