shaka-player 4.12.9 → 4.13.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 (259) hide show
  1. package/AUTHORS +1 -0
  2. package/CONTRIBUTORS +4 -0
  3. package/README.md +22 -21
  4. package/cspell.config.yaml +18 -0
  5. package/dist/controls.css +1 -1
  6. package/dist/controls.css.map +1 -1
  7. package/dist/deps.js +29 -24
  8. package/dist/locales.js +36 -36
  9. package/dist/shaka-player.compiled.d.ts +131 -36
  10. package/dist/shaka-player.compiled.debug.d.ts +131 -36
  11. package/dist/shaka-player.compiled.debug.externs.js +355 -107
  12. package/dist/shaka-player.compiled.debug.js +799 -742
  13. package/dist/shaka-player.compiled.debug.map +4 -4
  14. package/dist/shaka-player.compiled.externs.js +355 -107
  15. package/dist/shaka-player.compiled.js +1456 -1423
  16. package/dist/shaka-player.compiled.map +4 -4
  17. package/dist/shaka-player.ui.d.ts +165 -38
  18. package/dist/shaka-player.ui.debug.d.ts +165 -38
  19. package/dist/shaka-player.ui.debug.externs.js +394 -113
  20. package/dist/shaka-player.ui.debug.js +808 -738
  21. package/dist/shaka-player.ui.debug.map +4 -4
  22. package/dist/shaka-player.ui.externs.js +394 -113
  23. package/dist/shaka-player.ui.js +1671 -1632
  24. package/dist/shaka-player.ui.map +4 -4
  25. package/eslint.config.mjs +343 -0
  26. package/externs/airplay.js +1 -1
  27. package/externs/audiotrack.js +1 -1
  28. package/externs/awesomplete.js +1 -1
  29. package/externs/cast-sdk-v2.js +2 -2
  30. package/externs/cmcd.js +16 -1
  31. package/externs/device_sensor_event.js +1 -1
  32. package/externs/ima.js +8 -8
  33. package/externs/isoboxer.js +31 -31
  34. package/externs/jwk_set.js +1 -1
  35. package/externs/lcevc.js +8 -8
  36. package/externs/mediakeys.js +1 -1
  37. package/externs/mediasession.js +3 -2
  38. package/externs/mediatailor.js +18 -18
  39. package/externs/pictureinpicture.js +41 -1
  40. package/externs/playstation.js +2 -2
  41. package/externs/prefixed_eme.js +1 -1
  42. package/externs/shaka/abortable.js +4 -4
  43. package/externs/shaka/abr_manager.js +1 -1
  44. package/externs/shaka/ads.js +45 -6
  45. package/externs/shaka/cea.js +2 -2
  46. package/externs/shaka/codecs.js +4 -4
  47. package/externs/shaka/drm_info.js +6 -6
  48. package/externs/shaka/error.js +5 -5
  49. package/externs/shaka/manifest.js +51 -56
  50. package/externs/shaka/manifest_parser.js +3 -9
  51. package/externs/shaka/net.js +23 -20
  52. package/externs/shaka/offline.js +37 -37
  53. package/externs/shaka/offline_compat_v1.js +10 -10
  54. package/externs/shaka/offline_compat_v2.js +10 -10
  55. package/externs/shaka/player.js +137 -108
  56. package/externs/shaka/text.js +3 -3
  57. package/externs/shaka/transmuxer.js +1 -1
  58. package/externs/videotrack.js +1 -1
  59. package/lib/abr/ewma.js +1 -1
  60. package/lib/abr/simple_abr_manager.js +70 -22
  61. package/lib/ads/ad_manager.js +43 -18
  62. package/lib/ads/ad_utils.js +160 -58
  63. package/lib/ads/ads_stats.js +1 -1
  64. package/lib/ads/client_side_ad_manager.js +2 -2
  65. package/lib/ads/interstitial_ad.js +16 -11
  66. package/lib/ads/interstitial_ad_manager.js +419 -72
  67. package/lib/ads/interstitial_static_ad.js +299 -0
  68. package/lib/ads/media_tailor_ad.js +1 -0
  69. package/lib/ads/media_tailor_ad_manager.js +37 -36
  70. package/lib/ads/server_side_ad_manager.js +7 -6
  71. package/lib/cast/cast_receiver.js +5 -3
  72. package/lib/cast/cast_sender.js +2 -2
  73. package/lib/cast/cast_utils.js +20 -13
  74. package/lib/cea/cea608_data_channel.js +53 -53
  75. package/lib/cea/cea708_service.js +34 -24
  76. package/lib/cea/cea708_window.js +5 -2
  77. package/lib/cea/cea_decoder.js +5 -7
  78. package/lib/cea/mp4_cea_parser.js +1 -1
  79. package/lib/cea/sei_processor.js +1 -1
  80. package/lib/dash/content_protection.js +62 -192
  81. package/lib/dash/dash_parser.js +98 -108
  82. package/lib/dash/mpd_utils.js +14 -13
  83. package/lib/dash/segment_base.js +5 -5
  84. package/lib/dash/segment_list.js +10 -10
  85. package/lib/dash/segment_template.js +14 -14
  86. package/lib/debug/log.js +2 -2
  87. package/lib/dependencies/all.js +2 -1
  88. package/lib/{media → drm}/drm_engine.js +274 -143
  89. package/lib/{util → drm}/drm_utils.js +20 -11
  90. package/lib/drm/playready.js +233 -0
  91. package/lib/hls/hls_classes.js +14 -14
  92. package/lib/hls/hls_parser.js +257 -196
  93. package/lib/hls/hls_utils.js +14 -14
  94. package/lib/hls/manifest_text_parser.js +10 -10
  95. package/lib/media/adaptation_set.js +6 -5
  96. package/lib/media/adaptation_set_criteria.js +51 -379
  97. package/lib/media/buffering_observer.js +5 -4
  98. package/lib/media/closed_caption_parser.js +2 -2
  99. package/lib/media/content_workarounds.js +2 -2
  100. package/lib/media/example_based_criteria.js +69 -0
  101. package/lib/media/manifest_filterer.js +8 -8
  102. package/lib/media/manifest_parser.js +2 -2
  103. package/lib/media/media_source_capabilities.js +20 -1
  104. package/lib/media/media_source_engine.js +71 -26
  105. package/lib/media/mp4_segment_index_parser.js +5 -5
  106. package/lib/media/playhead.js +2 -8
  107. package/lib/media/playhead_observer.js +1 -1
  108. package/lib/media/preference_based_criteria.js +333 -0
  109. package/lib/media/preload_manager.js +53 -37
  110. package/lib/media/presentation_timeline.js +2 -2
  111. package/lib/media/quality_observer.js +35 -35
  112. package/lib/media/region_observer.js +2 -2
  113. package/lib/media/region_timeline.js +3 -3
  114. package/lib/media/segment_index.js +14 -14
  115. package/lib/media/segment_prefetch.js +17 -13
  116. package/lib/media/segment_reference.js +7 -7
  117. package/lib/media/segment_utils.js +9 -9
  118. package/lib/media/streaming_engine.js +77 -38
  119. package/lib/media/time_ranges_utils.js +1 -1
  120. package/lib/media/video_wrapper.js +1 -1
  121. package/lib/media/webm_segment_index_parser.js +4 -4
  122. package/lib/mss/content_protection.js +17 -222
  123. package/lib/mss/mss_parser.js +23 -24
  124. package/lib/net/data_uri_plugin.js +1 -0
  125. package/lib/net/http_fetch_plugin.js +8 -7
  126. package/lib/net/http_plugin_utils.js +5 -2
  127. package/lib/net/http_xhr_plugin.js +4 -3
  128. package/lib/net/networking_engine.js +72 -17
  129. package/lib/net/networking_utils.js +5 -2
  130. package/lib/offline/download_info.js +5 -1
  131. package/lib/offline/download_manager.js +15 -4
  132. package/lib/offline/download_progress_estimator.js +1 -1
  133. package/lib/offline/indexeddb/base_storage_cell.js +9 -9
  134. package/lib/offline/indexeddb/db_connection.js +1 -1
  135. package/lib/offline/indexeddb/db_operation.js +2 -2
  136. package/lib/offline/indexeddb/eme_session_storage_cell.js +1 -1
  137. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  138. package/lib/offline/indexeddb/v1_storage_cell.js +3 -3
  139. package/lib/offline/indexeddb/v2_storage_cell.js +2 -2
  140. package/lib/offline/manifest_converter.js +11 -12
  141. package/lib/offline/offline_scheme.js +8 -4
  142. package/lib/offline/session_deleter.js +11 -11
  143. package/lib/offline/storage.js +137 -88
  144. package/lib/offline/storage_muxer.js +8 -8
  145. package/lib/offline/stored_content_utils.js +3 -3
  146. package/lib/offline/stream_bandwidth_estimator.js +1 -1
  147. package/lib/player.js +270 -207
  148. package/lib/polyfill/all.js +1 -1
  149. package/lib/polyfill/media_capabilities.js +5 -5
  150. package/lib/polyfill/patchedmediakeys_apple.js +6 -6
  151. package/lib/polyfill/patchedmediakeys_webkit.js +8 -8
  152. package/lib/polyfill/video_play_promise.js +0 -1
  153. package/lib/text/cue.js +3 -2
  154. package/lib/text/lrc_text_parser.js +1 -1
  155. package/lib/text/mp4_ttml_parser.js +1 -1
  156. package/lib/text/mp4_vtt_parser.js +3 -3
  157. package/lib/text/sbv_text_parser.js +1 -1
  158. package/lib/text/ssa_text_parser.js +3 -1
  159. package/lib/text/stub_text_displayer.js +5 -5
  160. package/lib/text/text_engine.js +5 -4
  161. package/lib/text/text_utils.js +4 -4
  162. package/lib/text/ttml_text_parser.js +21 -20
  163. package/lib/text/ui_text_displayer.js +13 -13
  164. package/lib/text/vtt_text_parser.js +10 -10
  165. package/lib/text/web_vtt_generator.js +2 -2
  166. package/lib/transmuxer/aac_transmuxer.js +2 -2
  167. package/lib/transmuxer/ac3_transmuxer.js +2 -2
  168. package/lib/transmuxer/adts.js +2 -0
  169. package/lib/transmuxer/ec3.js +3 -3
  170. package/lib/transmuxer/ec3_transmuxer.js +2 -2
  171. package/lib/transmuxer/h264.js +5 -5
  172. package/lib/transmuxer/h265.js +3 -3
  173. package/lib/transmuxer/mp3_transmuxer.js +2 -2
  174. package/lib/transmuxer/mpeg_audio.js +6 -6
  175. package/lib/transmuxer/mss_transmuxer.js +2 -0
  176. package/lib/transmuxer/transmuxer_engine.js +1 -1
  177. package/lib/transmuxer/ts_transmuxer.js +10 -10
  178. package/lib/util/abortable_operation.js +10 -10
  179. package/lib/util/array_utils.js +6 -6
  180. package/lib/util/cmcd_manager.js +149 -18
  181. package/lib/util/cmsd_manager.js +11 -11
  182. package/lib/util/config_utils.js +3 -3
  183. package/lib/util/content_steering_manager.js +17 -17
  184. package/lib/util/data_view_reader.js +3 -3
  185. package/lib/util/ebml_parser.js +1 -1
  186. package/lib/util/error.js +11 -6
  187. package/lib/util/event_manager.js +1 -1
  188. package/lib/util/exp_golomb.js +1 -1
  189. package/lib/util/fairplay_utils.js +6 -1
  190. package/lib/util/fake_event.js +3 -2
  191. package/lib/util/fake_event_target.js +1 -1
  192. package/lib/util/functional.js +8 -8
  193. package/lib/util/id3_utils.js +1 -1
  194. package/lib/util/iterables.js +6 -6
  195. package/lib/util/language_utils.js +17 -17
  196. package/lib/util/manifest_parser_utils.js +13 -13
  197. package/lib/util/map_utils.js +6 -6
  198. package/lib/util/media_ready_state_utils.js +1 -1
  199. package/lib/util/mime_utils.js +15 -4
  200. package/lib/util/mp4_box_parsers.js +5 -5
  201. package/lib/util/mp4_generator.js +31 -30
  202. package/lib/util/mp4_parser.js +2 -2
  203. package/lib/util/multi_map.js +5 -5
  204. package/lib/util/mutex.js +1 -1
  205. package/lib/util/networking.js +1 -1
  206. package/lib/util/object_utils.js +5 -1
  207. package/lib/util/operation_manager.js +1 -1
  208. package/lib/util/periods.js +24 -24
  209. package/lib/util/platform.js +8 -4
  210. package/lib/util/player_configuration.js +50 -17
  211. package/lib/util/pssh.js +34 -6
  212. package/lib/util/public_promise.js +2 -2
  213. package/lib/util/state_history.js +2 -2
  214. package/lib/util/stream_utils.js +138 -120
  215. package/lib/util/string_utils.js +4 -3
  216. package/lib/util/switch_history.js +2 -2
  217. package/lib/util/tXml.js +22 -17
  218. package/lib/util/text_parser.js +2 -2
  219. package/lib/util/timer.js +1 -1
  220. package/lib/util/ts_parser.js +22 -22
  221. package/lib/util/xml_utils.js +1 -0
  222. package/package.json +7 -4
  223. package/project-words.txt +485 -0
  224. package/shaka-player.uncompiled.js +1 -1
  225. package/third_party/closure-uri/uri.js +2 -2
  226. package/third_party/closure-uri/utils.js +2 -2
  227. package/third_party/language-mapping-list/language-mapping-list.js +1 -1
  228. package/ui/ad_statistics_button.js +9 -5
  229. package/ui/airplay_button.js +1 -0
  230. package/ui/audio_language_selection.js +2 -1
  231. package/ui/context_menu.js +2 -2
  232. package/ui/controls.js +7 -7
  233. package/ui/externs/ui.js +29 -21
  234. package/ui/externs/watermark.js +64 -0
  235. package/ui/fast_forward_button.js +1 -1
  236. package/ui/gl_matrix/matrix_4x4.js +11 -5
  237. package/ui/hidden_fast_forward_button.js +1 -1
  238. package/ui/hidden_seek_button.js +1 -1
  239. package/ui/language_utils.js +27 -26
  240. package/ui/less/buttons.less +2 -2
  241. package/ui/localization.js +21 -21
  242. package/ui/loop_button.js +2 -2
  243. package/ui/overflow_menu.js +2 -2
  244. package/ui/playback_rate_selection.js +1 -1
  245. package/ui/presentation_time.js +4 -1
  246. package/ui/range_element.js +2 -2
  247. package/ui/resolution_selection.js +42 -6
  248. package/ui/rewind_button.js +1 -1
  249. package/ui/seek_bar.js +5 -5
  250. package/ui/statistics_button.js +8 -4
  251. package/ui/text_selection.js +3 -2
  252. package/ui/ui.js +32 -2
  253. package/ui/vr_manager.js +3 -3
  254. package/ui/vr_utils.js +14 -14
  255. package/ui/vr_webgl.js +5 -5
  256. package/ui/watermark.js +313 -0
  257. package/.eslintignore +0 -4
  258. package/.eslintrc.js +0 -310
  259. package/lib/polyfill/patchedmediakeys_nop.js +0 -148
package/lib/player.js CHANGED
@@ -9,10 +9,11 @@ goog.provide('shaka.Player');
9
9
  goog.require('goog.asserts');
10
10
  goog.require('shaka.config.AutoShowText');
11
11
  goog.require('shaka.Deprecate');
12
+ goog.require('shaka.drm.DrmEngine');
13
+ goog.require('shaka.drm.DrmUtils');
12
14
  goog.require('shaka.log');
13
15
  goog.require('shaka.media.AdaptationSetCriteria');
14
16
  goog.require('shaka.media.BufferingObserver');
15
- goog.require('shaka.media.DrmEngine');
16
17
  goog.require('shaka.media.ExampleBasedCriteria');
17
18
  goog.require('shaka.media.ManifestFilterer');
18
19
  goog.require('shaka.media.ManifestParser');
@@ -22,7 +23,6 @@ goog.require('shaka.media.MetaSegmentIndex');
22
23
  goog.require('shaka.media.PlayRateController');
23
24
  goog.require('shaka.media.Playhead');
24
25
  goog.require('shaka.media.PlayheadObserverManager');
25
- goog.require('shaka.media.PreferenceBasedCriteria');
26
26
  goog.require('shaka.media.PreloadManager');
27
27
  goog.require('shaka.media.QualityObserver');
28
28
  goog.require('shaka.media.RegionObserver');
@@ -46,7 +46,6 @@ goog.require('shaka.util.CmcdManager');
46
46
  goog.require('shaka.util.CmsdManager');
47
47
  goog.require('shaka.util.ConfigUtils');
48
48
  goog.require('shaka.util.Dom');
49
- goog.require('shaka.util.DrmUtils');
50
49
  goog.require('shaka.util.Error');
51
50
  goog.require('shaka.util.EventManager');
52
51
  goog.require('shaka.util.FakeEvent');
@@ -106,6 +105,17 @@ goog.requireType('shaka.media.PresentationTimeline');
106
105
  */
107
106
 
108
107
 
108
+ /**
109
+ * @event shaka.Player.DownloadCompleted
110
+ * @description Fired when a download has completed.
111
+ * @property {string} type
112
+ * 'downloadcompleted'
113
+ * @property {!shaka.extern.Request} request
114
+ * @property {!shaka.extern.Response} response
115
+ * @exportDoc
116
+ */
117
+
118
+
109
119
  /**
110
120
  * @event shaka.Player.DownloadFailed
111
121
  * @description Fired when a download has failed, for any reason.
@@ -124,7 +134,7 @@ goog.requireType('shaka.media.PresentationTimeline');
124
134
  * a download, but before the body has been downloaded.
125
135
  * If the HTTP plugin being used does not track this information, this event
126
136
  * will default to being fired when the body is received, instead.
127
- * @property {!Object.<string, string>} headers
137
+ * @property {!Object<string, string>} headers
128
138
  * @property {!shaka.extern.Request} request
129
139
  * @property {!shaka.net.NetworkingEngine.RequestType} type
130
140
  * 'downloadheadersreceived'
@@ -642,7 +652,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
642
652
  /** @private {shaka.net.NetworkingEngine} */
643
653
  this.networkingEngine_ = null;
644
654
 
645
- /** @private {shaka.media.DrmEngine} */
655
+ /** @private {shaka.drm.DrmEngine} */
646
656
  this.drmEngine_ = null;
647
657
 
648
658
  /** @private {shaka.media.MediaSourceEngine} */
@@ -749,7 +759,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
749
759
  */
750
760
  this.nextExternalStreamId_ = 1e9;
751
761
 
752
- /** @private {!Array.<shaka.extern.Stream>} */
762
+ /** @private {!Array<shaka.extern.Stream>} */
753
763
  this.externalSrcEqualsThumbnailsStreams_ = [];
754
764
 
755
765
  /** @private {number} */
@@ -758,6 +768,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
758
768
  /** @private {?shaka.extern.PlayerConfiguration} */
759
769
  this.config_ = this.defaultConfig_();
760
770
 
771
+ /** @private {!Object} */
772
+ this.lowLatencyConfig_ =
773
+ shaka.util.PlayerConfiguration.createDefaultForLL();
774
+
761
775
  /** @private {?number} */
762
776
  this.currentTargetLatency_ = null;
763
777
 
@@ -781,7 +795,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
781
795
  this.manifestFilterer_ = new shaka.media.ManifestFilterer(
782
796
  this.config_, this.maxHwRes_, null);
783
797
 
784
- /** @private {!Array.<shaka.media.PreloadManager>} */
798
+ /** @private {!Array<shaka.media.PreloadManager>} */
785
799
  this.createdPreloadManagers_ = [];
786
800
 
787
801
  /** @private {shaka.util.Stats} */
@@ -789,17 +803,20 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
789
803
 
790
804
  /** @private {!shaka.media.AdaptationSetCriteria} */
791
805
  this.currentAdaptationSetCriteria_ =
792
- new shaka.media.PreferenceBasedCriteria(
793
- this.config_.preferredAudioLanguage,
794
- this.config_.preferredVariantRole,
795
- this.config_.preferredAudioChannelCount,
796
- this.config_.preferredVideoHdrLevel,
797
- this.config_.preferSpatialAudio,
798
- this.config_.preferredVideoLayout,
799
- this.config_.preferredAudioLabel,
800
- this.config_.preferredVideoLabel,
801
- this.config_.mediaSource.codecSwitchingStrategy,
802
- /* audioCodec= */ '');
806
+ this.config_.adaptationSetCriteriaFactory();
807
+ this.currentAdaptationSetCriteria_.configure({
808
+ language: this.config_.preferredAudioLanguage,
809
+ role: this.config_.preferredVariantRole,
810
+ channelCount: this.config_.preferredAudioChannelCount,
811
+ hdrLevel: this.config_.preferredVideoHdrLevel,
812
+ spatialAudio: this.config_.preferSpatialAudio,
813
+ videoLayout: this.config_.preferredVideoLayout,
814
+ audioLabel: this.config_.preferredAudioLabel,
815
+ videoLabel: this.config_.preferredVideoLabel,
816
+ codecSwitchingStrategy:
817
+ this.config_.mediaSource.codecSwitchingStrategy,
818
+ audioCodec: '',
819
+ });
803
820
 
804
821
  /** @private {string} */
805
822
  this.currentTextLanguage_ = this.config_.preferredTextLanguage;
@@ -810,7 +827,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
810
827
  /** @private {boolean} */
811
828
  this.currentTextForced_ = this.config_.preferForcedSubs;
812
829
 
813
- /** @private {!Array.<function():(!Promise|undefined)>} */
830
+ /** @private {!Array<function(): (!Promise | undefined)>} */
814
831
  this.cleanupOnUnload_ = [];
815
832
 
816
833
  if (dependencyInjector) {
@@ -976,7 +993,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
976
993
 
977
994
  /**
978
995
  * @param {!shaka.util.FakeEvent.EventName} name
979
- * @param {Map.<string, Object>=} data
996
+ * @param {Map<string, Object>=} data
980
997
  * @return {!shaka.util.FakeEvent}
981
998
  * @private
982
999
  */
@@ -1071,7 +1088,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1071
1088
 
1072
1089
  /**
1073
1090
  * Set a factory to create an ad manager during player construction time.
1074
- * This method needs to be called bafore instantiating the Player class.
1091
+ * This method needs to be called before instantiating the Player class.
1075
1092
  *
1076
1093
  * @param {!shaka.extern.IAdManager.Factory} factory
1077
1094
  * @export
@@ -1111,14 +1128,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1111
1128
  return false;
1112
1129
  }
1113
1130
 
1114
- // DRM support is not strictly necessary, but the APIs at least need to be
1115
- // there. Our no-op DRM polyfill should handle that.
1116
- // TODO(#1017): Consider making even DrmEngine optional.
1117
- const drmSupport = shaka.util.DrmUtils.isBrowserSupported();
1118
- if (!drmSupport) {
1119
- return false;
1120
- }
1121
-
1122
1131
  // If we have MediaSource (MSE) support, we should be able to use Shaka.
1123
1132
  if (shaka.util.Platform.supportsMediaSource()) {
1124
1133
  return true;
@@ -1139,7 +1148,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1139
1148
  *
1140
1149
  * @see https://bit.ly/2ywccmH
1141
1150
  * @param {boolean=} promptsOkay
1142
- * @return {!Promise.<shaka.extern.SupportType>}
1151
+ * @return {!Promise<shaka.extern.SupportType>}
1143
1152
  * @export
1144
1153
  */
1145
1154
  static async probeSupport(promptsOkay=true) {
@@ -1147,7 +1156,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1147
1156
  'Must have basic support');
1148
1157
  let drm = {};
1149
1158
  if (promptsOkay) {
1150
- drm = await shaka.media.DrmEngine.probeSupport();
1159
+ drm = await shaka.drm.DrmEngine.probeSupport();
1151
1160
  }
1152
1161
  const manifest = shaka.media.ManifestParser.probeSupport();
1153
1162
  const media = shaka.media.MediaSourceEngine.probeSupport();
@@ -1215,6 +1224,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1215
1224
  const onError = (error) => this.onVideoError_(error);
1216
1225
  this.attachEventManager_.listen(mediaElement, 'error', onError);
1217
1226
  this.video_ = mediaElement;
1227
+ if (this.cmcdManager_) {
1228
+ this.cmcdManager_.setMediaElement(mediaElement);
1229
+ }
1218
1230
  }
1219
1231
 
1220
1232
  // Only initialize media source if the platform supports it.
@@ -1290,7 +1302,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1290
1302
  * Meant for operations that can't be interrupted midway through (e.g.
1291
1303
  * everything but load).
1292
1304
  * @param {string} mutexIdentifier
1293
- * @return {!Promise.<boolean>} endEarly If false, the calling context will
1305
+ * @return {!Promise<boolean>} endEarly If false, the calling context will
1294
1306
  * need to release the mutex.
1295
1307
  * @private
1296
1308
  */
@@ -1510,7 +1522,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1510
1522
  // each playback.
1511
1523
  if (this.config_ && this.config_.streaming.clearDecodingCache) {
1512
1524
  shaka.util.StreamUtils.clearDecodingConfigCache();
1513
- shaka.util.DrmUtils.clearMediaKeySystemAccessMap();
1525
+ shaka.drm.DrmUtils.clearMediaKeySystemAccessMap();
1514
1526
  }
1515
1527
 
1516
1528
  this.manifest_ = null;
@@ -1525,6 +1537,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1525
1537
 
1526
1538
  this.completionPercent_ = -1;
1527
1539
 
1540
+ if (this.networkingEngine_) {
1541
+ this.networkingEngine_.clearCommonAccessTokenMap();
1542
+ }
1543
+
1528
1544
  // Make sure that the app knows of the new buffering state.
1529
1545
  this.updateBufferState_();
1530
1546
  } finally {
@@ -1856,7 +1872,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1856
1872
  *
1857
1873
  * @param {boolean=} initializeMediaSource
1858
1874
  * @param {boolean=} keepAdManager
1859
- * @return {!Promise.<?shaka.media.PreloadManager>}
1875
+ * @return {!Promise<?shaka.media.PreloadManager>}
1860
1876
  * @export
1861
1877
  */
1862
1878
  async unloadAndSavePreload(
@@ -1876,7 +1892,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1876
1892
  *
1877
1893
  * @param {boolean=} keepAdManager
1878
1894
  * @param {boolean=} saveLivePosition
1879
- * @return {!Promise.<?shaka.media.PreloadManager>}
1895
+ * @return {!Promise<?shaka.media.PreloadManager>}
1880
1896
  * @export
1881
1897
  */
1882
1898
  async detachAndSavePreload(keepAdManager = false, saveLivePosition = false) {
@@ -1887,7 +1903,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1887
1903
 
1888
1904
  /**
1889
1905
  * @param {boolean=} saveLivePosition
1890
- * @return {!Promise.<?shaka.media.PreloadManager>}
1906
+ * @return {!Promise<?shaka.media.PreloadManager>}
1891
1907
  * @private
1892
1908
  */
1893
1909
  async savePreload_(saveLivePosition = false) {
@@ -1950,7 +1966,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1950
1966
  * <code>undefined</code>, playback will start at the default start time (0
1951
1967
  * for VOD and liveEdge for LIVE).
1952
1968
  * @param {?string=} mimeType
1953
- * @return {!Promise.<?shaka.media.PreloadManager>}
1969
+ * @return {!Promise<?shaka.media.PreloadManager>}
1954
1970
  * @export
1955
1971
  */
1956
1972
  async preload(assetUri, startTime = null, mimeType) {
@@ -1987,7 +2003,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1987
2003
  * @param {?number} startTime
1988
2004
  * @param {?string=} mimeType
1989
2005
  * @param {boolean=} standardLoad
1990
- * @return {!Promise.<?shaka.media.PreloadManager>}
2006
+ * @return {!Promise<?shaka.media.PreloadManager>}
1991
2007
  * @private
1992
2008
  */
1993
2009
  async preloadInner_(assetUri, startTime, mimeType, standardLoad = false) {
@@ -2047,7 +2063,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2047
2063
  * @param {boolean=} allowPrefetch
2048
2064
  * @param {boolean=} disableVideo
2049
2065
  * @param {boolean=} allowMakeAbrManager
2050
- * @return {!Promise.<!shaka.media.PreloadManager>}
2066
+ * @return {!Promise<!shaka.media.PreloadManager>}
2051
2067
  * @private
2052
2068
  */
2053
2069
  async makePreloadManager_(assetUri, startTime, mimeType,
@@ -2077,14 +2093,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2077
2093
  }
2078
2094
  };
2079
2095
 
2080
- const setConfig = (name, value) => {
2081
- if (getPreloadManager()) {
2082
- preloadManager.configure(name, value);
2083
- } else {
2084
- this.configure(name, value);
2085
- }
2086
- };
2087
-
2088
2096
  // Avoid having to detect the resolution again if it has already been
2089
2097
  // detected or set
2090
2098
  if (this.maxHwRes_.width == Infinity &&
@@ -2124,10 +2132,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2124
2132
  onEvent: (event) => preloadManager.dispatchEvent(event),
2125
2133
  onError: (error) => preloadManager.onError(error),
2126
2134
  isLowLatencyMode: () => getConfig().streaming.lowLatencyMode,
2127
- isAutoLowLatencyMode: () => getConfig().streaming.autoLowLatencyMode,
2128
- enableLowLatencyMode: () => {
2129
- setConfig('streaming.lowLatencyMode', true);
2130
- },
2131
2135
  updateDuration: () => {
2132
2136
  if (this.streamingEngine_ && preloadManager.hasBeenAttached()) {
2133
2137
  this.streamingEngine_.updateDuration();
@@ -2270,7 +2274,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2270
2274
  const networkingEngine = this.createNetworkingEngine(getPreloadManager);
2271
2275
  this.networkingEngine_.copyFiltersInto(networkingEngine);
2272
2276
 
2273
- /** @return {!shaka.media.DrmEngine} */
2277
+ /** @return {!shaka.drm.DrmEngine} */
2274
2278
  const createDrmEngine = () => {
2275
2279
  return this.createDrmEngine(drmPlayerInterface);
2276
2280
  };
@@ -2296,7 +2300,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2296
2300
  * the loading process.
2297
2301
  *
2298
2302
  * @param {string} assetUri
2299
- * @return {!Promise.<?string>} mimeType
2303
+ * @return {!Promise<?string>} mimeType
2300
2304
  * @private
2301
2305
  */
2302
2306
  async guessMimeType_(assetUri) {
@@ -2360,7 +2364,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2360
2364
  // example, Android has native HLS, but we'd prefer our own MediaSource
2361
2365
  // version there.
2362
2366
  if (MimeUtils.isHlsType(mimeType)) {
2363
- // Native FairPlay HLS can be preferred on Apple platfforms.
2367
+ // Native FairPlay HLS can be preferred on Apple platforms.
2364
2368
  if (Platform.isApple() &&
2365
2369
  (this.config_.drm.servers['com.apple.fps'] ||
2366
2370
  this.config_.drm.servers['com.apple.fps.1_0'])) {
@@ -2371,6 +2375,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2371
2375
  return this.config_.streaming.preferNativeHls;
2372
2376
  }
2373
2377
 
2378
+ if (MimeUtils.isDashType(mimeType)) {
2379
+ // Native DASH can be preferred on any platform via this flag:
2380
+ return this.config_.streaming.preferNativeDash;
2381
+ }
2382
+
2374
2383
  // In all other cases, we prefer MediaSource.
2375
2384
  return false;
2376
2385
  }
@@ -2504,7 +2513,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2504
2513
 
2505
2514
  switch (track.kind) {
2506
2515
  case 'metadata':
2507
- this.processTimedMetadataSrcEqls_(track);
2516
+ this.processTimedMetadataSrcEquals_(track);
2508
2517
  break;
2509
2518
 
2510
2519
  case 'chapters':
@@ -2542,7 +2551,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2542
2551
  *
2543
2552
  * @param {number} startTimeOfLoad
2544
2553
  * @param {?shaka.extern.Variant} prefetchedVariant
2545
- * @param {!Map.<number, shaka.media.SegmentPrefetch>} segmentPrefetchById
2554
+ * @param {!Map<number, shaka.media.SegmentPrefetch>} segmentPrefetchById
2546
2555
  * @return {!Promise}
2547
2556
  * @private
2548
2557
  */
@@ -2633,16 +2642,21 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2633
2642
  this.parser_.onInitialVariantChosen(toLazyLoad);
2634
2643
  }
2635
2644
 
2636
- if (this.manifest_.isLowLatency && !this.config_.streaming.lowLatencyMode) {
2637
- shaka.log.alwaysWarn('Low-latency live stream detected, but ' +
2638
- 'low-latency streaming mode is not enabled in Shaka Player. ' +
2639
- 'Set streaming.lowLatencyMode configuration to true, and see ' +
2640
- 'https://bit.ly/3clctcj for details.');
2645
+ if (this.manifest_.isLowLatency) {
2646
+ if (this.config_.streaming.lowLatencyMode) {
2647
+ this.configure(this.lowLatencyConfig_);
2648
+ } else {
2649
+ shaka.log.alwaysWarn('Low-latency live stream detected, but ' +
2650
+ 'low-latency streaming mode is not enabled in Shaka Player. ' +
2651
+ 'Set streaming.lowLatencyMode configuration to true, and see ' +
2652
+ 'https://bit.ly/3clctcj for details.');
2653
+ }
2641
2654
  }
2642
2655
 
2643
2656
  if (this.cmcdManager_) {
2644
2657
  this.cmcdManager_.setLowLatency(
2645
2658
  this.manifest_.isLowLatency && this.config_.streaming.lowLatencyMode);
2659
+ this.cmcdManager_.setStartTimeOfLoad(startTimeOfLoad * 1000);
2646
2660
  }
2647
2661
 
2648
2662
  shaka.Player.applyPlayRange_(this.manifest_.presentationTimeline,
@@ -2657,13 +2671,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2657
2671
  this.playheadObservers_ =
2658
2672
  this.createPlayheadObserversForMSE_(startTime);
2659
2673
 
2660
- // We need to start the buffer management code near the end because it
2661
- // will set the initial buffering state and that depends on other
2662
- // components being initialized.
2663
- const rebufferThreshold = Math.max(
2664
- this.manifest_.minBufferTime,
2665
- this.config_.streaming.rebufferingGoal);
2666
- this.startBufferManagement_(mediaElement, rebufferThreshold);
2674
+ this.startBufferManagement_(
2675
+ mediaElement, this.config_.streaming.rebufferingGoal);
2667
2676
  };
2668
2677
 
2669
2678
  if (!this.config_.streaming.startAtSegmentBoundary) {
@@ -2677,7 +2686,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2677
2686
  // Now we can switch to the initial variant.
2678
2687
  if (!activeVariant) {
2679
2688
  goog.asserts.assert(initialVariant,
2680
- 'Must have choosen an initial variant!');
2689
+ 'Must have chosen an initial variant!');
2681
2690
 
2682
2691
  // Now that we have initial streams, we may adjust the start time to
2683
2692
  // align to a segment boundary.
@@ -3241,7 +3250,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3241
3250
  * @param {!TextTrack} track
3242
3251
  * @private
3243
3252
  */
3244
- processTimedMetadataSrcEqls_(track) {
3253
+ processTimedMetadataSrcEquals_(track) {
3245
3254
  if (track.kind != 'metadata') {
3246
3255
  return;
3247
3256
  }
@@ -3260,7 +3269,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3260
3269
  }
3261
3270
  }
3262
3271
  if (track.cues) {
3263
- /** @type {!Array.<shaka.extern.HLSInterstitial>} */
3272
+ /** @type {!Array<shaka.extern.HLSInterstitial>} */
3264
3273
  const interstitials = [];
3265
3274
 
3266
3275
  for (const cue of track.cues) {
@@ -3322,7 +3331,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3322
3331
 
3323
3332
 
3324
3333
  /**
3325
- * @param {!Array.<shaka.extern.ID3Metadata>} metadata
3334
+ * @param {!Array<shaka.extern.ID3Metadata>} metadata
3326
3335
  * @param {number} offset
3327
3336
  * @param {?number} segmentEndTime
3328
3337
  * @private
@@ -3411,11 +3420,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3411
3420
  * fake instances. Configuration and initialization will be handled after
3412
3421
  * |createDrmEngine|.
3413
3422
  *
3414
- * @param {shaka.media.DrmEngine.PlayerInterface} playerInterface
3415
- * @return {!shaka.media.DrmEngine}
3423
+ * @param {shaka.drm.DrmEngine.PlayerInterface} playerInterface
3424
+ * @return {!shaka.drm.DrmEngine}
3416
3425
  */
3417
3426
  createDrmEngine(playerInterface) {
3418
- return new shaka.media.DrmEngine(playerInterface);
3427
+ return new shaka.drm.DrmEngine(playerInterface);
3419
3428
  }
3420
3429
 
3421
3430
  /**
@@ -3492,6 +3501,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3492
3501
  }
3493
3502
  });
3494
3503
  };
3504
+ /** @type {shaka.net.NetworkingEngine.OnDownloadCompleted} */
3505
+ const onDownloadCompleted_ = (request, response) => {
3506
+ // Release a 'downloadcompleted' event.
3507
+ const name = shaka.util.FakeEvent.EventName.DownloadCompleted;
3508
+ const data = new Map()
3509
+ .set('request', request)
3510
+ .set('response', response);
3511
+ dispatchEvent(shaka.Player.makeEvent_(name, data));
3512
+ };
3495
3513
  /** @type {shaka.net.NetworkingEngine.OnDownloadFailed} */
3496
3514
  const onDownloadFailed_ = (request, error, httpResponseCode, aborted) => {
3497
3515
  // Release a 'downloadfailed' event.
@@ -3533,8 +3551,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3533
3551
  };
3534
3552
 
3535
3553
  return new shaka.net.NetworkingEngine(
3536
- onProgressUpdated_, onHeadersReceived_, onDownloadFailed_, onRequest_,
3537
- onRetry_, onResponse_);
3554
+ onProgressUpdated_, onHeadersReceived_, onDownloadCompleted_,
3555
+ onDownloadFailed_, onRequest_, onRetry_, onResponse_);
3538
3556
  }
3539
3557
 
3540
3558
  /**
@@ -3642,7 +3660,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3642
3660
 
3643
3661
  this.bufferPoller_ = new shaka.util.Timer(() => {
3644
3662
  this.pollBufferState_();
3645
- }).tickEvery(/* seconds= */ 0.25);
3663
+ });
3664
+ if (this.config_.streaming.rebufferingGoal) {
3665
+ this.bufferPoller_.tickEvery(/* seconds= */ 0.25);
3666
+ }
3646
3667
  this.loadEventManager_.listen(mediaElement, 'waiting',
3647
3668
  (e) => this.pollBufferState_());
3648
3669
  this.loadEventManager_.listen(mediaElement, 'stalled',
@@ -3651,6 +3672,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3651
3672
  (e) => this.pollBufferState_());
3652
3673
  this.loadEventManager_.listen(mediaElement, 'progress',
3653
3674
  (e) => this.pollBufferState_());
3675
+ this.loadEventManager_.listen(mediaElement, 'seeked',
3676
+ (e) => this.pollBufferState_());
3654
3677
  }
3655
3678
 
3656
3679
  /**
@@ -3750,6 +3773,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3750
3773
  getNetworkingEngine: () => this.getNetworkingEngine(),
3751
3774
  getVariantTracks: () => this.getVariantTracks(),
3752
3775
  isLive: () => this.isLive(),
3776
+ getLiveLatency: () => this.getLiveLatency(),
3753
3777
  };
3754
3778
 
3755
3779
  return new shaka.util.CmcdManager(playerInterface, this.config_.cmcd);
@@ -4037,60 +4061,47 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4037
4061
  delete config['streaming']['dispatchAllEmsgBoxes'];
4038
4062
  }
4039
4063
 
4040
- // If lowLatencyMode is enabled, and inaccurateManifestTolerance and
4041
- // rebufferingGoal and segmentPrefetchLimit and baseDelay and
4042
- // autoCorrectDrift and maxDisabledTime are not specified, set
4043
- // inaccurateManifestTolerance to 0 and rebufferingGoal to 0.01 and
4044
- // segmentPrefetchLimit to 2 and updateIntervalSeconds to 0.1 and and
4045
- // baseDelay to 100 and autoCorrectDrift to false and maxDisabledTime
4046
- // to 1 by default for low latency streaming.
4047
- if (config['streaming'] && config['streaming']['lowLatencyMode']) {
4048
- if (config['streaming']['inaccurateManifestTolerance'] == undefined) {
4049
- config['streaming']['inaccurateManifestTolerance'] = 0;
4050
- }
4051
- if (config['streaming']['rebufferingGoal'] == undefined) {
4052
- config['streaming']['rebufferingGoal'] = 0.01;
4053
- }
4054
- if (config['streaming']['segmentPrefetchLimit'] == undefined) {
4055
- config['streaming']['segmentPrefetchLimit'] = 2;
4056
- }
4057
- if (config['streaming']['updateIntervalSeconds'] == undefined) {
4058
- config['streaming']['updateIntervalSeconds'] = 0.1;
4059
- }
4060
- if (config['streaming']['maxDisabledTime'] == undefined) {
4061
- config['streaming']['maxDisabledTime'] = 1;
4062
- }
4063
- if (config['streaming']['retryParameters'] == undefined) {
4064
- config['streaming']['retryParameters'] = {};
4065
- }
4066
- if (config['streaming']['retryParameters']['baseDelay'] == undefined) {
4067
- config['streaming']['retryParameters']['baseDelay'] = 100;
4068
- }
4069
- if (config['manifest'] == undefined) {
4070
- config['manifest'] = {};
4071
- }
4072
- if (config['manifest']['dash'] == undefined) {
4073
- config['manifest']['dash'] = {};
4074
- }
4075
- if (config['manifest']['dash']['autoCorrectDrift'] == undefined) {
4076
- config['manifest']['dash']['autoCorrectDrift'] = false;
4077
- }
4078
- if (config['manifest']['retryParameters'] == undefined) {
4079
- config['manifest']['retryParameters'] = {};
4080
- }
4081
- if (config['manifest']['retryParameters']['baseDelay'] == undefined) {
4082
- config['manifest']['retryParameters']['baseDelay'] = 100;
4083
- }
4084
- if (config['drm'] == undefined) {
4085
- config['drm'] = {};
4086
- }
4087
- if (config['drm']['retryParameters'] == undefined) {
4088
- config['drm']['retryParameters'] = {};
4064
+ // Deprecate 'streaming.autoLowLatencyMode' configuration.
4065
+ if (config['streaming'] && 'autoLowLatencyMode' in config['streaming']) {
4066
+ shaka.Deprecate.deprecateFeature(5,
4067
+ 'streaming.autoLowLatencyMode configuration',
4068
+ 'Please Use streaming.lowLatencyMode instead.');
4069
+ config['streaming']['lowLatencyMode'] =
4070
+ config['streaming']['autoLowLatencyMode'];
4071
+ delete config['streaming']['autoLowLatencyMode'];
4072
+ }
4073
+
4074
+ // Deprecate AdvancedDrmConfiguration's videoRobustness and audioRobustness
4075
+ // as a string. It's now an array of strings.
4076
+ if (config['drm'] && config['drm']['advanced']) {
4077
+ let fixedUp = false;
4078
+ for (const keySystem in config['drm']['advanced']) {
4079
+ const {videoRobustness, audioRobustness} =
4080
+ config['drm']['advanced'][keySystem];
4081
+ if ('videoRobustness' in config['drm']['advanced'][keySystem] &&
4082
+ !Array.isArray(
4083
+ config['drm']['advanced'][keySystem]['videoRobustness'])) {
4084
+ config['drm']['advanced'][keySystem]['videoRobustness'] =
4085
+ [videoRobustness];
4086
+ fixedUp = true;
4087
+ }
4088
+ if ('audioRobustness' in config['drm']['advanced'][keySystem] &&
4089
+ !Array.isArray(
4090
+ config['drm']['advanced'][keySystem]['audioRobustness'])) {
4091
+ config['drm']['advanced'][keySystem]['audioRobustness'] =
4092
+ [audioRobustness];
4093
+ fixedUp = true;
4094
+ }
4089
4095
  }
4090
- if (config['drm']['retryParameters']['baseDelay'] == undefined) {
4091
- config['drm']['retryParameters']['baseDelay'] = 100;
4096
+
4097
+ if (fixedUp) {
4098
+ shaka.Deprecate.deprecateFeature(5,
4099
+ 'AdvancedDrmConfiguration\'s videoRobustness and audioRobustness',
4100
+ 'These properties are no longer strings but array of strings, ' +
4101
+ 'please update your usage of these properties.');
4092
4102
  }
4093
4103
  }
4104
+
4094
4105
  const ret = shaka.util.PlayerConfiguration.mergeConfigObjects(
4095
4106
  this.config_, config, this.defaultConfig_());
4096
4107
 
@@ -4098,6 +4109,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4098
4109
  return ret;
4099
4110
  }
4100
4111
 
4112
+ /**
4113
+ * Changes low latency configuration settings on the Player.
4114
+ *
4115
+ * @param {!Object} config This object should follow the
4116
+ * {@link shaka.extern.PlayerConfiguration} object. Not all fields
4117
+ * need to be set; unset fields retain their old values.
4118
+ * @export
4119
+ */
4120
+ configurationForLowLatency(config) {
4121
+ this.lowLatencyConfig_ = config;
4122
+ }
4123
+
4101
4124
  /**
4102
4125
  * Apply config changes.
4103
4126
  * @private
@@ -4210,12 +4233,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4210
4233
  this.onAbrStatusChanged_();
4211
4234
  }
4212
4235
  if (this.bufferObserver_) {
4213
- let rebufferThreshold = this.config_.streaming.rebufferingGoal;
4214
- if (this.manifest_) {
4215
- rebufferThreshold =
4216
- Math.max(rebufferThreshold, this.manifest_.minBufferTime);
4236
+ this.updateBufferingSettings_(this.config_.streaming.rebufferingGoal);
4237
+ }
4238
+ if (this.bufferPoller_) {
4239
+ if (!this.config_.streaming.rebufferingGoal) {
4240
+ this.bufferPoller_.stop();
4241
+ } else {
4242
+ this.bufferPoller_.tickEvery(/* seconds= */ 0.25);
4217
4243
  }
4218
- this.updateBufferingSettings_(rebufferThreshold);
4219
4244
  }
4220
4245
 
4221
4246
  if (this.manifest_) {
@@ -4251,6 +4276,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4251
4276
  return ret;
4252
4277
  }
4253
4278
 
4279
+ /**
4280
+ * Return a copy of the current configuration for low latency.
4281
+ *
4282
+ * @return {!Object}
4283
+ * @export
4284
+ */
4285
+ getConfigurationForLowLatency() {
4286
+ return this.lowLatencyConfig_;
4287
+ }
4288
+
4254
4289
  /**
4255
4290
  * Return a copy of the current non default configuration. Modifications of
4256
4291
  * the returned value will not affect the Player's active configuration.
@@ -4561,7 +4596,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4561
4596
  * @export
4562
4597
  */
4563
4598
  keySystem() {
4564
- return shaka.util.DrmUtils.keySystem(this.drmInfo());
4599
+ return shaka.drm.DrmUtils.keySystem(this.drmInfo());
4565
4600
  }
4566
4601
 
4567
4602
  /**
@@ -4582,7 +4617,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4582
4617
  * This method should only be used for testing. Applications SHOULD NOT
4583
4618
  * use this in production.
4584
4619
  *
4585
- * @return {?shaka.media.DrmEngine}
4620
+ * @return {?shaka.drm.DrmEngine}
4586
4621
  */
4587
4622
  getDrmEngine() {
4588
4623
  return this.drmEngine_;
@@ -4605,7 +4640,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4605
4640
  /**
4606
4641
  * Returns the active sessions metadata
4607
4642
  *
4608
- * @return {!Array.<shaka.extern.DrmSessionMetadata>}
4643
+ * @return {!Array<shaka.extern.DrmSessionMetadata>}
4609
4644
  * @export
4610
4645
  */
4611
4646
  getActiveSessionsMetadata() {
@@ -4745,7 +4780,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4745
4780
  * <p>
4746
4781
  * If the player has not loaded content, this will return an empty list.
4747
4782
  *
4748
- * @return {!Array.<shaka.extern.Track>}
4783
+ * @return {!Array<shaka.extern.Track>}
4749
4784
  * @export
4750
4785
  */
4751
4786
  getVariantTracks() {
@@ -4801,7 +4836,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4801
4836
  * <p>
4802
4837
  * If the player has not loaded content, this will return an empty list.
4803
4838
  *
4804
- * @return {!Array.<shaka.extern.Track>}
4839
+ * @return {!Array<shaka.extern.Track>}
4805
4840
  * @export
4806
4841
  */
4807
4842
  getTextTracks() {
@@ -4833,7 +4868,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4833
4868
  *
4834
4869
  * If the player has not loaded content, this will return an empty list.
4835
4870
  *
4836
- * @return {!Array.<shaka.extern.Track>}
4871
+ * @return {!Array<shaka.extern.Track>}
4837
4872
  * @export
4838
4873
  */
4839
4874
  getImageTracks() {
@@ -4851,7 +4886,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4851
4886
  * If the player has not loaded content, this will return a null.
4852
4887
  *
4853
4888
  * @param {number} trackId
4854
- * @return {!Promise.<?Array<!shaka.extern.Thumbnail>>}
4889
+ * @return {!Promise<?Array<!shaka.extern.Thumbnail>>}
4855
4890
  * @export
4856
4891
  */
4857
4892
  async getAllThumbnails(trackId) {
@@ -4922,7 +4957,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4922
4957
  *
4923
4958
  * @param {number} trackId
4924
4959
  * @param {number} time
4925
- * @return {!Promise.<?shaka.extern.Thumbnail>}
4960
+ * @return {!Promise<?shaka.extern.Thumbnail>}
4926
4961
  * @export
4927
4962
  */
4928
4963
  async getThumbnails(trackId, time) {
@@ -5155,8 +5190,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5155
5190
  active.audio.channelsCount == variant.audio.channelsCount))) {
5156
5191
  shaka.log.alwaysWarn('Changing tracks while abr manager is enabled ' +
5157
5192
  'will likely result in the selected track ' +
5158
- 'being overriden. Consider disabling abr before ' +
5159
- 'calling selectVariantTrack().');
5193
+ 'being overridden. Consider disabling abr ' +
5194
+ 'before calling selectVariantTrack().');
5160
5195
  }
5161
5196
 
5162
5197
  if (this.isRemotePlayback()) {
@@ -5175,7 +5210,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5175
5210
  // currentAudioLanguage_.
5176
5211
  this.currentAdaptationSetCriteria_ = new shaka.media.ExampleBasedCriteria(
5177
5212
  variant,
5178
- this.config_.mediaSource.codecSwitchingStrategy);
5213
+ this.config_.mediaSource.codecSwitchingStrategy,
5214
+ this.config_.adaptationSetCriteriaFactory);
5179
5215
 
5180
5216
  // Update AbrManager variants to match these new settings.
5181
5217
  this.updateAbrManagerVariants_();
@@ -5209,7 +5245,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5209
5245
  * Return a list of audio language-role combinations available. If the
5210
5246
  * player has not loaded any content, this will return an empty list.
5211
5247
  *
5212
- * @return {!Array.<shaka.extern.LanguageRole>}
5248
+ * @return {!Array<shaka.extern.LanguageRole>}
5213
5249
  * @export
5214
5250
  */
5215
5251
  getAudioLanguagesAndRoles() {
@@ -5220,7 +5256,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5220
5256
  * Return a list of text language-role combinations available. If the player
5221
5257
  * has not loaded any content, this will be return an empty list.
5222
5258
  *
5223
- * @return {!Array.<shaka.extern.LanguageRole>}
5259
+ * @return {!Array<shaka.extern.LanguageRole>}
5224
5260
  * @export
5225
5261
  */
5226
5262
  getTextLanguagesAndRoles() {
@@ -5231,7 +5267,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5231
5267
  * Return a list of audio languages available. If the player has not loaded
5232
5268
  * any content, this will return an empty list.
5233
5269
  *
5234
- * @return {!Array.<string>}
5270
+ * @return {!Array<string>}
5235
5271
  * @export
5236
5272
  */
5237
5273
  getAudioLanguages() {
@@ -5242,7 +5278,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5242
5278
  * Return a list of text languages available. If the player has not loaded
5243
5279
  * any content, this will return an empty list.
5244
5280
  *
5245
- * @return {!Array.<string>}
5281
+ * @return {!Array<string>}
5246
5282
  * @export
5247
5283
  */
5248
5284
  getTextLanguages() {
@@ -5266,17 +5302,20 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5266
5302
  codec = '', spatialAudio = false) {
5267
5303
  const selectMediaSourceMode = () => {
5268
5304
  this.currentAdaptationSetCriteria_ =
5269
- new shaka.media.PreferenceBasedCriteria(
5270
- language,
5271
- role || '',
5272
- channelsCount || 0,
5273
- /* hdrLevel= */ '',
5274
- spatialAudio || false,
5275
- /* videoLayout= */ '',
5276
- /* audioLabel= */ '',
5277
- /* videoLabel= */ '',
5278
- this.config_.mediaSource.codecSwitchingStrategy,
5279
- codec || '');
5305
+ this.config_.adaptationSetCriteriaFactory();
5306
+ this.currentAdaptationSetCriteria_.configure({
5307
+ language,
5308
+ role: role || '',
5309
+ channelCount: channelsCount || 0,
5310
+ hdrLevel: '',
5311
+ spatialAudio: spatialAudio || false,
5312
+ videoLayout: '',
5313
+ audioLabel: '',
5314
+ videoLabel: '',
5315
+ codecSwitchingStrategy:
5316
+ this.config_.mediaSource.codecSwitchingStrategy,
5317
+ audioCodec: codec || '',
5318
+ });
5280
5319
 
5281
5320
  const diff = (a, b) => {
5282
5321
  if (!a.video && !b.video) {
@@ -5423,17 +5462,21 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5423
5462
  // Because of that we assume that all the variants with the same
5424
5463
  // label have the same language.
5425
5464
  this.currentAdaptationSetCriteria_ =
5426
- new shaka.media.PreferenceBasedCriteria(
5427
- firstVariantWithLabel.language,
5428
- /* role= */ '',
5429
- /* channelCount= */ 0,
5430
- /* hdrLevel= */ '',
5431
- /* spatialAudio= */ false,
5432
- /* videoLayout= */ '',
5433
- label,
5434
- /* videoLabel= */ '',
5435
- this.config_.mediaSource.codecSwitchingStrategy,
5436
- /* audioCodec= */ '');
5465
+ this.config_.adaptationSetCriteriaFactory();
5466
+ this.currentAdaptationSetCriteria_.configure({
5467
+ language: firstVariantWithLabel.language,
5468
+ role: '',
5469
+ channelCount: 0,
5470
+ hdrLevel: '',
5471
+ spatialAudio: false,
5472
+ videoLayout: '',
5473
+ label,
5474
+ videoLabel: '',
5475
+ audioLabel: '',
5476
+ codecSwitchingStrategy:
5477
+ this.config_.mediaSource.codecSwitchingStrategy,
5478
+ audioCodec: '',
5479
+ });
5437
5480
 
5438
5481
  this.chooseVariantAndSwitch_(clearBuffer, safeMargin);
5439
5482
  };
@@ -5488,7 +5531,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5488
5531
  /**
5489
5532
  * Return a list of chapters tracks.
5490
5533
  *
5491
- * @return {!Array.<shaka.extern.Track>}
5534
+ * @return {!Array<shaka.extern.Track>}
5492
5535
  * @export
5493
5536
  */
5494
5537
  getChaptersTracks() {
@@ -5505,7 +5548,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5505
5548
  * This returns the list of chapters.
5506
5549
  *
5507
5550
  * @param {string} language
5508
- * @return {!Array.<shaka.extern.Chapter>}
5551
+ * @return {!Array<shaka.extern.Chapter>}
5509
5552
  * @export
5510
5553
  */
5511
5554
  getChapters(language) {
@@ -5513,10 +5556,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5513
5556
  return [];
5514
5557
  }
5515
5558
  const LanguageUtils = shaka.util.LanguageUtils;
5516
- const inputlanguage = LanguageUtils.normalize(language);
5559
+ const inputLanguage = LanguageUtils.normalize(language);
5517
5560
  const chaptersTracks = this.getChaptersTracks_();
5518
5561
  const chaptersTracksWithLanguage = chaptersTracks
5519
- .filter((t) => LanguageUtils.normalize(t.language) == inputlanguage);
5562
+ .filter((t) => LanguageUtils.normalize(t.language) == inputLanguage);
5520
5563
  if (!chaptersTracksWithLanguage || !chaptersTracksWithLanguage.length) {
5521
5564
  return [];
5522
5565
  }
@@ -5550,7 +5593,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5550
5593
  * Ignore the TextTracks with the 'metadata' or 'chapters' kind, or the one
5551
5594
  * generated by the SimpleTextDisplayer.
5552
5595
  *
5553
- * @return {!Array.<TextTrack>}
5596
+ * @return {!Array<TextTrack>}
5554
5597
  * @private
5555
5598
  */
5556
5599
  getFilteredTextTracks_() {
@@ -5564,7 +5607,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5564
5607
  /**
5565
5608
  * Get the TextTracks with the 'metadata' kind.
5566
5609
  *
5567
- * @return {!Array.<TextTrack>}
5610
+ * @return {!Array<TextTrack>}
5568
5611
  * @private
5569
5612
  */
5570
5613
  getMetadataTracks_() {
@@ -5577,7 +5620,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5577
5620
  /**
5578
5621
  * Get the TextTracks with the 'chapters' kind.
5579
5622
  *
5580
- * @return {!Array.<TextTrack>}
5623
+ * @return {!Array<TextTrack>}
5581
5624
  * @private
5582
5625
  */
5583
5626
  getChaptersTracks_() {
@@ -5595,11 +5638,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5595
5638
  * @export
5596
5639
  */
5597
5640
  setTextTrackVisibility(isVisible) {
5598
- const oldVisibilty = this.isTextVisible_;
5641
+ const oldVisibility = this.isTextVisible_;
5599
5642
  // Convert to boolean in case apps pass 0/1 instead false/true.
5600
5643
  const newVisibility = !!isVisible;
5601
5644
 
5602
- if (oldVisibilty == newVisibility) {
5645
+ if (oldVisibility == newVisibility) {
5603
5646
  return;
5604
5647
  }
5605
5648
 
@@ -5772,6 +5815,22 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5772
5815
  return info;
5773
5816
  }
5774
5817
 
5818
+ /**
5819
+ * Get latency in milliseconds between the live edge and what's currently
5820
+ * playing.
5821
+ *
5822
+ * @return {?number} The latency in milliseconds, or null if nothing
5823
+ * is playing.
5824
+ */
5825
+ getLiveLatency() {
5826
+ if (!this.video_) {
5827
+ return null;
5828
+ }
5829
+ const now = this.getPresentationStartTimeAsDate().getTime() +
5830
+ this.video_.currentTime * 1000;
5831
+ return Date.now() - now;
5832
+ }
5833
+
5775
5834
  /**
5776
5835
  * Get statistics for the current playback session. If the player is not
5777
5836
  * playing content, this will return an empty stats object.
@@ -5841,10 +5900,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5841
5900
  }
5842
5901
 
5843
5902
  if (this.isLive()) {
5844
- const now = this.getPresentationStartTimeAsDate().valueOf() +
5845
- element.currentTime * 1000;
5846
- const latency = (Date.now() - now) / 1000;
5847
- this.stats_.setLiveLatency(latency);
5903
+ const latency = this.getLiveLatency() || 0;
5904
+ this.stats_.setLiveLatency(latency / 1000);
5848
5905
  }
5849
5906
 
5850
5907
  if (this.manifest_) {
@@ -5885,7 +5942,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5885
5942
  * @param {string=} codec
5886
5943
  * @param {string=} label
5887
5944
  * @param {boolean=} forced
5888
- * @return {!Promise.<shaka.extern.Track>}
5945
+ * @return {!Promise<shaka.extern.Track>}
5889
5946
  * @export
5890
5947
  */
5891
5948
  async addTextTrackAsync(uri, language, kind, mimeType, codec, label,
@@ -6035,7 +6092,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6035
6092
  *
6036
6093
  * @param {string} uri
6037
6094
  * @param {string=} mimeType
6038
- * @return {!Promise.<shaka.extern.Track>}
6095
+ * @return {!Promise<shaka.extern.Track>}
6039
6096
  * @export
6040
6097
  */
6041
6098
  async addThumbnailsTrack(uri, mimeType) {
@@ -6194,7 +6251,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6194
6251
  * @param {string} uri
6195
6252
  * @param {string} language
6196
6253
  * @param {string=} mimeType
6197
- * @return {!Promise.<shaka.extern.Track>}
6254
+ * @return {!Promise<shaka.extern.Track>}
6198
6255
  * @export
6199
6256
  */
6200
6257
  async addChaptersTrack(uri, language, mimeType) {
@@ -6258,7 +6315,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6258
6315
 
6259
6316
  /**
6260
6317
  * @param {string} uri
6261
- * @return {!Promise.<string>}
6318
+ * @return {!Promise<string>}
6262
6319
  * @private
6263
6320
  */
6264
6321
  async getTextMimetype_(uri) {
@@ -6266,7 +6323,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6266
6323
  try {
6267
6324
  goog.asserts.assert(
6268
6325
  this.networkingEngine_, 'Need networking engine.');
6269
- // eslint-disable-next-line require-atomic-updates
6270
6326
  mimeType = await shaka.net.NetworkingUtils.getMimeType(uri,
6271
6327
  this.networkingEngine_,
6272
6328
  this.config_.streaming.retryParameters);
@@ -6292,8 +6348,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6292
6348
  * @param {string} kind
6293
6349
  * @param {string} mimeType
6294
6350
  * @param {string} label
6295
- * @param {!Array.<!shaka.extern.AdCuePoint>} adCuePoints
6296
- * @return {!Promise.<!HTMLTrackElement>}
6351
+ * @param {!Array<!shaka.extern.AdCuePoint>} adCuePoints
6352
+ * @return {!Promise<!HTMLTrackElement>}
6297
6353
  * @private
6298
6354
  */
6299
6355
  async addSrcTrackElement_(uri, language, kind, mimeType, label,
@@ -6335,7 +6391,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6335
6391
  * @param {string} uri
6336
6392
  * @param {!shaka.net.NetworkingEngine} netEngine
6337
6393
  * @param {shaka.extern.RetryParameters} retryParams
6338
- * @return {!Promise.<BufferSource>}
6394
+ * @return {!Promise<BufferSource>}
6339
6395
  * @private
6340
6396
  */
6341
6397
  async getTextData_(uri, netEngine, retryParams) {
@@ -6357,7 +6413,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6357
6413
  *
6358
6414
  * @param {BufferSource} buffer
6359
6415
  * @param {string} mimeType
6360
- * @param {!Array.<!shaka.extern.AdCuePoint>} adCuePoints
6416
+ * @param {!Array<!shaka.extern.AdCuePoint>} adCuePoints
6361
6417
  * @return {string}
6362
6418
  * @private
6363
6419
  */
@@ -6671,7 +6727,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6671
6727
  /**
6672
6728
  * @param {shaka.extern.Variant} initialVariant
6673
6729
  * @param {number} time
6674
- * @return {!Promise.<number>}
6730
+ * @return {!Promise<number>}
6675
6731
  * @private
6676
6732
  */
6677
6733
  async adjustStartTime_(initialVariant, time) {
@@ -6683,14 +6739,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6683
6739
  /**
6684
6740
  * @param {?shaka.extern.Stream} stream
6685
6741
  * @param {number} time
6686
- * @return {!Promise.<?number>}
6742
+ * @return {!Promise<?number>}
6687
6743
  */
6688
6744
  const getAdjustedTime = async (stream, time) => {
6689
6745
  if (!stream) {
6690
6746
  return null;
6691
6747
  }
6692
6748
 
6693
- await stream.createSegmentIndex();
6749
+ if (!stream.segmentIndex) {
6750
+ await stream.createSegmentIndex();
6751
+ }
6694
6752
  const iter = stream.segmentIndex.getIteratorForTime(time);
6695
6753
  const ref = iter ? iter.next().value : null;
6696
6754
  if (!ref) {
@@ -6736,7 +6794,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6736
6794
  const loaded = this.stats_ && this.bufferObserver_ && this.playhead_;
6737
6795
 
6738
6796
  if (loaded) {
6739
- this.playRateController_.setBuffering(isBuffering);
6797
+ if (this.config_.streaming.rebufferingGoal == 0) {
6798
+ // Disable buffer control with playback rate
6799
+ this.playRateController_.setBuffering(/* isBuffering= */ false);
6800
+ } else {
6801
+ this.playRateController_.setBuffering(isBuffering);
6802
+ }
6740
6803
  if (this.cmcdManager_) {
6741
6804
  this.cmcdManager_.setBuffering(isBuffering);
6742
6805
  }
@@ -7933,7 +7996,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
7933
7996
  }
7934
7997
 
7935
7998
  /**
7936
- * @param {!Object.<string, string>} keyStatusMap A map of hex key IDs to
7999
+ * @param {!Object<string, string>} keyStatusMap A map of hex key IDs to
7937
8000
  * statuses.
7938
8001
  * @private
7939
8002
  */
@@ -8082,8 +8145,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
8082
8145
  /**
8083
8146
  * Get the normalized languages for a group of tracks.
8084
8147
  *
8085
- * @param {!Array.<?shaka.extern.Track>} tracks
8086
- * @return {!Set.<string>}
8148
+ * @param {!Array<?shaka.extern.Track>} tracks
8149
+ * @return {!Set<string>}
8087
8150
  * @private
8088
8151
  */
8089
8152
  static getLanguagesFrom_(tracks) {
@@ -8104,14 +8167,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
8104
8167
  * Get all permutations of normalized languages and role for a group of
8105
8168
  * tracks.
8106
8169
  *
8107
- * @param {!Array.<?shaka.extern.Track>} tracks
8108
- * @return {!Array.<shaka.extern.LanguageRole>}
8170
+ * @param {!Array<?shaka.extern.Track>} tracks
8171
+ * @return {!Array<shaka.extern.LanguageRole>}
8109
8172
  * @private
8110
8173
  */
8111
8174
  static getLanguageAndRolesFrom_(tracks) {
8112
- /** @type {!Map.<string, !Set>} */
8175
+ /** @type {!Map<string, !Set>} */
8113
8176
  const languageToRoles = new Map();
8114
- /** @type {!Map.<string, !Map.<string, string>>} */
8177
+ /** @type {!Map<string, !Map<string, string>>} */
8115
8178
  const languageRoleToLabel = new Map();
8116
8179
 
8117
8180
  for (const track of tracks) {
@@ -8320,15 +8383,15 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
8320
8383
  * @define {string} A version number taken from git at compile time.
8321
8384
  * @export
8322
8385
  */
8323
- // eslint-disable-next-line no-useless-concat, max-len
8324
- shaka.Player.version = 'v4.12.9' + '-uncompiled'; // x-release-please-version
8386
+ // eslint-disable-next-line no-useless-concat
8387
+ shaka.Player.version = 'v4.13.0' + '-uncompiled'; // x-release-please-version
8325
8388
 
8326
8389
  // Initialize the deprecation system using the version string we just set
8327
8390
  // on the player.
8328
8391
  shaka.Deprecate.init(shaka.Player.version);
8329
8392
 
8330
8393
 
8331
- /** @private {!Object.<string, function():*>} */
8394
+ /** @private {!Object<string, function(): *>} */
8332
8395
  shaka.Player.supportPlugins_ = {};
8333
8396
 
8334
8397