shaka-player 4.12.8 → 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 (261) 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 +33 -33
  9. package/dist/shaka-player.compiled.d.ts +138 -36
  10. package/dist/shaka-player.compiled.debug.d.ts +138 -36
  11. package/dist/shaka-player.compiled.debug.externs.js +367 -107
  12. package/dist/shaka-player.compiled.debug.js +828 -765
  13. package/dist/shaka-player.compiled.debug.map +4 -4
  14. package/dist/shaka-player.compiled.externs.js +367 -107
  15. package/dist/shaka-player.compiled.js +1451 -1416
  16. package/dist/shaka-player.compiled.map +4 -4
  17. package/dist/shaka-player.ui.d.ts +172 -38
  18. package/dist/shaka-player.ui.debug.d.ts +172 -38
  19. package/dist/shaka-player.ui.debug.externs.js +406 -113
  20. package/dist/shaka-player.ui.debug.js +842 -766
  21. package/dist/shaka-player.ui.debug.map +4 -4
  22. package/dist/shaka-player.ui.externs.js +406 -113
  23. package/dist/shaka-player.ui.js +1670 -1628
  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 +139 -109
  56. package/externs/shaka/text.js +10 -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 +42 -40
  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 +119 -119
  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 +55 -53
  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/gap_jumping_controller.js +14 -1
  102. package/lib/media/manifest_filterer.js +8 -8
  103. package/lib/media/manifest_parser.js +2 -2
  104. package/lib/media/media_source_capabilities.js +20 -1
  105. package/lib/media/media_source_engine.js +84 -35
  106. package/lib/media/mp4_segment_index_parser.js +5 -5
  107. package/lib/media/playhead.js +2 -8
  108. package/lib/media/playhead_observer.js +1 -1
  109. package/lib/media/preference_based_criteria.js +333 -0
  110. package/lib/media/preload_manager.js +53 -37
  111. package/lib/media/presentation_timeline.js +2 -2
  112. package/lib/media/quality_observer.js +35 -35
  113. package/lib/media/region_observer.js +2 -2
  114. package/lib/media/region_timeline.js +3 -3
  115. package/lib/media/segment_index.js +14 -14
  116. package/lib/media/segment_prefetch.js +17 -13
  117. package/lib/media/segment_reference.js +7 -7
  118. package/lib/media/segment_utils.js +9 -9
  119. package/lib/media/streaming_engine.js +77 -38
  120. package/lib/media/time_ranges_utils.js +1 -1
  121. package/lib/media/video_wrapper.js +1 -1
  122. package/lib/media/webm_segment_index_parser.js +4 -4
  123. package/lib/mss/content_protection.js +17 -222
  124. package/lib/mss/mss_parser.js +23 -24
  125. package/lib/net/data_uri_plugin.js +1 -0
  126. package/lib/net/http_fetch_plugin.js +8 -7
  127. package/lib/net/http_plugin_utils.js +5 -2
  128. package/lib/net/http_xhr_plugin.js +4 -3
  129. package/lib/net/networking_engine.js +72 -17
  130. package/lib/net/networking_utils.js +5 -2
  131. package/lib/offline/download_info.js +5 -1
  132. package/lib/offline/download_manager.js +15 -4
  133. package/lib/offline/download_progress_estimator.js +1 -1
  134. package/lib/offline/indexeddb/base_storage_cell.js +9 -9
  135. package/lib/offline/indexeddb/db_connection.js +1 -1
  136. package/lib/offline/indexeddb/db_operation.js +2 -2
  137. package/lib/offline/indexeddb/eme_session_storage_cell.js +1 -1
  138. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  139. package/lib/offline/indexeddb/v1_storage_cell.js +3 -3
  140. package/lib/offline/indexeddb/v2_storage_cell.js +2 -2
  141. package/lib/offline/manifest_converter.js +11 -12
  142. package/lib/offline/offline_scheme.js +8 -4
  143. package/lib/offline/session_deleter.js +11 -11
  144. package/lib/offline/storage.js +137 -88
  145. package/lib/offline/storage_muxer.js +8 -8
  146. package/lib/offline/stored_content_utils.js +3 -3
  147. package/lib/offline/stream_bandwidth_estimator.js +1 -1
  148. package/lib/player.js +291 -207
  149. package/lib/polyfill/all.js +1 -1
  150. package/lib/polyfill/media_capabilities.js +5 -5
  151. package/lib/polyfill/patchedmediakeys_apple.js +6 -6
  152. package/lib/polyfill/patchedmediakeys_webkit.js +8 -8
  153. package/lib/polyfill/video_play_promise.js +0 -1
  154. package/lib/text/cue.js +3 -2
  155. package/lib/text/lrc_text_parser.js +1 -1
  156. package/lib/text/mp4_ttml_parser.js +1 -1
  157. package/lib/text/mp4_vtt_parser.js +3 -3
  158. package/lib/text/sbv_text_parser.js +1 -1
  159. package/lib/text/simple_text_displayer.js +37 -10
  160. package/lib/text/ssa_text_parser.js +3 -1
  161. package/lib/text/stub_text_displayer.js +12 -5
  162. package/lib/text/text_engine.js +5 -4
  163. package/lib/text/text_utils.js +4 -4
  164. package/lib/text/ttml_text_parser.js +21 -20
  165. package/lib/text/ui_text_displayer.js +20 -13
  166. package/lib/text/vtt_text_parser.js +10 -10
  167. package/lib/text/web_vtt_generator.js +2 -2
  168. package/lib/transmuxer/aac_transmuxer.js +2 -2
  169. package/lib/transmuxer/ac3_transmuxer.js +2 -2
  170. package/lib/transmuxer/adts.js +2 -0
  171. package/lib/transmuxer/ec3.js +3 -3
  172. package/lib/transmuxer/ec3_transmuxer.js +2 -2
  173. package/lib/transmuxer/h264.js +5 -5
  174. package/lib/transmuxer/h265.js +3 -3
  175. package/lib/transmuxer/mp3_transmuxer.js +2 -2
  176. package/lib/transmuxer/mpeg_audio.js +6 -6
  177. package/lib/transmuxer/mss_transmuxer.js +2 -0
  178. package/lib/transmuxer/transmuxer_engine.js +1 -1
  179. package/lib/transmuxer/ts_transmuxer.js +10 -10
  180. package/lib/util/abortable_operation.js +10 -10
  181. package/lib/util/array_utils.js +6 -6
  182. package/lib/util/cmcd_manager.js +149 -18
  183. package/lib/util/cmsd_manager.js +11 -11
  184. package/lib/util/config_utils.js +3 -3
  185. package/lib/util/content_steering_manager.js +17 -17
  186. package/lib/util/data_view_reader.js +3 -3
  187. package/lib/util/ebml_parser.js +1 -1
  188. package/lib/util/error.js +11 -6
  189. package/lib/util/event_manager.js +1 -1
  190. package/lib/util/exp_golomb.js +1 -1
  191. package/lib/util/fairplay_utils.js +6 -1
  192. package/lib/util/fake_event.js +3 -2
  193. package/lib/util/fake_event_target.js +1 -1
  194. package/lib/util/functional.js +8 -8
  195. package/lib/util/id3_utils.js +1 -1
  196. package/lib/util/iterables.js +6 -6
  197. package/lib/util/language_utils.js +17 -17
  198. package/lib/util/manifest_parser_utils.js +13 -13
  199. package/lib/util/map_utils.js +6 -6
  200. package/lib/util/media_ready_state_utils.js +1 -1
  201. package/lib/util/mime_utils.js +15 -4
  202. package/lib/util/mp4_box_parsers.js +5 -5
  203. package/lib/util/mp4_generator.js +31 -30
  204. package/lib/util/mp4_parser.js +2 -2
  205. package/lib/util/multi_map.js +5 -5
  206. package/lib/util/mutex.js +1 -1
  207. package/lib/util/networking.js +1 -1
  208. package/lib/util/object_utils.js +5 -1
  209. package/lib/util/operation_manager.js +1 -1
  210. package/lib/util/periods.js +24 -24
  211. package/lib/util/platform.js +8 -4
  212. package/lib/util/player_configuration.js +50 -17
  213. package/lib/util/pssh.js +34 -6
  214. package/lib/util/public_promise.js +2 -2
  215. package/lib/util/state_history.js +2 -2
  216. package/lib/util/stream_utils.js +138 -120
  217. package/lib/util/string_utils.js +4 -3
  218. package/lib/util/switch_history.js +2 -2
  219. package/lib/util/tXml.js +22 -17
  220. package/lib/util/text_parser.js +2 -2
  221. package/lib/util/timer.js +1 -1
  222. package/lib/util/ts_parser.js +22 -22
  223. package/lib/util/xml_utils.js +1 -0
  224. package/package.json +7 -4
  225. package/project-words.txt +485 -0
  226. package/shaka-player.uncompiled.js +1 -1
  227. package/third_party/closure-uri/uri.js +2 -2
  228. package/third_party/closure-uri/utils.js +2 -2
  229. package/third_party/language-mapping-list/language-mapping-list.js +1 -1
  230. package/ui/ad_statistics_button.js +9 -5
  231. package/ui/airplay_button.js +1 -0
  232. package/ui/audio_language_selection.js +2 -1
  233. package/ui/context_menu.js +2 -2
  234. package/ui/controls.js +7 -7
  235. package/ui/externs/ui.js +29 -21
  236. package/ui/externs/watermark.js +64 -0
  237. package/ui/fast_forward_button.js +1 -1
  238. package/ui/gl_matrix/matrix_4x4.js +11 -5
  239. package/ui/hidden_fast_forward_button.js +1 -1
  240. package/ui/hidden_seek_button.js +1 -1
  241. package/ui/language_utils.js +27 -26
  242. package/ui/less/buttons.less +2 -2
  243. package/ui/localization.js +21 -21
  244. package/ui/loop_button.js +2 -2
  245. package/ui/overflow_menu.js +2 -2
  246. package/ui/playback_rate_selection.js +1 -1
  247. package/ui/presentation_time.js +4 -1
  248. package/ui/range_element.js +2 -2
  249. package/ui/resolution_selection.js +42 -6
  250. package/ui/rewind_button.js +1 -1
  251. package/ui/seek_bar.js +5 -5
  252. package/ui/statistics_button.js +8 -4
  253. package/ui/text_selection.js +3 -2
  254. package/ui/ui.js +32 -2
  255. package/ui/vr_manager.js +3 -3
  256. package/ui/vr_utils.js +14 -14
  257. package/ui/vr_webgl.js +5 -5
  258. package/ui/watermark.js +313 -0
  259. package/.eslintignore +0 -4
  260. package/.eslintrc.js +0 -310
  261. 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 {
@@ -1721,6 +1737,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1721
1737
  }, 'initializeMediaSourceEngineInner_');
1722
1738
  }
1723
1739
 
1740
+ if (this.manifest_ && this.manifest_.textStreams.length) {
1741
+ if (this.textDisplayer_.enableTextDisplayer) {
1742
+ this.textDisplayer_.enableTextDisplayer();
1743
+ } else {
1744
+ shaka.Deprecate.deprecateFeature(5,
1745
+ 'Text displayer w/ enableTextDisplayer',
1746
+ 'Text displayer should have a "enableTextDisplayer" method!');
1747
+ }
1748
+ }
1749
+
1724
1750
  // Wait for the preload manager to do all of the loading it can do.
1725
1751
  await mutexWrapOperation(async () => {
1726
1752
  await preloadManager.waitForFinish();
@@ -1846,7 +1872,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1846
1872
  *
1847
1873
  * @param {boolean=} initializeMediaSource
1848
1874
  * @param {boolean=} keepAdManager
1849
- * @return {!Promise.<?shaka.media.PreloadManager>}
1875
+ * @return {!Promise<?shaka.media.PreloadManager>}
1850
1876
  * @export
1851
1877
  */
1852
1878
  async unloadAndSavePreload(
@@ -1866,7 +1892,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1866
1892
  *
1867
1893
  * @param {boolean=} keepAdManager
1868
1894
  * @param {boolean=} saveLivePosition
1869
- * @return {!Promise.<?shaka.media.PreloadManager>}
1895
+ * @return {!Promise<?shaka.media.PreloadManager>}
1870
1896
  * @export
1871
1897
  */
1872
1898
  async detachAndSavePreload(keepAdManager = false, saveLivePosition = false) {
@@ -1877,7 +1903,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1877
1903
 
1878
1904
  /**
1879
1905
  * @param {boolean=} saveLivePosition
1880
- * @return {!Promise.<?shaka.media.PreloadManager>}
1906
+ * @return {!Promise<?shaka.media.PreloadManager>}
1881
1907
  * @private
1882
1908
  */
1883
1909
  async savePreload_(saveLivePosition = false) {
@@ -1940,7 +1966,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1940
1966
  * <code>undefined</code>, playback will start at the default start time (0
1941
1967
  * for VOD and liveEdge for LIVE).
1942
1968
  * @param {?string=} mimeType
1943
- * @return {!Promise.<?shaka.media.PreloadManager>}
1969
+ * @return {!Promise<?shaka.media.PreloadManager>}
1944
1970
  * @export
1945
1971
  */
1946
1972
  async preload(assetUri, startTime = null, mimeType) {
@@ -1977,7 +2003,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1977
2003
  * @param {?number} startTime
1978
2004
  * @param {?string=} mimeType
1979
2005
  * @param {boolean=} standardLoad
1980
- * @return {!Promise.<?shaka.media.PreloadManager>}
2006
+ * @return {!Promise<?shaka.media.PreloadManager>}
1981
2007
  * @private
1982
2008
  */
1983
2009
  async preloadInner_(assetUri, startTime, mimeType, standardLoad = false) {
@@ -2037,7 +2063,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2037
2063
  * @param {boolean=} allowPrefetch
2038
2064
  * @param {boolean=} disableVideo
2039
2065
  * @param {boolean=} allowMakeAbrManager
2040
- * @return {!Promise.<!shaka.media.PreloadManager>}
2066
+ * @return {!Promise<!shaka.media.PreloadManager>}
2041
2067
  * @private
2042
2068
  */
2043
2069
  async makePreloadManager_(assetUri, startTime, mimeType,
@@ -2067,14 +2093,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2067
2093
  }
2068
2094
  };
2069
2095
 
2070
- const setConfig = (name, value) => {
2071
- if (getPreloadManager()) {
2072
- preloadManager.configure(name, value);
2073
- } else {
2074
- this.configure(name, value);
2075
- }
2076
- };
2077
-
2078
2096
  // Avoid having to detect the resolution again if it has already been
2079
2097
  // detected or set
2080
2098
  if (this.maxHwRes_.width == Infinity &&
@@ -2114,10 +2132,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2114
2132
  onEvent: (event) => preloadManager.dispatchEvent(event),
2115
2133
  onError: (error) => preloadManager.onError(error),
2116
2134
  isLowLatencyMode: () => getConfig().streaming.lowLatencyMode,
2117
- isAutoLowLatencyMode: () => getConfig().streaming.autoLowLatencyMode,
2118
- enableLowLatencyMode: () => {
2119
- setConfig('streaming.lowLatencyMode', true);
2120
- },
2121
2135
  updateDuration: () => {
2122
2136
  if (this.streamingEngine_ && preloadManager.hasBeenAttached()) {
2123
2137
  this.streamingEngine_.updateDuration();
@@ -2260,7 +2274,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2260
2274
  const networkingEngine = this.createNetworkingEngine(getPreloadManager);
2261
2275
  this.networkingEngine_.copyFiltersInto(networkingEngine);
2262
2276
 
2263
- /** @return {!shaka.media.DrmEngine} */
2277
+ /** @return {!shaka.drm.DrmEngine} */
2264
2278
  const createDrmEngine = () => {
2265
2279
  return this.createDrmEngine(drmPlayerInterface);
2266
2280
  };
@@ -2286,7 +2300,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2286
2300
  * the loading process.
2287
2301
  *
2288
2302
  * @param {string} assetUri
2289
- * @return {!Promise.<?string>} mimeType
2303
+ * @return {!Promise<?string>} mimeType
2290
2304
  * @private
2291
2305
  */
2292
2306
  async guessMimeType_(assetUri) {
@@ -2350,7 +2364,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2350
2364
  // example, Android has native HLS, but we'd prefer our own MediaSource
2351
2365
  // version there.
2352
2366
  if (MimeUtils.isHlsType(mimeType)) {
2353
- // Native FairPlay HLS can be preferred on Apple platfforms.
2367
+ // Native FairPlay HLS can be preferred on Apple platforms.
2354
2368
  if (Platform.isApple() &&
2355
2369
  (this.config_.drm.servers['com.apple.fps'] ||
2356
2370
  this.config_.drm.servers['com.apple.fps.1_0'])) {
@@ -2361,6 +2375,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2361
2375
  return this.config_.streaming.preferNativeHls;
2362
2376
  }
2363
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
+
2364
2383
  // In all other cases, we prefer MediaSource.
2365
2384
  return false;
2366
2385
  }
@@ -2494,7 +2513,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2494
2513
 
2495
2514
  switch (track.kind) {
2496
2515
  case 'metadata':
2497
- this.processTimedMetadataSrcEqls_(track);
2516
+ this.processTimedMetadataSrcEquals_(track);
2498
2517
  break;
2499
2518
 
2500
2519
  case 'chapters':
@@ -2532,7 +2551,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2532
2551
  *
2533
2552
  * @param {number} startTimeOfLoad
2534
2553
  * @param {?shaka.extern.Variant} prefetchedVariant
2535
- * @param {!Map.<number, shaka.media.SegmentPrefetch>} segmentPrefetchById
2554
+ * @param {!Map<number, shaka.media.SegmentPrefetch>} segmentPrefetchById
2536
2555
  * @return {!Promise}
2537
2556
  * @private
2538
2557
  */
@@ -2623,16 +2642,21 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2623
2642
  this.parser_.onInitialVariantChosen(toLazyLoad);
2624
2643
  }
2625
2644
 
2626
- if (this.manifest_.isLowLatency && !this.config_.streaming.lowLatencyMode) {
2627
- shaka.log.alwaysWarn('Low-latency live stream detected, but ' +
2628
- 'low-latency streaming mode is not enabled in Shaka Player. ' +
2629
- 'Set streaming.lowLatencyMode configuration to true, and see ' +
2630
- '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
+ }
2631
2654
  }
2632
2655
 
2633
2656
  if (this.cmcdManager_) {
2634
2657
  this.cmcdManager_.setLowLatency(
2635
2658
  this.manifest_.isLowLatency && this.config_.streaming.lowLatencyMode);
2659
+ this.cmcdManager_.setStartTimeOfLoad(startTimeOfLoad * 1000);
2636
2660
  }
2637
2661
 
2638
2662
  shaka.Player.applyPlayRange_(this.manifest_.presentationTimeline,
@@ -2647,13 +2671,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2647
2671
  this.playheadObservers_ =
2648
2672
  this.createPlayheadObserversForMSE_(startTime);
2649
2673
 
2650
- // We need to start the buffer management code near the end because it
2651
- // will set the initial buffering state and that depends on other
2652
- // components being initialized.
2653
- const rebufferThreshold = Math.max(
2654
- this.manifest_.minBufferTime,
2655
- this.config_.streaming.rebufferingGoal);
2656
- this.startBufferManagement_(mediaElement, rebufferThreshold);
2674
+ this.startBufferManagement_(
2675
+ mediaElement, this.config_.streaming.rebufferingGoal);
2657
2676
  };
2658
2677
 
2659
2678
  if (!this.config_.streaming.startAtSegmentBoundary) {
@@ -2667,7 +2686,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2667
2686
  // Now we can switch to the initial variant.
2668
2687
  if (!activeVariant) {
2669
2688
  goog.asserts.assert(initialVariant,
2670
- 'Must have choosen an initial variant!');
2689
+ 'Must have chosen an initial variant!');
2671
2690
 
2672
2691
  // Now that we have initial streams, we may adjust the start time to
2673
2692
  // align to a segment boundary.
@@ -3100,6 +3119,17 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3100
3119
  if (unloaded) {
3101
3120
  return;
3102
3121
  }
3122
+
3123
+ if (this.getFilteredTextTracks_().length) {
3124
+ if (this.textDisplayer_.enableTextDisplayer) {
3125
+ this.textDisplayer_.enableTextDisplayer();
3126
+ } else {
3127
+ shaka.Deprecate.deprecateFeature(5,
3128
+ 'Text displayer w/ enableTextDisplayer',
3129
+ 'Text displayer should have a "enableTextDisplayer" method!');
3130
+ }
3131
+ }
3132
+
3103
3133
  let enabledNativeTrack = false;
3104
3134
  for (const track of textTracks) {
3105
3135
  if (track.mode !== 'disabled') {
@@ -3220,7 +3250,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3220
3250
  * @param {!TextTrack} track
3221
3251
  * @private
3222
3252
  */
3223
- processTimedMetadataSrcEqls_(track) {
3253
+ processTimedMetadataSrcEquals_(track) {
3224
3254
  if (track.kind != 'metadata') {
3225
3255
  return;
3226
3256
  }
@@ -3239,7 +3269,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3239
3269
  }
3240
3270
  }
3241
3271
  if (track.cues) {
3242
- /** @type {!Array.<shaka.extern.HLSInterstitial>} */
3272
+ /** @type {!Array<shaka.extern.HLSInterstitial>} */
3243
3273
  const interstitials = [];
3244
3274
 
3245
3275
  for (const cue of track.cues) {
@@ -3301,7 +3331,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3301
3331
 
3302
3332
 
3303
3333
  /**
3304
- * @param {!Array.<shaka.extern.ID3Metadata>} metadata
3334
+ * @param {!Array<shaka.extern.ID3Metadata>} metadata
3305
3335
  * @param {number} offset
3306
3336
  * @param {?number} segmentEndTime
3307
3337
  * @private
@@ -3390,11 +3420,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3390
3420
  * fake instances. Configuration and initialization will be handled after
3391
3421
  * |createDrmEngine|.
3392
3422
  *
3393
- * @param {shaka.media.DrmEngine.PlayerInterface} playerInterface
3394
- * @return {!shaka.media.DrmEngine}
3423
+ * @param {shaka.drm.DrmEngine.PlayerInterface} playerInterface
3424
+ * @return {!shaka.drm.DrmEngine}
3395
3425
  */
3396
3426
  createDrmEngine(playerInterface) {
3397
- return new shaka.media.DrmEngine(playerInterface);
3427
+ return new shaka.drm.DrmEngine(playerInterface);
3398
3428
  }
3399
3429
 
3400
3430
  /**
@@ -3471,6 +3501,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3471
3501
  }
3472
3502
  });
3473
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
+ };
3474
3513
  /** @type {shaka.net.NetworkingEngine.OnDownloadFailed} */
3475
3514
  const onDownloadFailed_ = (request, error, httpResponseCode, aborted) => {
3476
3515
  // Release a 'downloadfailed' event.
@@ -3512,8 +3551,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3512
3551
  };
3513
3552
 
3514
3553
  return new shaka.net.NetworkingEngine(
3515
- onProgressUpdated_, onHeadersReceived_, onDownloadFailed_, onRequest_,
3516
- onRetry_, onResponse_);
3554
+ onProgressUpdated_, onHeadersReceived_, onDownloadCompleted_,
3555
+ onDownloadFailed_, onRequest_, onRetry_, onResponse_);
3517
3556
  }
3518
3557
 
3519
3558
  /**
@@ -3621,7 +3660,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3621
3660
 
3622
3661
  this.bufferPoller_ = new shaka.util.Timer(() => {
3623
3662
  this.pollBufferState_();
3624
- }).tickEvery(/* seconds= */ 0.25);
3663
+ });
3664
+ if (this.config_.streaming.rebufferingGoal) {
3665
+ this.bufferPoller_.tickEvery(/* seconds= */ 0.25);
3666
+ }
3625
3667
  this.loadEventManager_.listen(mediaElement, 'waiting',
3626
3668
  (e) => this.pollBufferState_());
3627
3669
  this.loadEventManager_.listen(mediaElement, 'stalled',
@@ -3630,6 +3672,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3630
3672
  (e) => this.pollBufferState_());
3631
3673
  this.loadEventManager_.listen(mediaElement, 'progress',
3632
3674
  (e) => this.pollBufferState_());
3675
+ this.loadEventManager_.listen(mediaElement, 'seeked',
3676
+ (e) => this.pollBufferState_());
3633
3677
  }
3634
3678
 
3635
3679
  /**
@@ -3729,6 +3773,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3729
3773
  getNetworkingEngine: () => this.getNetworkingEngine(),
3730
3774
  getVariantTracks: () => this.getVariantTracks(),
3731
3775
  isLive: () => this.isLive(),
3776
+ getLiveLatency: () => this.getLiveLatency(),
3732
3777
  };
3733
3778
 
3734
3779
  return new shaka.util.CmcdManager(playerInterface, this.config_.cmcd);
@@ -4016,60 +4061,47 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4016
4061
  delete config['streaming']['dispatchAllEmsgBoxes'];
4017
4062
  }
4018
4063
 
4019
- // If lowLatencyMode is enabled, and inaccurateManifestTolerance and
4020
- // rebufferingGoal and segmentPrefetchLimit and baseDelay and
4021
- // autoCorrectDrift and maxDisabledTime are not specified, set
4022
- // inaccurateManifestTolerance to 0 and rebufferingGoal to 0.01 and
4023
- // segmentPrefetchLimit to 2 and updateIntervalSeconds to 0.1 and and
4024
- // baseDelay to 100 and autoCorrectDrift to false and maxDisabledTime
4025
- // to 1 by default for low latency streaming.
4026
- if (config['streaming'] && config['streaming']['lowLatencyMode']) {
4027
- if (config['streaming']['inaccurateManifestTolerance'] == undefined) {
4028
- config['streaming']['inaccurateManifestTolerance'] = 0;
4029
- }
4030
- if (config['streaming']['rebufferingGoal'] == undefined) {
4031
- config['streaming']['rebufferingGoal'] = 0.01;
4032
- }
4033
- if (config['streaming']['segmentPrefetchLimit'] == undefined) {
4034
- config['streaming']['segmentPrefetchLimit'] = 2;
4035
- }
4036
- if (config['streaming']['updateIntervalSeconds'] == undefined) {
4037
- config['streaming']['updateIntervalSeconds'] = 0.1;
4038
- }
4039
- if (config['streaming']['maxDisabledTime'] == undefined) {
4040
- config['streaming']['maxDisabledTime'] = 1;
4041
- }
4042
- if (config['streaming']['retryParameters'] == undefined) {
4043
- config['streaming']['retryParameters'] = {};
4044
- }
4045
- if (config['streaming']['retryParameters']['baseDelay'] == undefined) {
4046
- config['streaming']['retryParameters']['baseDelay'] = 100;
4047
- }
4048
- if (config['manifest'] == undefined) {
4049
- config['manifest'] = {};
4050
- }
4051
- if (config['manifest']['dash'] == undefined) {
4052
- config['manifest']['dash'] = {};
4053
- }
4054
- if (config['manifest']['dash']['autoCorrectDrift'] == undefined) {
4055
- config['manifest']['dash']['autoCorrectDrift'] = false;
4056
- }
4057
- if (config['manifest']['retryParameters'] == undefined) {
4058
- config['manifest']['retryParameters'] = {};
4059
- }
4060
- if (config['manifest']['retryParameters']['baseDelay'] == undefined) {
4061
- config['manifest']['retryParameters']['baseDelay'] = 100;
4062
- }
4063
- if (config['drm'] == undefined) {
4064
- config['drm'] = {};
4065
- }
4066
- if (config['drm']['retryParameters'] == undefined) {
4067
- 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
+ }
4068
4095
  }
4069
- if (config['drm']['retryParameters']['baseDelay'] == undefined) {
4070
- 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.');
4071
4102
  }
4072
4103
  }
4104
+
4073
4105
  const ret = shaka.util.PlayerConfiguration.mergeConfigObjects(
4074
4106
  this.config_, config, this.defaultConfig_());
4075
4107
 
@@ -4077,6 +4109,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4077
4109
  return ret;
4078
4110
  }
4079
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
+
4080
4124
  /**
4081
4125
  * Apply config changes.
4082
4126
  * @private
@@ -4189,12 +4233,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4189
4233
  this.onAbrStatusChanged_();
4190
4234
  }
4191
4235
  if (this.bufferObserver_) {
4192
- let rebufferThreshold = this.config_.streaming.rebufferingGoal;
4193
- if (this.manifest_) {
4194
- rebufferThreshold =
4195
- 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);
4196
4243
  }
4197
- this.updateBufferingSettings_(rebufferThreshold);
4198
4244
  }
4199
4245
 
4200
4246
  if (this.manifest_) {
@@ -4230,6 +4276,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4230
4276
  return ret;
4231
4277
  }
4232
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
+
4233
4289
  /**
4234
4290
  * Return a copy of the current non default configuration. Modifications of
4235
4291
  * the returned value will not affect the Player's active configuration.
@@ -4540,7 +4596,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4540
4596
  * @export
4541
4597
  */
4542
4598
  keySystem() {
4543
- return shaka.util.DrmUtils.keySystem(this.drmInfo());
4599
+ return shaka.drm.DrmUtils.keySystem(this.drmInfo());
4544
4600
  }
4545
4601
 
4546
4602
  /**
@@ -4561,7 +4617,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4561
4617
  * This method should only be used for testing. Applications SHOULD NOT
4562
4618
  * use this in production.
4563
4619
  *
4564
- * @return {?shaka.media.DrmEngine}
4620
+ * @return {?shaka.drm.DrmEngine}
4565
4621
  */
4566
4622
  getDrmEngine() {
4567
4623
  return this.drmEngine_;
@@ -4584,7 +4640,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4584
4640
  /**
4585
4641
  * Returns the active sessions metadata
4586
4642
  *
4587
- * @return {!Array.<shaka.extern.DrmSessionMetadata>}
4643
+ * @return {!Array<shaka.extern.DrmSessionMetadata>}
4588
4644
  * @export
4589
4645
  */
4590
4646
  getActiveSessionsMetadata() {
@@ -4724,7 +4780,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4724
4780
  * <p>
4725
4781
  * If the player has not loaded content, this will return an empty list.
4726
4782
  *
4727
- * @return {!Array.<shaka.extern.Track>}
4783
+ * @return {!Array<shaka.extern.Track>}
4728
4784
  * @export
4729
4785
  */
4730
4786
  getVariantTracks() {
@@ -4780,7 +4836,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4780
4836
  * <p>
4781
4837
  * If the player has not loaded content, this will return an empty list.
4782
4838
  *
4783
- * @return {!Array.<shaka.extern.Track>}
4839
+ * @return {!Array<shaka.extern.Track>}
4784
4840
  * @export
4785
4841
  */
4786
4842
  getTextTracks() {
@@ -4812,7 +4868,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4812
4868
  *
4813
4869
  * If the player has not loaded content, this will return an empty list.
4814
4870
  *
4815
- * @return {!Array.<shaka.extern.Track>}
4871
+ * @return {!Array<shaka.extern.Track>}
4816
4872
  * @export
4817
4873
  */
4818
4874
  getImageTracks() {
@@ -4830,7 +4886,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4830
4886
  * If the player has not loaded content, this will return a null.
4831
4887
  *
4832
4888
  * @param {number} trackId
4833
- * @return {!Promise.<?Array<!shaka.extern.Thumbnail>>}
4889
+ * @return {!Promise<?Array<!shaka.extern.Thumbnail>>}
4834
4890
  * @export
4835
4891
  */
4836
4892
  async getAllThumbnails(trackId) {
@@ -4901,7 +4957,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4901
4957
  *
4902
4958
  * @param {number} trackId
4903
4959
  * @param {number} time
4904
- * @return {!Promise.<?shaka.extern.Thumbnail>}
4960
+ * @return {!Promise<?shaka.extern.Thumbnail>}
4905
4961
  * @export
4906
4962
  */
4907
4963
  async getThumbnails(trackId, time) {
@@ -5134,8 +5190,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5134
5190
  active.audio.channelsCount == variant.audio.channelsCount))) {
5135
5191
  shaka.log.alwaysWarn('Changing tracks while abr manager is enabled ' +
5136
5192
  'will likely result in the selected track ' +
5137
- 'being overriden. Consider disabling abr before ' +
5138
- 'calling selectVariantTrack().');
5193
+ 'being overridden. Consider disabling abr ' +
5194
+ 'before calling selectVariantTrack().');
5139
5195
  }
5140
5196
 
5141
5197
  if (this.isRemotePlayback()) {
@@ -5154,7 +5210,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5154
5210
  // currentAudioLanguage_.
5155
5211
  this.currentAdaptationSetCriteria_ = new shaka.media.ExampleBasedCriteria(
5156
5212
  variant,
5157
- this.config_.mediaSource.codecSwitchingStrategy);
5213
+ this.config_.mediaSource.codecSwitchingStrategy,
5214
+ this.config_.adaptationSetCriteriaFactory);
5158
5215
 
5159
5216
  // Update AbrManager variants to match these new settings.
5160
5217
  this.updateAbrManagerVariants_();
@@ -5188,7 +5245,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5188
5245
  * Return a list of audio language-role combinations available. If the
5189
5246
  * player has not loaded any content, this will return an empty list.
5190
5247
  *
5191
- * @return {!Array.<shaka.extern.LanguageRole>}
5248
+ * @return {!Array<shaka.extern.LanguageRole>}
5192
5249
  * @export
5193
5250
  */
5194
5251
  getAudioLanguagesAndRoles() {
@@ -5199,7 +5256,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5199
5256
  * Return a list of text language-role combinations available. If the player
5200
5257
  * has not loaded any content, this will be return an empty list.
5201
5258
  *
5202
- * @return {!Array.<shaka.extern.LanguageRole>}
5259
+ * @return {!Array<shaka.extern.LanguageRole>}
5203
5260
  * @export
5204
5261
  */
5205
5262
  getTextLanguagesAndRoles() {
@@ -5210,7 +5267,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5210
5267
  * Return a list of audio languages available. If the player has not loaded
5211
5268
  * any content, this will return an empty list.
5212
5269
  *
5213
- * @return {!Array.<string>}
5270
+ * @return {!Array<string>}
5214
5271
  * @export
5215
5272
  */
5216
5273
  getAudioLanguages() {
@@ -5221,7 +5278,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5221
5278
  * Return a list of text languages available. If the player has not loaded
5222
5279
  * any content, this will return an empty list.
5223
5280
  *
5224
- * @return {!Array.<string>}
5281
+ * @return {!Array<string>}
5225
5282
  * @export
5226
5283
  */
5227
5284
  getTextLanguages() {
@@ -5245,17 +5302,20 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5245
5302
  codec = '', spatialAudio = false) {
5246
5303
  const selectMediaSourceMode = () => {
5247
5304
  this.currentAdaptationSetCriteria_ =
5248
- new shaka.media.PreferenceBasedCriteria(
5249
- language,
5250
- role || '',
5251
- channelsCount || 0,
5252
- /* hdrLevel= */ '',
5253
- spatialAudio || false,
5254
- /* videoLayout= */ '',
5255
- /* audioLabel= */ '',
5256
- /* videoLabel= */ '',
5257
- this.config_.mediaSource.codecSwitchingStrategy,
5258
- 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
+ });
5259
5319
 
5260
5320
  const diff = (a, b) => {
5261
5321
  if (!a.video && !b.video) {
@@ -5402,17 +5462,21 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5402
5462
  // Because of that we assume that all the variants with the same
5403
5463
  // label have the same language.
5404
5464
  this.currentAdaptationSetCriteria_ =
5405
- new shaka.media.PreferenceBasedCriteria(
5406
- firstVariantWithLabel.language,
5407
- /* role= */ '',
5408
- /* channelCount= */ 0,
5409
- /* hdrLevel= */ '',
5410
- /* spatialAudio= */ false,
5411
- /* videoLayout= */ '',
5412
- label,
5413
- /* videoLabel= */ '',
5414
- this.config_.mediaSource.codecSwitchingStrategy,
5415
- /* 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
+ });
5416
5480
 
5417
5481
  this.chooseVariantAndSwitch_(clearBuffer, safeMargin);
5418
5482
  };
@@ -5467,7 +5531,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5467
5531
  /**
5468
5532
  * Return a list of chapters tracks.
5469
5533
  *
5470
- * @return {!Array.<shaka.extern.Track>}
5534
+ * @return {!Array<shaka.extern.Track>}
5471
5535
  * @export
5472
5536
  */
5473
5537
  getChaptersTracks() {
@@ -5484,7 +5548,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5484
5548
  * This returns the list of chapters.
5485
5549
  *
5486
5550
  * @param {string} language
5487
- * @return {!Array.<shaka.extern.Chapter>}
5551
+ * @return {!Array<shaka.extern.Chapter>}
5488
5552
  * @export
5489
5553
  */
5490
5554
  getChapters(language) {
@@ -5492,10 +5556,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5492
5556
  return [];
5493
5557
  }
5494
5558
  const LanguageUtils = shaka.util.LanguageUtils;
5495
- const inputlanguage = LanguageUtils.normalize(language);
5559
+ const inputLanguage = LanguageUtils.normalize(language);
5496
5560
  const chaptersTracks = this.getChaptersTracks_();
5497
5561
  const chaptersTracksWithLanguage = chaptersTracks
5498
- .filter((t) => LanguageUtils.normalize(t.language) == inputlanguage);
5562
+ .filter((t) => LanguageUtils.normalize(t.language) == inputLanguage);
5499
5563
  if (!chaptersTracksWithLanguage || !chaptersTracksWithLanguage.length) {
5500
5564
  return [];
5501
5565
  }
@@ -5529,7 +5593,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5529
5593
  * Ignore the TextTracks with the 'metadata' or 'chapters' kind, or the one
5530
5594
  * generated by the SimpleTextDisplayer.
5531
5595
  *
5532
- * @return {!Array.<TextTrack>}
5596
+ * @return {!Array<TextTrack>}
5533
5597
  * @private
5534
5598
  */
5535
5599
  getFilteredTextTracks_() {
@@ -5543,7 +5607,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5543
5607
  /**
5544
5608
  * Get the TextTracks with the 'metadata' kind.
5545
5609
  *
5546
- * @return {!Array.<TextTrack>}
5610
+ * @return {!Array<TextTrack>}
5547
5611
  * @private
5548
5612
  */
5549
5613
  getMetadataTracks_() {
@@ -5556,7 +5620,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5556
5620
  /**
5557
5621
  * Get the TextTracks with the 'chapters' kind.
5558
5622
  *
5559
- * @return {!Array.<TextTrack>}
5623
+ * @return {!Array<TextTrack>}
5560
5624
  * @private
5561
5625
  */
5562
5626
  getChaptersTracks_() {
@@ -5574,11 +5638,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5574
5638
  * @export
5575
5639
  */
5576
5640
  setTextTrackVisibility(isVisible) {
5577
- const oldVisibilty = this.isTextVisible_;
5641
+ const oldVisibility = this.isTextVisible_;
5578
5642
  // Convert to boolean in case apps pass 0/1 instead false/true.
5579
5643
  const newVisibility = !!isVisible;
5580
5644
 
5581
- if (oldVisibilty == newVisibility) {
5645
+ if (oldVisibility == newVisibility) {
5582
5646
  return;
5583
5647
  }
5584
5648
 
@@ -5751,6 +5815,22 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5751
5815
  return info;
5752
5816
  }
5753
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
+
5754
5834
  /**
5755
5835
  * Get statistics for the current playback session. If the player is not
5756
5836
  * playing content, this will return an empty stats object.
@@ -5820,10 +5900,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5820
5900
  }
5821
5901
 
5822
5902
  if (this.isLive()) {
5823
- const now = this.getPresentationStartTimeAsDate().valueOf() +
5824
- element.currentTime * 1000;
5825
- const latency = (Date.now() - now) / 1000;
5826
- this.stats_.setLiveLatency(latency);
5903
+ const latency = this.getLiveLatency() || 0;
5904
+ this.stats_.setLiveLatency(latency / 1000);
5827
5905
  }
5828
5906
 
5829
5907
  if (this.manifest_) {
@@ -5864,7 +5942,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5864
5942
  * @param {string=} codec
5865
5943
  * @param {string=} label
5866
5944
  * @param {boolean=} forced
5867
- * @return {!Promise.<shaka.extern.Track>}
5945
+ * @return {!Promise<shaka.extern.Track>}
5868
5946
  * @export
5869
5947
  */
5870
5948
  async addTextTrackAsync(uri, language, kind, mimeType, codec, label,
@@ -6014,7 +6092,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6014
6092
  *
6015
6093
  * @param {string} uri
6016
6094
  * @param {string=} mimeType
6017
- * @return {!Promise.<shaka.extern.Track>}
6095
+ * @return {!Promise<shaka.extern.Track>}
6018
6096
  * @export
6019
6097
  */
6020
6098
  async addThumbnailsTrack(uri, mimeType) {
@@ -6173,7 +6251,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6173
6251
  * @param {string} uri
6174
6252
  * @param {string} language
6175
6253
  * @param {string=} mimeType
6176
- * @return {!Promise.<shaka.extern.Track>}
6254
+ * @return {!Promise<shaka.extern.Track>}
6177
6255
  * @export
6178
6256
  */
6179
6257
  async addChaptersTrack(uri, language, mimeType) {
@@ -6237,7 +6315,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6237
6315
 
6238
6316
  /**
6239
6317
  * @param {string} uri
6240
- * @return {!Promise.<string>}
6318
+ * @return {!Promise<string>}
6241
6319
  * @private
6242
6320
  */
6243
6321
  async getTextMimetype_(uri) {
@@ -6245,7 +6323,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6245
6323
  try {
6246
6324
  goog.asserts.assert(
6247
6325
  this.networkingEngine_, 'Need networking engine.');
6248
- // eslint-disable-next-line require-atomic-updates
6249
6326
  mimeType = await shaka.net.NetworkingUtils.getMimeType(uri,
6250
6327
  this.networkingEngine_,
6251
6328
  this.config_.streaming.retryParameters);
@@ -6271,8 +6348,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6271
6348
  * @param {string} kind
6272
6349
  * @param {string} mimeType
6273
6350
  * @param {string} label
6274
- * @param {!Array.<!shaka.extern.AdCuePoint>} adCuePoints
6275
- * @return {!Promise.<!HTMLTrackElement>}
6351
+ * @param {!Array<!shaka.extern.AdCuePoint>} adCuePoints
6352
+ * @return {!Promise<!HTMLTrackElement>}
6276
6353
  * @private
6277
6354
  */
6278
6355
  async addSrcTrackElement_(uri, language, kind, mimeType, label,
@@ -6314,7 +6391,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6314
6391
  * @param {string} uri
6315
6392
  * @param {!shaka.net.NetworkingEngine} netEngine
6316
6393
  * @param {shaka.extern.RetryParameters} retryParams
6317
- * @return {!Promise.<BufferSource>}
6394
+ * @return {!Promise<BufferSource>}
6318
6395
  * @private
6319
6396
  */
6320
6397
  async getTextData_(uri, netEngine, retryParams) {
@@ -6336,7 +6413,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6336
6413
  *
6337
6414
  * @param {BufferSource} buffer
6338
6415
  * @param {string} mimeType
6339
- * @param {!Array.<!shaka.extern.AdCuePoint>} adCuePoints
6416
+ * @param {!Array<!shaka.extern.AdCuePoint>} adCuePoints
6340
6417
  * @return {string}
6341
6418
  * @private
6342
6419
  */
@@ -6650,7 +6727,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6650
6727
  /**
6651
6728
  * @param {shaka.extern.Variant} initialVariant
6652
6729
  * @param {number} time
6653
- * @return {!Promise.<number>}
6730
+ * @return {!Promise<number>}
6654
6731
  * @private
6655
6732
  */
6656
6733
  async adjustStartTime_(initialVariant, time) {
@@ -6662,14 +6739,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6662
6739
  /**
6663
6740
  * @param {?shaka.extern.Stream} stream
6664
6741
  * @param {number} time
6665
- * @return {!Promise.<?number>}
6742
+ * @return {!Promise<?number>}
6666
6743
  */
6667
6744
  const getAdjustedTime = async (stream, time) => {
6668
6745
  if (!stream) {
6669
6746
  return null;
6670
6747
  }
6671
6748
 
6672
- await stream.createSegmentIndex();
6749
+ if (!stream.segmentIndex) {
6750
+ await stream.createSegmentIndex();
6751
+ }
6673
6752
  const iter = stream.segmentIndex.getIteratorForTime(time);
6674
6753
  const ref = iter ? iter.next().value : null;
6675
6754
  if (!ref) {
@@ -6715,7 +6794,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6715
6794
  const loaded = this.stats_ && this.bufferObserver_ && this.playhead_;
6716
6795
 
6717
6796
  if (loaded) {
6718
- 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
+ }
6719
6803
  if (this.cmcdManager_) {
6720
6804
  this.cmcdManager_.setBuffering(isBuffering);
6721
6805
  }
@@ -7912,7 +7996,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
7912
7996
  }
7913
7997
 
7914
7998
  /**
7915
- * @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
7916
8000
  * statuses.
7917
8001
  * @private
7918
8002
  */
@@ -8061,8 +8145,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
8061
8145
  /**
8062
8146
  * Get the normalized languages for a group of tracks.
8063
8147
  *
8064
- * @param {!Array.<?shaka.extern.Track>} tracks
8065
- * @return {!Set.<string>}
8148
+ * @param {!Array<?shaka.extern.Track>} tracks
8149
+ * @return {!Set<string>}
8066
8150
  * @private
8067
8151
  */
8068
8152
  static getLanguagesFrom_(tracks) {
@@ -8083,14 +8167,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
8083
8167
  * Get all permutations of normalized languages and role for a group of
8084
8168
  * tracks.
8085
8169
  *
8086
- * @param {!Array.<?shaka.extern.Track>} tracks
8087
- * @return {!Array.<shaka.extern.LanguageRole>}
8170
+ * @param {!Array<?shaka.extern.Track>} tracks
8171
+ * @return {!Array<shaka.extern.LanguageRole>}
8088
8172
  * @private
8089
8173
  */
8090
8174
  static getLanguageAndRolesFrom_(tracks) {
8091
- /** @type {!Map.<string, !Set>} */
8175
+ /** @type {!Map<string, !Set>} */
8092
8176
  const languageToRoles = new Map();
8093
- /** @type {!Map.<string, !Map.<string, string>>} */
8177
+ /** @type {!Map<string, !Map<string, string>>} */
8094
8178
  const languageRoleToLabel = new Map();
8095
8179
 
8096
8180
  for (const track of tracks) {
@@ -8299,15 +8383,15 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
8299
8383
  * @define {string} A version number taken from git at compile time.
8300
8384
  * @export
8301
8385
  */
8302
- // eslint-disable-next-line no-useless-concat, max-len
8303
- shaka.Player.version = 'v4.12.8' + '-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
8304
8388
 
8305
8389
  // Initialize the deprecation system using the version string we just set
8306
8390
  // on the player.
8307
8391
  shaka.Deprecate.init(shaka.Player.version);
8308
8392
 
8309
8393
 
8310
- /** @private {!Object.<string, function():*>} */
8394
+ /** @private {!Object<string, function(): *>} */
8311
8395
  shaka.Player.supportPlugins_ = {};
8312
8396
 
8313
8397