shaka-player 3.1.3 → 3.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/AUTHORS +3 -0
  2. package/CHANGELOG.md +175 -3
  3. package/CONTRIBUTORS +3 -0
  4. package/README.md +4 -4
  5. package/build/generateExterns.js +1 -1
  6. package/build/types/polyfill +1 -0
  7. package/demo/common/asset.js +9 -7
  8. package/demo/common/assets.js +11 -2
  9. package/demo/common/message_ids.js +2 -1
  10. package/demo/config.js +5 -2
  11. package/demo/index.html +1 -1
  12. package/demo/locales/en.json +2 -1
  13. package/demo/locales/source.json +8 -4
  14. package/demo/main.js +2 -1
  15. package/dist/controls.css +2 -2
  16. package/dist/controls.css.map +1 -1
  17. package/dist/demo.compiled.debug.js +15 -15
  18. package/dist/demo.compiled.debug.map +2 -2
  19. package/dist/demo.compiled.js +15 -15
  20. package/dist/demo.compiled.map +2 -2
  21. package/dist/deps.js +22 -21
  22. package/dist/locales.js +36 -36
  23. package/dist/receiver.compiled.debug.js +9 -9
  24. package/dist/receiver.compiled.debug.map +2 -2
  25. package/dist/receiver.compiled.js +9 -9
  26. package/dist/receiver.compiled.map +2 -2
  27. package/dist/shaka-player.compiled.d.ts +58 -10
  28. package/dist/shaka-player.compiled.debug.d.ts +58 -10
  29. package/dist/shaka-player.compiled.debug.externs.js +777 -717
  30. package/dist/shaka-player.compiled.debug.js +639 -607
  31. package/dist/shaka-player.compiled.debug.map +4 -4
  32. package/dist/shaka-player.compiled.externs.js +777 -717
  33. package/dist/shaka-player.compiled.js +826 -819
  34. package/dist/shaka-player.compiled.map +4 -4
  35. package/dist/shaka-player.ui.d.ts +58 -10
  36. package/dist/shaka-player.ui.debug.d.ts +58 -10
  37. package/dist/shaka-player.ui.debug.externs.js +529 -469
  38. package/dist/shaka-player.ui.debug.js +676 -645
  39. package/dist/shaka-player.ui.debug.map +4 -4
  40. package/dist/shaka-player.ui.externs.js +529 -469
  41. package/dist/shaka-player.ui.js +963 -955
  42. package/dist/shaka-player.ui.map +4 -4
  43. package/docs/tutorials/fairplay.md +1 -1
  44. package/docs/tutorials/ui.md +5 -5
  45. package/externs/aria.js +6 -0
  46. package/externs/shaka/ads.js +24 -1
  47. package/externs/shaka/manifest.js +6 -1
  48. package/externs/shaka/offline.js +5 -0
  49. package/externs/shaka/player.js +53 -9
  50. package/externs/shaka/text.js +10 -10
  51. package/externs/texttrack.js +3 -0
  52. package/karma.conf.js +1 -0
  53. package/lib/ads/ad_manager.js +16 -15
  54. package/lib/ads/client_side_ad_manager.js +52 -88
  55. package/lib/ads/server_side_ad_manager.js +26 -12
  56. package/lib/cast/cast_proxy.js +11 -2
  57. package/lib/cast/cast_receiver.js +2 -1
  58. package/lib/cast/cast_sender.js +2 -2
  59. package/lib/cast/cast_utils.js +6 -1
  60. package/lib/cea/cea608_data_channel.js +56 -56
  61. package/lib/cea/cea608_memory.js +33 -33
  62. package/lib/cea/cea708_service.js +43 -43
  63. package/lib/cea/cea708_window.js +38 -38
  64. package/lib/cea/cea_decoder.js +13 -14
  65. package/lib/cea/cea_utils.js +23 -23
  66. package/lib/cea/dtvcc_packet_builder.js +7 -7
  67. package/lib/cea/i_caption_decoder.js +2 -3
  68. package/lib/cea/i_cea_parser.js +2 -2
  69. package/lib/cea/mp4_cea_parser.js +6 -6
  70. package/lib/dash/dash_parser.js +98 -2
  71. package/lib/dash/segment_list.js +1 -1
  72. package/lib/dash/segment_template.js +1 -1
  73. package/lib/hls/hls_parser.js +159 -29
  74. package/lib/media/closed_caption_parser.js +1 -2
  75. package/lib/media/drm_engine.js +169 -192
  76. package/lib/media/gap_jumping_controller.js +4 -2
  77. package/lib/media/media_source_engine.js +1 -2
  78. package/lib/media/segment_index.js +3 -1
  79. package/lib/media/segment_reference.js +19 -2
  80. package/lib/media/streaming_engine.js +8 -7
  81. package/lib/net/networking_engine.js +3 -1
  82. package/lib/offline/download_manager.js +1 -2
  83. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  84. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  85. package/lib/offline/manifest_converter.js +3 -1
  86. package/lib/offline/storage.js +12 -14
  87. package/lib/player.js +437 -167
  88. package/lib/polyfill/aria.js +82 -0
  89. package/lib/polyfill/media_capabilities.js +7 -1
  90. package/lib/polyfill/mediasource.js +6 -0
  91. package/lib/polyfill/orientation.js +1 -1
  92. package/lib/polyfill/patchedmediakeys_apple.js +4 -4
  93. package/lib/polyfill/patchedmediakeys_ms.js +4 -4
  94. package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
  95. package/lib/routing/walker.js +2 -3
  96. package/lib/text/mp4_ttml_parser.js +3 -0
  97. package/lib/text/srt_text_parser.js +4 -4
  98. package/lib/text/text_engine.js +16 -4
  99. package/lib/text/ttml_text_parser.js +5 -0
  100. package/lib/text/ui_text_displayer.js +85 -37
  101. package/lib/text/vtt_text_parser.js +2 -2
  102. package/lib/text/web_vtt_generator.js +55 -12
  103. package/lib/util/error.js +6 -0
  104. package/lib/util/fake_event.js +53 -7
  105. package/lib/util/manifest_parser_utils.js +1 -0
  106. package/lib/util/mp4_box_parsers.js +20 -20
  107. package/lib/util/multi_map.js +8 -0
  108. package/lib/util/periods.js +4 -1
  109. package/lib/util/platform.js +13 -1
  110. package/lib/util/player_configuration.js +13 -1
  111. package/lib/util/stream_utils.js +153 -85
  112. package/lib/util/xml_utils.js +31 -12
  113. package/package.json +1 -1
  114. package/roadmap.md +24 -22
  115. package/shaka-player.uncompiled.js +1 -0
  116. package/test/cast/cast_proxy_unit.js +12 -6
  117. package/test/cast/cast_utils_unit.js +2 -1
  118. package/test/cea/cea608_memory_unit.js +1 -1
  119. package/test/cea/cea708_service_unit.js +8 -8
  120. package/test/cea/cea708_window_unit.js +6 -6
  121. package/test/cea/cea_decoder_unit.js +1 -1
  122. package/test/cea/dtvcc_packet_builder_unit.js +2 -2
  123. package/test/dash/dash_parser_manifest_unit.js +230 -2
  124. package/test/hls/hls_parser_unit.js +255 -1
  125. package/test/media/closed_caption_parser_unit.js +6 -1
  126. package/test/media/drm_engine_integration.js +86 -12
  127. package/test/media/drm_engine_unit.js +353 -450
  128. package/test/offline/manifest_convert_unit.js +2 -0
  129. package/test/offline/storage_integration.js +9 -19
  130. package/test/player_integration.js +90 -0
  131. package/test/player_src_equals_integration.js +52 -0
  132. package/test/player_unit.js +11 -33
  133. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  134. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  135. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  136. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  137. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  138. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  139. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  140. package/test/test/assets/3675/dash_0.mpd +30 -0
  141. package/test/test/assets/3675/dash_1.mpd +30 -0
  142. package/test/test/assets/3675/dash_2.mpd +30 -0
  143. package/test/test/assets/3675/dash_3.mpd +30 -0
  144. package/test/test/assets/3675/dash_4.mpd +30 -0
  145. package/test/test/assets/3675/dash_5.mpd +26 -0
  146. package/test/test/assets/3675/init-stream0.m4s +0 -0
  147. package/test/test/assets/chapters.srt +11 -0
  148. package/test/test/assets/chapters.vtt +10 -0
  149. package/test/test/util/cea_utils.js +12 -12
  150. package/test/test/util/fake_ad_manager.js +8 -1
  151. package/test/test/util/manifest_generator.js +2 -0
  152. package/test/test/util/manifest_parser_util.js +3 -1
  153. package/test/text/ttml_text_parser_unit.js +9 -0
  154. package/test/text/ui_text_displayer_unit.js +29 -17
  155. package/test/text/web_vtt_generator_unit.js +81 -7
  156. package/test/ui/localization_unit.js +15 -14
  157. package/test/ui/text_displayer_layout_unit.js +13 -1
  158. package/test/util/stream_utils_unit.js +153 -10
  159. package/ui/airplay_button.js +1 -1
  160. package/ui/audio_language_selection.js +2 -5
  161. package/ui/cast_button.js +6 -9
  162. package/ui/constants.js +0 -3
  163. package/ui/controls.js +4 -6
  164. package/ui/fast_forward_button.js +2 -3
  165. package/ui/fullscreen_button.js +1 -3
  166. package/ui/language_utils.js +1 -1
  167. package/ui/less/containers.less +3 -7
  168. package/ui/locales/ru.json +6 -6
  169. package/ui/localization.js +28 -51
  170. package/ui/loop_button.js +1 -3
  171. package/ui/mute_button.js +1 -3
  172. package/ui/overflow_menu.js +2 -3
  173. package/ui/pip_button.js +7 -10
  174. package/ui/playback_rate_selection.js +3 -6
  175. package/ui/presentation_time.js +1 -3
  176. package/ui/resolution_selection.js +4 -7
  177. package/ui/rewind_button.js +2 -3
  178. package/ui/seek_bar.js +2 -4
  179. package/ui/spacer.js +1 -1
  180. package/ui/text_selection.js +8 -11
  181. package/ui/ui_utils.js +1 -1
  182. package/ui/volume_bar.js +1 -3
package/lib/player.js CHANGED
@@ -217,6 +217,8 @@ goog.requireType('shaka.routing.Payload');
217
217
  * <code>selectAudioLanguage()</code>, or <code>selectTextLanguage()</code>.
218
218
  * @property {string} type
219
219
  * 'adaptation'
220
+ * @property {shaka.extern.Track} oldTrack
221
+ * @property {shaka.extern.Track} newTrack
220
222
  * @exportDoc
221
223
  */
222
224
 
@@ -596,7 +598,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
596
598
  enterNode: (node, has, wants) => {
597
599
  this.dispatchEvent(this.makeEvent_(
598
600
  /* name= */ shaka.Player.EventName.OnStateChange,
599
- /* data= */ {'state': node.name}));
601
+ /* data= */ (new Map()).set('state', node.name)));
600
602
 
601
603
  const action = actions.get(node);
602
604
  return action(has, wants);
@@ -627,7 +629,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
627
629
  onIdle: (node) => {
628
630
  this.dispatchEvent(this.makeEvent_(
629
631
  /* name= */ shaka.Player.EventName.OnStateIdle,
630
- /* data= */ {'state': node.name}));
632
+ /* data= */ (new Map()).set('state', node.name)));
631
633
  },
632
634
  };
633
635
 
@@ -647,7 +649,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
647
649
 
648
650
  /**
649
651
  * @param {!shaka.Player.EventName} name
650
- * @param {Object=} data
652
+ * @param {Map.<string, Object>=} data
651
653
  * @return {!shaka.util.FakeEvent}
652
654
  * @private
653
655
  */
@@ -1142,24 +1144,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1142
1144
  if (!mimeType) {
1143
1145
  // Try using the uri extension.
1144
1146
  const extension = shaka.media.ManifestParser.getExtension(uri);
1145
- mimeType = {
1146
- 'mp4': 'video/mp4',
1147
- 'm4v': 'video/mp4',
1148
- 'm4a': 'audio/mp4',
1149
- 'webm': 'video/webm',
1150
- 'weba': 'audio/webm',
1151
- 'mkv': 'video/webm', // Chromium browsers supports it.
1152
- 'ts': 'video/mp2t',
1153
- 'ogv': 'video/ogg',
1154
- 'ogg': 'audio/ogg',
1155
- 'mpg': 'video/mpeg',
1156
- 'mpeg': 'video/mpeg',
1157
- 'm3u8': 'application/x-mpegurl',
1158
- 'mp3': 'audio/mpeg',
1159
- 'aac': 'audio/aac',
1160
- 'flac': 'audio/flac',
1161
- 'wav': 'audio/wav',
1162
- }[extension];
1147
+ mimeType = shaka.Player.SRC_EQUAL_EXTENSIONS_TO_MIME_TYPES_[extension];
1163
1148
  }
1164
1149
 
1165
1150
  // TODO: The load graph system has a design limitation that requires routing
@@ -1633,11 +1618,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1633
1618
  }
1634
1619
  });
1635
1620
 
1636
- // TODO (#1391): Once filterManifest_ is async, remove this eslint disable.
1637
- /* eslint-disable require-await */
1638
1621
  const playerInterface = {
1639
1622
  networkingEngine: networkingEngine,
1640
- filter: async (manifest) => this.filterManifest_(manifest),
1623
+ filter: (manifest) => this.filterManifest_(manifest),
1641
1624
  makeTextStreamsForClosedCaptions: (manifest) => {
1642
1625
  return this.makeTextStreamsForClosedCaptions_(manifest);
1643
1626
  },
@@ -1655,7 +1638,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1655
1638
  this.configure('streaming.lowLatencyMode', true);
1656
1639
  },
1657
1640
  };
1658
- /* eslint-enable require-await */
1659
1641
 
1660
1642
  const startTime = Date.now() / 1000;
1661
1643
 
@@ -1747,17 +1729,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1747
1729
  },
1748
1730
  });
1749
1731
 
1750
- // TODO: remove once MediaCap implementation is complete.
1751
- if (!this.config_.useMediaCapabilities) {
1752
- shaka.util.StreamUtils.filterManifestByMediaSource(this.manifest_);
1753
- }
1754
-
1755
1732
  this.drmEngine_.configure(this.config_.drm);
1756
1733
 
1757
1734
  await this.drmEngine_.initForPlayback(
1758
1735
  this.manifest_.variants,
1759
- this.manifest_.offlineSessionIds,
1760
- this.config_.useMediaCapabilities);
1736
+ this.manifest_.offlineSessionIds);
1761
1737
 
1762
1738
  await this.drmEngine_.attach(has.mediaElement);
1763
1739
 
@@ -1872,7 +1848,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1872
1848
  // If the content is multi-codec and the browser can play more than one of
1873
1849
  // them, choose codecs now before we initialize streaming.
1874
1850
  shaka.util.StreamUtils.chooseCodecsAndFilterManifest(
1875
- this.manifest_, this.config_.preferredAudioChannelCount);
1851
+ this.manifest_,
1852
+ this.config_.preferredVideoCodecs,
1853
+ this.config_.preferredAudioCodecs,
1854
+ this.config_.preferredAudioChannelCount,
1855
+ this.config_.preferredDecodingAttributes);
1876
1856
 
1877
1857
  this.streamingEngine_ = this.createStreamingEngine();
1878
1858
  this.streamingEngine_.configure(this.config_.streaming);
@@ -1911,7 +1891,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1911
1891
  }
1912
1892
 
1913
1893
  // Since the first streams just became active, send an adaptation event.
1914
- this.onAdaptation_();
1894
+ this.onAdaptation_(null,
1895
+ shaka.util.StreamUtils.variantToTrack(initialVariant));
1915
1896
  }
1916
1897
 
1917
1898
  // Decide if text should be shown automatically.
@@ -2024,6 +2005,16 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2024
2005
 
2025
2006
  this.drmEngine_.configure(this.config_.drm);
2026
2007
 
2008
+ const uri = wants.uri || '';
2009
+ const extension = shaka.media.ManifestParser.getExtension(uri);
2010
+ let mimeType = shaka.Player.SRC_EQUAL_EXTENSIONS_TO_MIME_TYPES_[extension];
2011
+ if (mimeType == 'application/x-mpegurl' && shaka.util.Platform.isApple()) {
2012
+ mimeType = 'application/vnd.apple.mpegurl';
2013
+ }
2014
+ if (!mimeType) {
2015
+ mimeType = 'video/mp4';
2016
+ }
2017
+
2027
2018
  // TODO: Instead of feeding DrmEngine with Variants, we should refactor
2028
2019
  // DrmEngine so that it takes a minimal config derived from Variants. In
2029
2020
  // cases like this one or in removal of stored content, the details are
@@ -2044,7 +2035,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2044
2035
  createSegmentIndex: () => Promise.resolve(),
2045
2036
  segmentIndex: null,
2046
2037
  mimeType: wants.mimeType ?
2047
- shaka.util.MimeUtils.getBasicType(wants.mimeType) : 'video/mp4',
2038
+ shaka.util.MimeUtils.getBasicType(wants.mimeType) : mimeType,
2048
2039
  codecs: wants.mimeType ?
2049
2040
  shaka.util.MimeUtils.getCodecs(wants.mimeType) : '',
2050
2041
  encrypted: true,
@@ -2163,8 +2154,22 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2163
2154
  }
2164
2155
  if (this.video_.textTracks) {
2165
2156
  this.eventManager_.listen(this.video_.textTracks, 'addtrack', (e) => {
2166
- this.onTracksChanged_();
2167
- this.processTimedMetadataSrcEqls_(/** @type {!TrackEvent} */(e));
2157
+ const trackEvent = /** @type {!TrackEvent} */(e);
2158
+ if (trackEvent.track) {
2159
+ const track = trackEvent.track;
2160
+ goog.asserts.assert(track instanceof TextTrack, 'Wrong track type!');
2161
+ switch (track.kind) {
2162
+ case 'metadata':
2163
+ this.processTimedMetadataSrcEqls_(track);
2164
+ break;
2165
+ case 'chapters':
2166
+ this.processChaptersTrack_(track);
2167
+ break;
2168
+ default:
2169
+ this.onTracksChanged_();
2170
+ break;
2171
+ }
2172
+ }
2168
2173
  });
2169
2174
  this.eventManager_.listen(
2170
2175
  this.video_.textTracks, 'removetrack', () => this.onTracksChanged_());
@@ -2337,13 +2342,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2337
2342
  * We're looking for metadata tracks to process id3 tags. One of the uses is
2338
2343
  * for ad info on LIVE streams
2339
2344
  *
2340
- * @param {!TrackEvent} event
2345
+ * @param {!TextTrack} track
2341
2346
  * @private
2342
2347
  */
2343
- processTimedMetadataSrcEqls_(event) {
2344
- const track = event.track;
2345
- goog.asserts.assert(track instanceof TextTrack, 'Wrong track type!');
2346
-
2348
+ processTimedMetadataSrcEqls_(track) {
2347
2349
  if (track.kind != 'metadata') {
2348
2350
  return;
2349
2351
  }
@@ -2415,15 +2417,40 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2415
2417
  goog.asserts.assert(!endTime || startTime <= endTime,
2416
2418
  'Metadata start time should be less or equal to the end time!');
2417
2419
  const eventName = shaka.Player.EventName.Metadata;
2418
- const data = {
2419
- startTime: startTime,
2420
- endTime: endTime,
2421
- metadataType: metadataType,
2422
- payload: payload,
2423
- };
2420
+ const data = new Map()
2421
+ .set('startTime', startTime)
2422
+ .set('endTime', endTime)
2423
+ .set('metadataType', metadataType)
2424
+ .set('payload', payload);
2424
2425
  this.dispatchEvent(this.makeEvent_(eventName, data));
2425
2426
  }
2426
2427
 
2428
+ /**
2429
+ * We're looking for chapters tracks to process the chapters.
2430
+ *
2431
+ * @param {?TextTrack} track
2432
+ * @private
2433
+ */
2434
+ processChaptersTrack_(track) {
2435
+ if (!track || track.kind != 'chapters') {
2436
+ return;
2437
+ }
2438
+
2439
+ // Hidden mode is required for the cuechange event to launch correctly and
2440
+ // get the cues and the activeCues
2441
+ track.mode = 'hidden';
2442
+
2443
+ // In Safari the initial assignment does not always work, so we schedule
2444
+ // this process to be repeated several times to ensure that it has been put
2445
+ // in the correct mode.
2446
+ new shaka.util.Timer(() => {
2447
+ const chaptersTracks = this.getChaptersTracks_();
2448
+ for (const chaptersTrack of chaptersTracks) {
2449
+ chaptersTrack.mode = 'hidden';
2450
+ }
2451
+ }).tickNow().tickAfter(/* seconds= */ 0.5);
2452
+ }
2453
+
2427
2454
  /**
2428
2455
  * Take a series of variants and ensure that they only contain one type of
2429
2456
  * variant. The different options are:
@@ -2869,6 +2896,32 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2869
2896
  return this.config_;
2870
2897
  }
2871
2898
 
2899
+ /**
2900
+ * Returns the ratio of video length buffered compared to buffering Goal
2901
+ * @return {number}
2902
+ * @export
2903
+ */
2904
+ getBufferFullness() {
2905
+ if (this.video_) {
2906
+ const bufferedLength = this.video_.buffered.length;
2907
+ const bufferedEnd =
2908
+ bufferedLength ? this.video_.buffered.end(bufferedLength - 1) : 0;
2909
+ const bufferingGoal = this.getConfiguration().streaming.bufferingGoal;
2910
+ const lengthToBeBuffered = Math.min(this.video_.currentTime +
2911
+ bufferingGoal, this.seekRange().end);
2912
+
2913
+ if (bufferedEnd >= lengthToBeBuffered) {
2914
+ return 1;
2915
+ } else if (bufferedEnd <= this.video_.currentTime) {
2916
+ return 0;
2917
+ } else if (bufferedEnd < lengthToBeBuffered) {
2918
+ return ((bufferedEnd - this.video_.currentTime) /
2919
+ (lengthToBeBuffered - this.video_.currentTime));
2920
+ }
2921
+ }
2922
+ return 0;
2923
+ }
2924
+
2872
2925
  /**
2873
2926
  * Reset configuration to default.
2874
2927
  * @export
@@ -3079,6 +3132,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3079
3132
  return {'start': 0, 'end': 0};
3080
3133
  }
3081
3134
 
3135
+ /**
3136
+ * Go to live in a live stream.
3137
+ *
3138
+ * @export
3139
+ */
3140
+ goToLive() {
3141
+ if (this.isLive()) {
3142
+ this.video_.currentTime = this.seekRange().end;
3143
+ } else {
3144
+ shaka.log.warning('goToLive is for live streams!');
3145
+ }
3146
+ }
3147
+
3082
3148
  /**
3083
3149
  * Get the key system currently used by EME. If EME is not being used, this
3084
3150
  * will return an empty string. If the player has not loaded content, this
@@ -3103,6 +3169,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3103
3169
  return this.drmEngine_ ? this.drmEngine_.getDrmInfo() : null;
3104
3170
  }
3105
3171
 
3172
+
3173
+ /**
3174
+ * Get the drm engine.
3175
+ * This method should only be used for testing. Applications SHOULD NOT
3176
+ * use this in production.
3177
+ *
3178
+ * @return {?shaka.media.DrmEngine}
3179
+ */
3180
+ getDrmEngine() {
3181
+ return this.drmEngine_;
3182
+ }
3183
+
3184
+
3106
3185
  /**
3107
3186
  * Get the next known expiration time for any EME session. If the session
3108
3187
  * never expires, this will return <code>Infinity</code>. If there are no EME
@@ -3357,9 +3436,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3357
3436
  return null;
3358
3437
  }
3359
3438
  const reference = imageStream.segmentIndex.get(referencePosition);
3439
+ const tilesLayout =
3440
+ reference.getTilesLayout() || imageStream.tilesLayout;
3360
3441
  // This expression is used to detect one or more numbers (0-9) followed
3361
3442
  // by an x and after one or more numbers (0-9)
3362
- const match = /(\d+)x(\d+)/.exec(imageStream.tilesLayout);
3443
+ const match = /(\d+)x(\d+)/.exec(tilesLayout);
3363
3444
  if (!match) {
3364
3445
  shaka.log.warning('Tiles layout does not contain a valid format ' +
3365
3446
  ' (columns x rows)');
@@ -3599,36 +3680,34 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3599
3680
  new shaka.media.PreferenceBasedCriteria(language, role || '',
3600
3681
  /* channelCount= */ 0, /* label= */ '');
3601
3682
 
3602
- if (!this.config_.abr.enabled) {
3603
- const diff = (a, b) => {
3604
- if (!a.video && !b.video) {
3605
- return 0;
3606
- } else if (!a.video || !b.video) {
3607
- return Infinity;
3608
- } else {
3609
- return Math.abs((a.video.height || 0) - (b.video.height || 0)) +
3683
+ const diff = (a, b) => {
3684
+ if (!a.video && !b.video) {
3685
+ return 0;
3686
+ } else if (!a.video || !b.video) {
3687
+ return Infinity;
3688
+ } else {
3689
+ return Math.abs((a.video.height || 0) - (b.video.height || 0)) +
3610
3690
  Math.abs((a.video.width || 0) - (b.video.width || 0));
3611
- }
3612
- };
3691
+ }
3692
+ };
3613
3693
  // Find the variant whose size is closest to the active variant. This
3614
3694
  // ensures we stay at about the same resolution when just changing the
3615
3695
  // language/role.
3616
- const active = this.streamingEngine_.getCurrentVariant();
3617
- const set =
3696
+ const active = this.streamingEngine_.getCurrentVariant();
3697
+ const set =
3618
3698
  this.currentAdaptationSetCriteria_.create(this.manifest_.variants);
3619
- let bestVariant = null;
3620
- for (const curVariant of set.values()) {
3621
- if (!bestVariant ||
3699
+ let bestVariant = null;
3700
+ for (const curVariant of set.values()) {
3701
+ if (!bestVariant ||
3622
3702
  diff(bestVariant, active) > diff(curVariant, active)) {
3623
- bestVariant = curVariant;
3624
- }
3625
- }
3626
- if (bestVariant) {
3627
- const track = shaka.util.StreamUtils.variantToTrack(bestVariant);
3628
- this.selectVariantTrack(track, /* clearBuffer= */ true);
3629
- return;
3703
+ bestVariant = curVariant;
3630
3704
  }
3631
3705
  }
3706
+ if (bestVariant) {
3707
+ const track = shaka.util.StreamUtils.variantToTrack(bestVariant);
3708
+ this.selectVariantTrack(track, /* clearBuffer= */ true);
3709
+ return;
3710
+ }
3632
3711
 
3633
3712
  // If we haven't switched yet, just use ABR to find a new track.
3634
3713
  this.chooseVariantAndSwitch_();
@@ -3772,6 +3851,51 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3772
3851
  return expected;
3773
3852
  }
3774
3853
 
3854
+ /**
3855
+ * Return a list of chapters tracks.
3856
+ *
3857
+ * @return {!Array.<shaka.extern.Track>}
3858
+ * @export
3859
+ */
3860
+ getChaptersTracks() {
3861
+ if (this.video_ && this.video_.src && this.video_.textTracks) {
3862
+ const textTracks = this.getChaptersTracks_();
3863
+ const StreamUtils = shaka.util.StreamUtils;
3864
+ return textTracks.map((text) => StreamUtils.html5TextTrackToTrack(text));
3865
+ } else {
3866
+ return [];
3867
+ }
3868
+ }
3869
+
3870
+ /**
3871
+ * This returns the list of chapters.
3872
+ *
3873
+ * @param {string} language
3874
+ * @return {!Array.<shaka.extern.Chapter>}
3875
+ * @export
3876
+ */
3877
+ getChapters(language) {
3878
+ const LanguageUtils = shaka.util.LanguageUtils;
3879
+ const inputlanguage = LanguageUtils.normalize(language);
3880
+ const chaptersTracks = this.getChaptersTracks_();
3881
+ const chaptersTrack = chaptersTracks
3882
+ .find((t) => LanguageUtils.normalize(t.language) == inputlanguage);
3883
+ if (!chaptersTrack || !chaptersTrack.cues) {
3884
+ return [];
3885
+ }
3886
+ const chapters = [];
3887
+ for (const cue of chaptersTrack.cues) {
3888
+ /** @type {shaka.extern.Chapter} */
3889
+ const chapter = {
3890
+ title: cue.text,
3891
+ startTime: cue.startTime,
3892
+ endTime: cue.endTime,
3893
+ };
3894
+ chapters.push(chapter);
3895
+ }
3896
+ return chapters;
3897
+ }
3898
+
3775
3899
  /**
3776
3900
  * Ignore the TextTracks with the 'metadata' or 'chapters' kind, or the one
3777
3901
  * generated by the SimpleTextDisplayer.
@@ -3800,6 +3924,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3800
3924
  .filter((t) => t.kind == 'metadata');
3801
3925
  }
3802
3926
 
3927
+ /**
3928
+ * Get the TextTracks with the 'chapters' kind.
3929
+ *
3930
+ * @return {!Array.<TextTrack>}
3931
+ * @private
3932
+ */
3933
+ getChaptersTracks_() {
3934
+ goog.asserts.assert(this.video_.textTracks,
3935
+ 'TextTracks should be valid.');
3936
+ return Array.from(this.video_.textTracks)
3937
+ .filter((t) => t.kind == 'chapters');
3938
+ }
3939
+
3803
3940
  /**
3804
3941
  * Enable or disable the text displayer. If the player is in an unloaded
3805
3942
  * state, the request will be applied next time content is loaded.
@@ -4101,16 +4238,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4101
4238
  if (!mimeType) {
4102
4239
  // Try using the uri extension.
4103
4240
  const extension = shaka.media.ManifestParser.getExtension(uri);
4104
- mimeType = {
4105
- 'sbv': 'text/x-subviewer',
4106
- 'srt': 'text/srt',
4107
- 'vtt': 'text/vtt',
4108
- 'webvtt': 'text/vtt',
4109
- 'ttml': 'application/ttml+xml',
4110
- 'lrc': 'application/x-subtitle-lrc',
4111
- 'ssa': 'text/x-ssa',
4112
- 'ass': 'text/x-ssa',
4113
- }[extension];
4241
+ mimeType = shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_[extension];
4114
4242
 
4115
4243
  if (!mimeType) {
4116
4244
  shaka.log.error(
@@ -4258,74 +4386,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4258
4386
  }
4259
4387
 
4260
4388
  if (!mimeType) {
4261
- // Try using the uri extension.
4262
- const extension = shaka.media.ManifestParser.getExtension(uri);
4263
- mimeType = {
4264
- 'sbv': 'text/x-subviewer',
4265
- 'srt': 'text/srt',
4266
- 'vtt': 'text/vtt',
4267
- 'webvtt': 'text/vtt',
4268
- 'ttml': 'application/ttml+xml',
4269
- 'lrc': 'application/x-subtitle-lrc',
4270
- 'ssa': 'text/x-ssa',
4271
- 'ass': 'text/x-ssa',
4272
- }[extension];
4273
-
4274
- if (!mimeType) {
4275
- try {
4276
- goog.asserts.assert(
4277
- this.networkingEngine_, 'Need networking engine.');
4278
- // eslint-disable-next-line require-atomic-updates
4279
- mimeType = await shaka.media.ManifestParser.getMimeType(uri,
4280
- this.networkingEngine_,
4281
- this.config_.streaming.retryParameters);
4282
- } catch (error) {}
4283
- }
4389
+ mimeType = await this.getTextMimetype_(uri);
4390
+ }
4284
4391
 
4285
- if (!mimeType) {
4286
- shaka.log.error(
4287
- 'The mimeType has not been provided and it could not be deduced ' +
4288
- 'from its extension.');
4289
- throw new shaka.util.Error(
4290
- shaka.util.Error.Severity.RECOVERABLE,
4291
- shaka.util.Error.Category.TEXT,
4292
- shaka.util.Error.Code.TEXT_COULD_NOT_GUESS_MIME_TYPE,
4293
- extension);
4294
- }
4392
+ let adCuePoints = [];
4393
+ if (this.adManager_) {
4394
+ try {
4395
+ adCuePoints = this.adManager_.getServerSideCuePoints();
4396
+ } catch (error) {}
4295
4397
  }
4296
4398
 
4297
4399
  if (this.loadMode_ == shaka.Player.LoadMode.SRC_EQUALS) {
4298
- if (mimeType != 'text/vtt') {
4299
- goog.asserts.assert(
4300
- this.networkingEngine_, 'Need networking engine.');
4301
- const data = await this.getTextData_(uri,
4302
- this.networkingEngine_,
4303
- this.config_.streaming.retryParameters);
4304
- const vvtText = this.convertToWebVTT_(data, mimeType);
4305
- const blob = new Blob([vvtText], {type: 'text/vtt'});
4306
- uri = shaka.media.MediaSourceEngine.createObjectURL(blob);
4307
- mimeType = 'text/vtt';
4308
- }
4309
4400
  if (forced) {
4310
4401
  // See: https://github.com/whatwg/html/issues/4472
4311
4402
  kind = 'forced';
4312
4403
  }
4313
- const trackElement =
4314
- /** @type {!HTMLTrackElement} */(document.createElement('track'));
4315
- trackElement.src = uri;
4316
- trackElement.label = label || '';
4317
- trackElement.kind = kind;
4318
- trackElement.srclang = language;
4319
- // Because we're pulling in the text track file via Javascript, the
4320
- // same-origin policy applies. If you'd like to have a player served
4321
- // from one domain, but the text track served from another, you'll
4322
- // need to enable CORS in order to do so. In addition to enabling CORS
4323
- // on the server serving the text tracks, you will need to add the
4324
- // crossorigin attribute to the video element itself.
4325
- if (!this.video_.getAttribute('crossorigin')) {
4326
- this.video_.setAttribute('crossorigin', 'anonymous');
4327
- }
4328
- this.video_.appendChild(trackElement);
4404
+ await this.addSrcTrackElement_(uri, language, kind, mimeType, label || '',
4405
+ adCuePoints);
4329
4406
  const textTracks = this.getTextTracks();
4330
4407
  const srcTrack = textTracks.find((t) => {
4331
4408
  return t.language == language &&
@@ -4355,6 +4432,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4355
4432
  shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_TEXT_TO_LIVE_STREAM);
4356
4433
  }
4357
4434
 
4435
+ if (adCuePoints.length) {
4436
+ goog.asserts.assert(
4437
+ this.networkingEngine_, 'Need networking engine.');
4438
+ const data = await this.getTextData_(uri,
4439
+ this.networkingEngine_,
4440
+ this.config_.streaming.retryParameters);
4441
+ const vvtText = this.convertToWebVTT_(data, mimeType, adCuePoints);
4442
+ const blob = new Blob([vvtText], {type: 'text/vtt'});
4443
+ uri = shaka.media.MediaSourceEngine.createObjectURL(blob);
4444
+ mimeType = 'text/vtt';
4445
+ }
4446
+
4358
4447
  /** @type {shaka.extern.Stream} */
4359
4448
  const stream = {
4360
4449
  id: this.nextExternalStreamId_++,
@@ -4400,6 +4489,138 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4400
4489
  return shaka.util.StreamUtils.textStreamToTrack(stream);
4401
4490
  }
4402
4491
 
4492
+ /**
4493
+ * Adds the given chapters track to the loaded manifest. <code>load()</code>
4494
+ * must resolve before calling. The presentation must have a duration.
4495
+ *
4496
+ * This returns the created track.
4497
+ *
4498
+ * @param {string} uri
4499
+ * @param {string} language
4500
+ * @param {string=} mimeType
4501
+ * @return {!Promise.<shaka.extern.Track>}
4502
+ * @export
4503
+ */
4504
+ async addChaptersTrack(uri, language, mimeType) {
4505
+ if (this.loadMode_ != shaka.Player.LoadMode.MEDIA_SOURCE &&
4506
+ this.loadMode_ != shaka.Player.LoadMode.SRC_EQUALS) {
4507
+ shaka.log.error(
4508
+ 'Must call load() and wait for it to resolve before adding ' +
4509
+ 'chapters tracks.');
4510
+ throw new shaka.util.Error(
4511
+ shaka.util.Error.Severity.RECOVERABLE,
4512
+ shaka.util.Error.Category.PLAYER,
4513
+ shaka.util.Error.Code.CONTENT_NOT_LOADED);
4514
+ }
4515
+
4516
+ if (!mimeType) {
4517
+ mimeType = await this.getTextMimetype_(uri);
4518
+ }
4519
+ let adCuePoints = [];
4520
+ if (this.adManager_) {
4521
+ try {
4522
+ adCuePoints = this.adManager_.getServerSideCuePoints();
4523
+ } catch (error) {}
4524
+ }
4525
+ await this.addSrcTrackElement_(uri, language, /* kind= */ 'chapters',
4526
+ mimeType, /* label= */ '', adCuePoints);
4527
+ const chaptersTracks = this.getChaptersTracks();
4528
+ const chaptersTrack = chaptersTracks.find((t) => {
4529
+ return t.language == language;
4530
+ });
4531
+ if (chaptersTrack) {
4532
+ const html5ChaptersTracks = this.getChaptersTracks_();
4533
+ for (const html5ChaptersTrack of html5ChaptersTracks) {
4534
+ this.processChaptersTrack_(html5ChaptersTrack);
4535
+ }
4536
+ return chaptersTrack;
4537
+ }
4538
+ // This should not happen, but there are browser implementations that may
4539
+ // not support the Track element.
4540
+ shaka.log.error('Cannot add this text when loaded with src=');
4541
+ throw new shaka.util.Error(
4542
+ shaka.util.Error.Severity.RECOVERABLE,
4543
+ shaka.util.Error.Category.TEXT,
4544
+ shaka.util.Error.Code.CANNOT_ADD_EXTERNAL_TEXT_TO_SRC_EQUALS);
4545
+ }
4546
+
4547
+ /**
4548
+ * @param {string} uri
4549
+ * @return {!Promise.<string>}
4550
+ * @private
4551
+ */
4552
+ async getTextMimetype_(uri) {
4553
+ // Try using the uri extension.
4554
+ const extension = shaka.media.ManifestParser.getExtension(uri);
4555
+ let mimeType = shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_[extension];
4556
+
4557
+ if (mimeType) {
4558
+ return mimeType;
4559
+ }
4560
+
4561
+ try {
4562
+ goog.asserts.assert(
4563
+ this.networkingEngine_, 'Need networking engine.');
4564
+ // eslint-disable-next-line require-atomic-updates
4565
+ mimeType = await shaka.media.ManifestParser.getMimeType(uri,
4566
+ this.networkingEngine_,
4567
+ this.config_.streaming.retryParameters);
4568
+ } catch (error) {}
4569
+
4570
+ if (mimeType) {
4571
+ return mimeType;
4572
+ }
4573
+
4574
+ shaka.log.error(
4575
+ 'The mimeType has not been provided and it could not be deduced ' +
4576
+ 'from its extension.');
4577
+ throw new shaka.util.Error(
4578
+ shaka.util.Error.Severity.RECOVERABLE,
4579
+ shaka.util.Error.Category.TEXT,
4580
+ shaka.util.Error.Code.TEXT_COULD_NOT_GUESS_MIME_TYPE,
4581
+ extension);
4582
+ }
4583
+
4584
+ /**
4585
+ * @param {string} uri
4586
+ * @param {string} language
4587
+ * @param {string} kind
4588
+ * @param {string} mimeType
4589
+ * @param {string} label
4590
+ * @param {!Array.<!shaka.extern.AdCuePoint>} adCuePoints
4591
+ * @private
4592
+ */
4593
+ async addSrcTrackElement_(uri, language, kind, mimeType, label,
4594
+ adCuePoints) {
4595
+ if (mimeType != 'text/vtt' || adCuePoints.length) {
4596
+ goog.asserts.assert(
4597
+ this.networkingEngine_, 'Need networking engine.');
4598
+ const data = await this.getTextData_(uri,
4599
+ this.networkingEngine_,
4600
+ this.config_.streaming.retryParameters);
4601
+ const vvtText = this.convertToWebVTT_(data, mimeType, adCuePoints);
4602
+ const blob = new Blob([vvtText], {type: 'text/vtt'});
4603
+ uri = shaka.media.MediaSourceEngine.createObjectURL(blob);
4604
+ mimeType = 'text/vtt';
4605
+ }
4606
+ const trackElement =
4607
+ /** @type {!HTMLTrackElement} */(document.createElement('track'));
4608
+ trackElement.src = uri;
4609
+ trackElement.label = label;
4610
+ trackElement.kind = kind;
4611
+ trackElement.srclang = language;
4612
+ // Because we're pulling in the text track file via Javascript, the
4613
+ // same-origin policy applies. If you'd like to have a player served
4614
+ // from one domain, but the text track served from another, you'll
4615
+ // need to enable CORS in order to do so. In addition to enabling CORS
4616
+ // on the server serving the text tracks, you will need to add the
4617
+ // crossorigin attribute to the video element itself.
4618
+ if (!this.video_.getAttribute('crossorigin')) {
4619
+ this.video_.setAttribute('crossorigin', 'anonymous');
4620
+ }
4621
+ this.video_.appendChild(trackElement);
4622
+ }
4623
+
4403
4624
  /**
4404
4625
  * @param {string} uri
4405
4626
  * @param {!shaka.net.NetworkingEngine} netEngine
@@ -4424,10 +4645,11 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4424
4645
  *
4425
4646
  * @param {BufferSource} buffer
4426
4647
  * @param {string} mimeType
4648
+ * @param {!Array.<!shaka.extern.AdCuePoint>} adCuePoints
4427
4649
  * @return {string}
4428
4650
  * @private
4429
4651
  */
4430
- convertToWebVTT_(buffer, mimeType) {
4652
+ convertToWebVTT_(buffer, mimeType, adCuePoints) {
4431
4653
  const factory = shaka.text.TextEngine.findParser(mimeType);
4432
4654
  if (factory) {
4433
4655
  const obj = factory();
@@ -4438,7 +4660,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4438
4660
  };
4439
4661
  const data = shaka.util.BufferUtils.toUint8(buffer);
4440
4662
  const cues = obj.parseMedia(data, time);
4441
- return shaka.text.WebVttGenerator.convert(cues);
4663
+ return shaka.text.WebVttGenerator.convert(cues, adCuePoints);
4442
4664
  }
4443
4665
  throw new shaka.util.Error(
4444
4666
  shaka.util.Error.Severity.CRITICAL,
@@ -4680,8 +4902,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4680
4902
  this.streamingEngine_.getCurrentVariant() : null;
4681
4903
 
4682
4904
  await shaka.util.StreamUtils.filterManifest(
4683
- this.drmEngine_, currentVariant, manifest,
4684
- this.config_.useMediaCapabilities);
4905
+ this.drmEngine_, currentVariant, manifest);
4685
4906
  this.checkPlayableVariants_(manifest);
4686
4907
  }
4687
4908
 
@@ -4816,7 +5037,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4816
5037
  // Surface the buffering event so that the app knows if/when we are
4817
5038
  // buffering.
4818
5039
  const eventName = shaka.Player.EventName.Buffering;
4819
- this.dispatchEvent(this.makeEvent_(eventName, {'buffering': isBuffering}));
5040
+ const data = (new Map()).set('buffering', isBuffering);
5041
+ this.dispatchEvent(this.makeEvent_(eventName, data));
4820
5042
  }
4821
5043
 
4822
5044
  /**
@@ -4984,9 +5206,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4984
5206
  if (chosenVariant) {
4985
5207
  this.switchVariant_(chosenVariant, /* fromAdaptation= */ true,
4986
5208
  /* clearBuffers= */ true, /* safeMargin= */ 0);
4987
- // Send an adaptation event so that the UI can show the new
4988
- // language/tracks.
4989
- this.onAdaptation_();
4990
5209
  }
4991
5210
  }
4992
5211
 
@@ -5017,8 +5236,14 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5017
5236
  oldTrack = shaka.util.StreamUtils.variantToTrack(currentVariant);
5018
5237
  }
5019
5238
  const newTrack = shaka.util.StreamUtils.variantToTrack(variant);
5020
- // Dispatch a 'variantchanged' event
5021
- this.onVariantChanged_(oldTrack, newTrack);
5239
+
5240
+ if (fromAdaptation) {
5241
+ // Dispatch an 'adaptation' event
5242
+ this.onAdaptation_(oldTrack, newTrack);
5243
+ } else {
5244
+ // Dispatch a 'variantchanged' event
5245
+ this.onVariantChanged_(oldTrack, newTrack);
5246
+ }
5022
5247
  }
5023
5248
 
5024
5249
  /**
@@ -5162,19 +5387,23 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5162
5387
  return;
5163
5388
  }
5164
5389
 
5165
- this.addVariantToSwitchHistory_(variant, /* fromAdaptation= */ true);
5166
- this.streamingEngine_.switchVariant(variant, clearBuffer, safeMargin);
5167
- this.onAdaptation_();
5390
+ this.switchVariant_(variant, /* fromAdaptation= */ true,
5391
+ clearBuffer, safeMargin);
5168
5392
  }
5169
5393
 
5170
5394
  /**
5171
5395
  * Dispatches an 'adaptation' event.
5396
+ * @param {?shaka.extern.Track} from
5397
+ * @param {shaka.extern.Track} to
5172
5398
  * @private
5173
5399
  */
5174
- onAdaptation_() {
5400
+ onAdaptation_(from, to) {
5175
5401
  // Delay the 'adaptation' event so that StreamingEngine has time to absorb
5176
5402
  // the changes before the user tries to query it.
5177
- const event = this.makeEvent_(shaka.Player.EventName.Adaptation);
5403
+ const data = new Map()
5404
+ .set('oldTrack', from)
5405
+ .set('newTrack', to);
5406
+ const event = this.makeEvent_(shaka.Player.EventName.Adaptation, data);
5178
5407
  this.delayDispatchEvent_(event);
5179
5408
  }
5180
5409
 
@@ -5198,10 +5427,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5198
5427
  onVariantChanged_(from, to) {
5199
5428
  // Delay the 'variantchanged' event so StreamingEngine has time to absorb
5200
5429
  // the changes before the user tries to query it.
5201
- const event = this.makeEvent_(shaka.Player.EventName.VariantChanged, {
5202
- oldTrack: from,
5203
- newTrack: to,
5204
- });
5430
+ const data = new Map()
5431
+ .set('oldTrack', from)
5432
+ .set('newTrack', to);
5433
+ const event = this.makeEvent_(shaka.Player.EventName.VariantChanged, data);
5205
5434
  this.delayDispatchEvent_(event);
5206
5435
  }
5207
5436
 
@@ -5224,10 +5453,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5224
5453
 
5225
5454
  /** @private */
5226
5455
  onAbrStatusChanged_() {
5227
- const event = this.makeEvent_(shaka.Player.EventName.AbrStatusChanged, {
5228
- newStatus: this.config_.abr.enabled,
5229
- });
5230
- this.delayDispatchEvent_(event);
5456
+ const data = (new Map()).set('newStatus', this.config_.abr.enabled);
5457
+ this.delayDispatchEvent_(this.makeEvent_(
5458
+ shaka.Player.EventName.AbrStatusChanged, data));
5231
5459
  }
5232
5460
 
5233
5461
  /**
@@ -5244,7 +5472,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5244
5472
  }
5245
5473
 
5246
5474
  const eventName = shaka.Player.EventName.Error;
5247
- const event = this.makeEvent_(eventName, {'detail': error});
5475
+ const event = this.makeEvent_(eventName, (new Map()).set('detail', error));
5248
5476
  this.dispatchEvent(event);
5249
5477
  if (event.defaultPrevented) {
5250
5478
  error.handled = true;
@@ -5273,7 +5501,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
5273
5501
  eventElement: region.eventElement,
5274
5502
  };
5275
5503
 
5276
- this.dispatchEvent(this.makeEvent_(eventName, {detail: clone}));
5504
+ const data = (new Map()).set('detail', clone);
5505
+ this.dispatchEvent(this.makeEvent_(eventName, data));
5277
5506
  }
5278
5507
 
5279
5508
  /**
@@ -6102,7 +6331,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
6102
6331
  * @define {string} A version number taken from git at compile time.
6103
6332
  * @export
6104
6333
  */
6105
- shaka.Player.version = 'v3.1.3-uncompiled';
6334
+ shaka.Player.version = 'v3.2.2-uncompiled';
6106
6335
 
6107
6336
  // Initialize the deprecation system using the version string we just set
6108
6337
  // on the player.
@@ -6129,6 +6358,47 @@ shaka.Player.supportPlugins_ = {};
6129
6358
  shaka.Player.adManagerFactory_ = null;
6130
6359
 
6131
6360
 
6361
+ /**
6362
+ * @const {!Object.<string, string>}
6363
+ * @private
6364
+ */
6365
+ shaka.Player.SRC_EQUAL_EXTENSIONS_TO_MIME_TYPES_ = {
6366
+ 'mp4': 'video/mp4',
6367
+ 'm4v': 'video/mp4',
6368
+ 'm4a': 'audio/mp4',
6369
+ 'webm': 'video/webm',
6370
+ 'weba': 'audio/webm',
6371
+ 'mkv': 'video/webm', // Chromium browsers supports it.
6372
+ 'ts': 'video/mp2t',
6373
+ 'ogv': 'video/ogg',
6374
+ 'ogg': 'audio/ogg',
6375
+ 'mpg': 'video/mpeg',
6376
+ 'mpeg': 'video/mpeg',
6377
+ 'm3u8': 'application/x-mpegurl',
6378
+ 'mpd': 'application/dash+xml',
6379
+ 'mp3': 'audio/mpeg',
6380
+ 'aac': 'audio/aac',
6381
+ 'flac': 'audio/flac',
6382
+ 'wav': 'audio/wav',
6383
+ };
6384
+
6385
+
6386
+ /**
6387
+ * @const {!Object.<string, string>}
6388
+ * @private
6389
+ */
6390
+ shaka.Player.TEXT_EXTENSIONS_TO_MIME_TYPES_ = {
6391
+ 'sbv': 'text/x-subviewer',
6392
+ 'srt': 'text/srt',
6393
+ 'vtt': 'text/vtt',
6394
+ 'webvtt': 'text/vtt',
6395
+ 'ttml': 'application/ttml+xml',
6396
+ 'lrc': 'application/x-subtitle-lrc',
6397
+ 'ssa': 'text/x-ssa',
6398
+ 'ass': 'text/x-ssa',
6399
+ };
6400
+
6401
+
6132
6402
  /**
6133
6403
  * @const {string}
6134
6404
  */