shaka-player 3.2.1 → 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
  3. package/.github/ISSUE_TEMPLATE/question.md +1 -1
  4. package/AUTHORS +9 -5
  5. package/CHANGELOG.md +358 -0
  6. package/CONTRIBUTORS +7 -2
  7. package/build/conformance.textproto +183 -169
  8. package/build/generateExterns.js +1 -1
  9. package/build/types/core +3 -0
  10. package/build/types/offline +1 -0
  11. package/build/types/polyfill +1 -0
  12. package/build/types/ui +2 -0
  13. package/demo/common/assets.js +19 -1
  14. package/demo/common/message_ids.js +13 -1
  15. package/demo/config.js +31 -1
  16. package/demo/index.html +1 -1
  17. package/demo/locales/en.json +12 -0
  18. package/demo/locales/source.json +48 -0
  19. package/dist/controls.css +26 -2
  20. package/dist/controls.css.map +1 -1
  21. package/dist/demo.compiled.debug.js +20 -17
  22. package/dist/demo.compiled.debug.map +3 -3
  23. package/dist/demo.compiled.js +20 -17
  24. package/dist/demo.compiled.map +3 -3
  25. package/dist/deps.js +19 -12
  26. package/dist/locales.js +39 -37
  27. package/dist/receiver.compiled.debug.js +12 -10
  28. package/dist/receiver.compiled.debug.map +3 -3
  29. package/dist/receiver.compiled.js +12 -10
  30. package/dist/receiver.compiled.map +3 -3
  31. package/dist/shaka-player.compiled.d.ts +231 -18
  32. package/dist/shaka-player.compiled.debug.d.ts +231 -18
  33. package/dist/shaka-player.compiled.debug.externs.js +279 -8
  34. package/dist/shaka-player.compiled.debug.js +512 -449
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +279 -8
  37. package/dist/shaka-player.compiled.js +854 -821
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +247 -19
  40. package/dist/shaka-player.ui.debug.d.ts +247 -19
  41. package/dist/shaka-player.ui.debug.externs.js +307 -9
  42. package/dist/shaka-player.ui.debug.js +662 -580
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +307 -9
  45. package/dist/shaka-player.ui.js +1047 -1000
  46. package/dist/shaka-player.ui.map +4 -4
  47. package/docs/design/bg-fetch-after.gv +29 -0
  48. package/docs/design/bg-fetch-after.gv.png +0 -0
  49. package/docs/design/bg-fetch-before.gv +18 -0
  50. package/docs/design/bg-fetch-before.gv.png +0 -0
  51. package/docs/design/bg-fetch.md +134 -0
  52. package/docs/tutorials/blob-url.md +15 -0
  53. package/docs/tutorials/fairplay.md +1 -1
  54. package/docs/tutorials/index.json +1 -0
  55. package/docs/tutorials/ui-customization.md +66 -0
  56. package/docs/tutorials/ui.md +5 -5
  57. package/externs/cmcd.js +186 -0
  58. package/externs/ima.js +3 -0
  59. package/externs/shaka/ads.js +5 -0
  60. package/externs/shaka/manifest.js +12 -1
  61. package/externs/shaka/manifest_parser.js +10 -1
  62. package/externs/shaka/net.js +20 -4
  63. package/externs/shaka/offline.js +31 -2
  64. package/externs/shaka/player.js +138 -5
  65. package/externs/shaka/text.js +24 -0
  66. package/externs/webcrypto.js +18 -0
  67. package/karma.conf.js +1 -0
  68. package/lib/abr/ewma.js +14 -0
  69. package/lib/abr/ewma_bandwidth_estimator.js +16 -2
  70. package/lib/abr/simple_abr_manager.js +6 -0
  71. package/lib/ads/client_side_ad.js +8 -0
  72. package/lib/ads/client_side_ad_manager.js +54 -90
  73. package/lib/ads/server_side_ad.js +7 -0
  74. package/lib/ads/server_side_ad_manager.js +7 -10
  75. package/lib/cast/cast_proxy.js +3 -2
  76. package/lib/cast/cast_receiver.js +2 -1
  77. package/lib/cast/cast_sender.js +2 -2
  78. package/lib/cast/cast_utils.js +1 -0
  79. package/lib/dash/dash_parser.js +141 -16
  80. package/lib/dash/segment_base.js +25 -1
  81. package/lib/dash/segment_list.js +19 -10
  82. package/lib/dash/segment_template.js +24 -11
  83. package/lib/hls/hls_parser.js +146 -40
  84. package/lib/media/drm_engine.js +7 -0
  85. package/lib/media/gap_jumping_controller.js +4 -2
  86. package/lib/media/media_source_engine.js +1 -2
  87. package/lib/media/quality_observer.js +291 -0
  88. package/lib/media/segment_index.js +8 -1
  89. package/lib/media/segment_reference.js +37 -4
  90. package/lib/media/streaming_engine.js +49 -7
  91. package/lib/net/http_fetch_plugin.js +31 -11
  92. package/lib/net/http_plugin_utils.js +1 -0
  93. package/lib/net/http_xhr_plugin.js +40 -14
  94. package/lib/net/networking_engine.js +83 -19
  95. package/lib/offline/download_info.js +68 -0
  96. package/lib/offline/download_manager.js +13 -5
  97. package/lib/offline/indexeddb/base_storage_cell.js +35 -0
  98. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  99. package/lib/offline/indexeddb/v5_storage_cell.js +5 -0
  100. package/lib/offline/storage.js +393 -284
  101. package/lib/offline/stored_content_utils.js +2 -0
  102. package/lib/player.js +249 -43
  103. package/lib/polyfill/media_capabilities.js +36 -15
  104. package/lib/polyfill/mediasource.js +6 -0
  105. package/lib/polyfill/orientation.js +1 -1
  106. package/lib/polyfill/patchedmediakeys_apple.js +4 -4
  107. package/lib/polyfill/patchedmediakeys_ms.js +4 -4
  108. package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
  109. package/lib/polyfill/random_uuid.js +52 -0
  110. package/lib/text/cue.js +18 -0
  111. package/lib/text/mp4_ttml_parser.js +3 -0
  112. package/lib/text/text_engine.js +14 -2
  113. package/lib/text/ttml_text_parser.js +114 -60
  114. package/lib/text/ui_text_displayer.js +95 -41
  115. package/lib/util/cmcd_manager.js +672 -0
  116. package/lib/util/error.js +6 -0
  117. package/lib/util/fake_event.js +53 -7
  118. package/lib/util/language_utils.js +12 -0
  119. package/lib/util/mutex.js +52 -0
  120. package/lib/util/periods.js +102 -65
  121. package/lib/util/platform.js +13 -1
  122. package/lib/util/player_configuration.js +18 -0
  123. package/lib/util/stream_utils.js +99 -10
  124. package/lib/util/xml_utils.js +19 -0
  125. package/package.json +2 -2
  126. package/shaka-player.uncompiled.js +3 -0
  127. package/test/cast/cast_proxy_unit.js +12 -6
  128. package/test/cast/cast_utils_unit.js +1 -1
  129. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  130. package/test/dash/dash_parser_live_unit.js +101 -1
  131. package/test/dash/dash_parser_manifest_unit.js +222 -2
  132. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  133. package/test/dash/dash_parser_segment_list_unit.js +2 -1
  134. package/test/dash/dash_parser_segment_template_unit.js +2 -1
  135. package/test/hls/hls_live_unit.js +2 -0
  136. package/test/hls/hls_parser_unit.js +7 -1
  137. package/test/media/closed_caption_parser_unit.js +6 -1
  138. package/test/media/drm_engine_unit.js +47 -3
  139. package/test/media/quality_observer_unit.js +139 -0
  140. package/test/media/segment_reference_unit.js +16 -1
  141. package/test/media/streaming_engine_integration.js +4 -2
  142. package/test/media/streaming_engine_unit.js +147 -0
  143. package/test/net/http_plugin_unit.js +20 -15
  144. package/test/offline/storage_integration.js +108 -4
  145. package/test/player_integration.js +178 -8
  146. package/test/player_src_equals_integration.js +41 -8
  147. package/test/player_unit.js +19 -9
  148. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  149. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  150. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  151. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  152. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  153. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  154. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  155. package/test/test/assets/3675/dash_0.mpd +30 -0
  156. package/test/test/assets/3675/dash_1.mpd +30 -0
  157. package/test/test/assets/3675/dash_2.mpd +30 -0
  158. package/test/test/assets/3675/dash_3.mpd +30 -0
  159. package/test/test/assets/3675/dash_4.mpd +30 -0
  160. package/test/test/assets/3675/dash_5.mpd +26 -0
  161. package/test/test/assets/3675/init-stream0.m4s +0 -0
  162. package/test/test/assets/chapters.vtt +2 -2
  163. package/test/test/assets/chapters2.vtt +10 -0
  164. package/test/test/util/dash_parser_util.js +4 -0
  165. package/test/test/util/fake_ad.js +7 -0
  166. package/test/test/util/fake_ad_manager.js +1 -1
  167. package/test/test/util/fake_drm_engine.js +9 -2
  168. package/test/test/util/manifest_generator.js +3 -2
  169. package/test/test/util/test_scheme.js +14 -1
  170. package/test/test/util/ttml_utils.js +81 -0
  171. package/test/text/mp4_ttml_parser_unit.js +11 -18
  172. package/test/text/ttml_text_parser_unit.js +552 -227
  173. package/test/text/ui_text_displayer_unit.js +29 -17
  174. package/test/ui/localization_unit.js +15 -14
  175. package/test/ui/text_displayer_layout_unit.js +13 -1
  176. package/test/ui/ui_unit.js +250 -0
  177. package/test/util/cmcd_manager_unit.js +291 -0
  178. package/test/util/stream_utils_unit.js +45 -4
  179. package/third_party/closure-uri/uri.js +21 -0
  180. package/ui/airplay_button.js +1 -0
  181. package/ui/audio_language_selection.js +7 -0
  182. package/ui/cast_button.js +3 -3
  183. package/ui/context_menu.js +109 -0
  184. package/ui/controls.js +45 -13
  185. package/ui/controls.less +1 -0
  186. package/ui/enums.js +4 -0
  187. package/ui/externs/ui.js +28 -1
  188. package/ui/fast_forward_button.js +14 -5
  189. package/ui/fullscreen_button.js +1 -0
  190. package/ui/less/buttons.less +0 -4
  191. package/ui/less/containers.less +77 -7
  192. package/ui/less/overflow_menu.less +0 -10
  193. package/ui/less/tooltip.less +97 -0
  194. package/ui/locales/en.json +1 -0
  195. package/ui/locales/ru.json +6 -6
  196. package/ui/locales/source.json +4 -0
  197. package/ui/localization.js +28 -51
  198. package/ui/loop_button.js +5 -0
  199. package/ui/mute_button.js +2 -1
  200. package/ui/overflow_menu.js +5 -25
  201. package/ui/pip_button.js +7 -3
  202. package/ui/play_button.js +2 -2
  203. package/ui/playback_rate_selection.js +8 -9
  204. package/ui/resolution_selection.js +7 -0
  205. package/ui/rewind_button.js +15 -6
  206. package/ui/seek_bar.js +4 -2
  207. package/ui/settings_menu.js +36 -4
  208. package/ui/small_play_button.js +1 -0
  209. package/ui/statistics_button.js +253 -0
  210. package/ui/text_selection.js +12 -4
  211. package/ui/ui.js +30 -0
  212. package/ui/volume_bar.js +1 -1
  213. package/externs/media_capabilities.js +0 -16
@@ -419,13 +419,48 @@ shaka.util.StreamUtils = class {
419
419
  */
420
420
  static async filterManifestByMediaCapabilities(
421
421
  manifest, usePersistentLicenses) {
422
- goog.asserts.assert(window.shakaMediaCapabilities,
422
+ goog.asserts.assert(navigator.mediaCapabilities,
423
423
  'MediaCapabilities should be valid.');
424
424
 
425
425
  await shaka.util.StreamUtils.getDecodingInfosForVariants(
426
426
  manifest.variants, usePersistentLicenses, /* srcEquals= */ false);
427
427
  manifest.variants = manifest.variants.filter((variant) => {
428
+ // See: https://github.com/google/shaka-player/issues/3860
428
429
  const video = variant.video;
430
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
431
+ if (video) {
432
+ let videoCodecs = shaka.util.StreamUtils.patchVp9(video.codecs);
433
+ // For multiplexed streams. Here we must check the audio of the
434
+ // stream to see if it is compatible.
435
+ if (video.codecs.includes(',')) {
436
+ const allCodecs = video.codecs.split(',');
437
+ videoCodecs = shaka.util.ManifestParserUtils.guessCodecs(
438
+ ContentType.VIDEO, allCodecs);
439
+ const audioCodecs = shaka.util.ManifestParserUtils.guessCodecs(
440
+ ContentType.AUDIO, allCodecs);
441
+ const audioFullType = shaka.util.MimeUtils.getFullOrConvertedType(
442
+ video.mimeType, audioCodecs, ContentType.AUDIO);
443
+ if (!MediaSource.isTypeSupported(audioFullType)) {
444
+ return false;
445
+ }
446
+ }
447
+ const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
448
+ video.mimeType, videoCodecs, ContentType.VIDEO);
449
+ if (!MediaSource.isTypeSupported(fullType)) {
450
+ return false;
451
+ }
452
+ }
453
+ const audio = variant.audio;
454
+ if (audio) {
455
+ const codecs =
456
+ shaka.util.StreamUtils.getCorrectAudioCodecs_(audio.codecs);
457
+ const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
458
+ audio.mimeType, codecs, ContentType.AUDIO);
459
+ if (!MediaSource.isTypeSupported(fullType)) {
460
+ return false;
461
+ }
462
+ }
463
+
429
464
  // See: https://github.com/google/shaka-player/issues/3380
430
465
  if (shaka.util.Platform.isXboxOne() && video &&
431
466
  ((video.width && video.width > 1920) ||
@@ -468,7 +503,7 @@ shaka.util.StreamUtils = class {
468
503
  return;
469
504
  }
470
505
 
471
- const mediaCapabilities = window.shakaMediaCapabilities;
506
+ const mediaCapabilities = navigator.mediaCapabilities;
472
507
 
473
508
  const operations = [];
474
509
  const getVariantDecodingInfos = (async (variant, decodingConfig) => {
@@ -547,14 +582,23 @@ shaka.util.StreamUtils = class {
547
582
  // framerate must be greater than 0, otherwise the config is invalid.
548
583
  framerate: video.frameRate || 1,
549
584
  };
585
+ if (video.hdr) {
586
+ switch (video.hdr) {
587
+ case 'SDR':
588
+ mediaDecodingConfig.video.transferFunction = 'srgb';
589
+ break;
590
+ case 'PQ':
591
+ mediaDecodingConfig.video.transferFunction = 'pq';
592
+ break;
593
+ case 'HLG':
594
+ mediaDecodingConfig.video.transferFunction = 'hlg';
595
+ break;
596
+ }
597
+ }
550
598
  }
551
599
  if (audio) {
552
- // Some Tizen devices seem to misreport AC-3 support, but correctly
553
- // report EC-3 support. So query EC-3 as a fallback for AC-3.
554
- // See https://github.com/google/shaka-player/issues/2989 for details.
555
600
  const codecs =
556
- (audio.codecs.toLowerCase() == 'ac-3' &&
557
- shaka.util.Platform.isTizen()) ? 'ec-3' : audio.codecs;
601
+ shaka.util.StreamUtils.getCorrectAudioCodecs_(audio.codecs);
558
602
  const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
559
603
  audio.mimeType, codecs, ContentType.AUDIO);
560
604
 
@@ -665,6 +709,26 @@ shaka.util.StreamUtils = class {
665
709
  return configs;
666
710
  }
667
711
 
712
+
713
+ /**
714
+ * Generates the correct audio codec for MediaDecodingConfiguration and
715
+ * for MediaSource.isTypeSupported.
716
+ * @param {string} codecs
717
+ * @return {string}
718
+ * @private
719
+ */
720
+ static getCorrectAudioCodecs_(codecs) {
721
+ // Some Tizen devices seem to misreport AC-3 support, but correctly
722
+ // report EC-3 support. So query EC-3 as a fallback for AC-3.
723
+ // See https://github.com/google/shaka-player/issues/2989 for details.
724
+ if (shaka.util.Platform.isTizen()) {
725
+ return codecs.toLowerCase() == 'ac-3' ? 'ec-3' : codecs;
726
+ } else {
727
+ return codecs;
728
+ }
729
+ }
730
+
731
+
668
732
  /**
669
733
  * MediaCapabilities supports 'vp09...' codecs, but not 'vp9'. Translate vp9
670
734
  * codec strings into 'vp09...', to allow such content to play with
@@ -976,6 +1040,31 @@ shaka.util.StreamUtils = class {
976
1040
  static imageStreamToTrack(stream) {
977
1041
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
978
1042
 
1043
+ let width = stream.width || null;
1044
+ let height = stream.height || null;
1045
+
1046
+ // The stream width and height represent the size of the entire thumbnail
1047
+ // sheet, so divide by the layout.
1048
+ let reference = null;
1049
+ // Note: segmentIndex is built by default for HLS, but not for DASH, but
1050
+ // in DASH this information comes at the stream level and not at the
1051
+ // segment level.
1052
+ if (stream.segmentIndex) {
1053
+ reference = stream.segmentIndex.get(0);
1054
+ }
1055
+ let layout = stream.tilesLayout;
1056
+ if (reference) {
1057
+ layout = reference.getTilesLayout() || layout;
1058
+ }
1059
+ if (layout && width != null) {
1060
+ width /= Number(layout.split('x')[0]);
1061
+ }
1062
+ if (layout && height != null) {
1063
+ height /= Number(layout.split('x')[1]);
1064
+ }
1065
+ // TODO: What happens if there are multiple grids, with different
1066
+ // layout sizes, inside this image stream?
1067
+
979
1068
  /** @type {shaka.extern.Track} */
980
1069
  const track = {
981
1070
  id: stream.id,
@@ -985,8 +1074,8 @@ shaka.util.StreamUtils = class {
985
1074
  language: '',
986
1075
  label: null,
987
1076
  kind: null,
988
- width: stream.width || null,
989
- height: stream.height || null,
1077
+ width,
1078
+ height,
990
1079
  frameRate: null,
991
1080
  pixelAspectRatio: null,
992
1081
  hdr: null,
@@ -1003,7 +1092,7 @@ shaka.util.StreamUtils = class {
1003
1092
  channelsCount: null,
1004
1093
  audioSamplingRate: null,
1005
1094
  spatialAudio: false,
1006
- tilesLayout: stream.tilesLayout || null,
1095
+ tilesLayout: layout || null,
1007
1096
  audioBandwidth: null,
1008
1097
  videoBandwidth: null,
1009
1098
  originalVideoId: null,
@@ -103,6 +103,25 @@ shaka.util.XmlUtils = class {
103
103
  }
104
104
 
105
105
 
106
+ /**
107
+ * Gets a namespace-qualified attribute.
108
+ * @param {!Element} elem The element to get from.
109
+ * @param {!Array.<string>} nsList The lis of namespace URIs.
110
+ * @param {string} name The local name of the attribute.
111
+ * @return {?string} The attribute's value, or null if not present.
112
+ */
113
+ static getAttributeNSList(elem, nsList, name) {
114
+ // Some browsers return the empty string when the attribute is missing,
115
+ // so check if it exists first. See: https://mzl.la/2L7F0UK
116
+ for (const ns of nsList) {
117
+ if (elem.hasAttributeNS(ns, name)) {
118
+ return elem.getAttributeNS(ns, name);
119
+ }
120
+ }
121
+ return null;
122
+ }
123
+
124
+
106
125
  /**
107
126
  * Gets the text contents of a node.
108
127
  * @param {!Node} elem The XML element.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shaka-player",
3
3
  "description": "DASH/EME video player library",
4
- "version": "3.2.1",
4
+ "version": "3.3.1",
5
5
  "homepage": "https://github.com/google/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -12,6 +12,7 @@
12
12
  ],
13
13
  "devDependencies": {
14
14
  "@chiragrupani/karma-chromium-edge-launcher": "^2.1.0",
15
+ "@onslip/karma-safari-launcher": "^1.0.1",
15
16
  "@teppeis/clutz": "^1.0.29-4c95e12.v20190929",
16
17
  "awesomplete": "^1.1.4",
17
18
  "babel-core": "^6.26.3",
@@ -44,7 +45,6 @@
44
45
  "karma-jasmine": "^3.3.1",
45
46
  "karma-jasmine-ajax": "^0.1.13",
46
47
  "karma-opera-launcher": "^1.0.0",
47
- "karma-safari-launcher": "^1.0.0",
48
48
  "karma-sourcemap-loader": "^0.3.7",
49
49
  "karma-spec-reporter": "0.0.32",
50
50
  "karma-webdriver-launcher": "^1.0.8",
@@ -44,6 +44,7 @@ goog.require('shaka.polyfill.PatchedMediaKeysMs');
44
44
  goog.require('shaka.polyfill.PatchedMediaKeysNop');
45
45
  goog.require('shaka.polyfill.PatchedMediaKeysWebkit');
46
46
  goog.require('shaka.polyfill.PiPWebkit');
47
+ goog.require('shaka.polyfill.RandomUUID');
47
48
  goog.require('shaka.polyfill.VTTCue');
48
49
  goog.require('shaka.polyfill.VideoPlayPromise');
49
50
  goog.require('shaka.polyfill.VideoPlaybackQuality');
@@ -70,6 +71,7 @@ goog.require('shaka.ui.AdPosition');
70
71
  goog.require('shaka.ui.AirPlayButton');
71
72
  goog.require('shaka.ui.BigPlayButton');
72
73
  goog.require('shaka.ui.CastButton');
74
+ goog.require('shaka.ui.ContextMenu');
73
75
  goog.require('shaka.ui.Element');
74
76
  goog.require('shaka.ui.FastForwardButton');
75
77
  goog.require('shaka.ui.FullscreenButton');
@@ -85,6 +87,7 @@ goog.require('shaka.ui.RewindButton');
85
87
  goog.require('shaka.ui.SkipAdButton');
86
88
  goog.require('shaka.ui.SmallPlayButton');
87
89
  goog.require('shaka.ui.Spacer');
90
+ goog.require('shaka.ui.StatisticsButton');
88
91
  goog.require('shaka.ui.TextSelection');
89
92
  goog.require('shaka.ui.VolumeBar');
90
93
  goog.require('shaka.util.Dom');
@@ -297,7 +297,8 @@ describe('CastProxy', () => {
297
297
  'timeupdate', Util.spyFunc(proxyListener));
298
298
 
299
299
  expect(proxyListener).not.toHaveBeenCalled();
300
- const fakeEvent = new FakeEvent('timeupdate', {detail: 8675309});
300
+ const fakeEvent = new FakeEvent(
301
+ 'timeupdate', (new Map()).set('detail', 8675309));
301
302
  mockVideo.on['timeupdate'](fakeEvent);
302
303
  expect(proxyListener).toHaveBeenCalledWith(jasmine.objectContaining({
303
304
  type: 'timeupdate',
@@ -315,7 +316,8 @@ describe('CastProxy', () => {
315
316
  mockSender.hasRemoteProperties.and.returnValue(true);
316
317
 
317
318
  expect(proxyListener).not.toHaveBeenCalled();
318
- const fakeEvent = new FakeEvent('timeupdate', {detail: 8675309});
319
+ const fakeEvent = new FakeEvent(
320
+ 'timeupdate', (new Map()).set('detail', 8675309));
319
321
  mockVideo.on['timeupdate'](fakeEvent);
320
322
  expect(proxyListener).not.toHaveBeenCalled();
321
323
  });
@@ -332,7 +334,8 @@ describe('CastProxy', () => {
332
334
  mockSender.hasRemoteProperties.and.returnValue(true);
333
335
 
334
336
  expect(proxyListener).not.toHaveBeenCalled();
335
- const fakeEvent = new FakeEvent('timeupdate', {detail: 8675309});
337
+ const fakeEvent = new FakeEvent(
338
+ 'timeupdate', (new Map()).set('detail', 8675309));
336
339
  mockSender.onRemoteEvent('video', fakeEvent);
337
340
  expect(proxyListener).toHaveBeenCalledWith(jasmine.objectContaining({
338
341
  type: 'timeupdate',
@@ -446,7 +449,8 @@ describe('CastProxy', () => {
446
449
  'buffering', Util.spyFunc(proxyListener));
447
450
 
448
451
  expect(proxyListener).not.toHaveBeenCalled();
449
- const fakeEvent = new FakeEvent('buffering', {detail: 8675309});
452
+ const fakeEvent = new FakeEvent(
453
+ 'buffering', (new Map()).set('detail', 8675309));
450
454
  mockPlayer.listeners['buffering'](fakeEvent);
451
455
  expect(proxyListener).toHaveBeenCalledWith(jasmine.objectContaining({
452
456
  type: 'buffering',
@@ -464,7 +468,8 @@ describe('CastProxy', () => {
464
468
  mockSender.hasRemoteProperties.and.returnValue(true);
465
469
 
466
470
  expect(proxyListener).not.toHaveBeenCalled();
467
- const fakeEvent = new FakeEvent('buffering', {detail: 8675309});
471
+ const fakeEvent = new FakeEvent(
472
+ 'buffering', (new Map()).set('detail', 8675309));
468
473
  mockPlayer.listeners['buffering'](fakeEvent);
469
474
  expect(proxyListener).not.toHaveBeenCalled();
470
475
  });
@@ -481,7 +486,8 @@ describe('CastProxy', () => {
481
486
  mockSender.hasRemoteProperties.and.returnValue(true);
482
487
 
483
488
  expect(proxyListener).not.toHaveBeenCalled();
484
- const fakeEvent = new FakeEvent('buffering', {detail: 8675309});
489
+ const fakeEvent = new FakeEvent(
490
+ 'buffering', (new Map()).set('detail', 8675309));
485
491
  mockSender.onRemoteEvent('player', fakeEvent);
486
492
  expect(proxyListener).toHaveBeenCalledWith(jasmine.objectContaining({
487
493
  type: 'buffering',
@@ -123,7 +123,7 @@ describe('CastUtils', () => {
123
123
  expect(typeof deserialized).toBe('object');
124
124
 
125
125
  // The object can be used to construct a FakeEvent.
126
- const fakeEvent = new FakeEvent(deserialized['type'], deserialized);
126
+ const fakeEvent = FakeEvent.fromRealEvent(deserialized);
127
127
 
128
128
  // The fake event has the same type and properties as the original.
129
129
  const asObj = /** @type {!Object} */ (fakeEvent);
@@ -42,6 +42,8 @@ describe('DashParser ContentProtection', () => {
42
42
 
43
43
  const playerInterface = {
44
44
  networkingEngine: netEngine,
45
+ modifyManifestRequest: (request, manifestInfo) => {},
46
+ modifySegmentRequest: (request, segmentInfo) => {},
45
47
  filter: (manifest) => Promise.resolve(),
46
48
  makeTextStreamsForClosedCaptions: (manifest) => {},
47
49
  onTimelineRegionAdded: fail, // Should not have any EventStream elements.
@@ -39,6 +39,8 @@ describe('DashParser Live', () => {
39
39
  parser.configure(shaka.util.PlayerConfiguration.createDefault().manifest);
40
40
  playerInterface = {
41
41
  networkingEngine: fakeNetEngine,
42
+ modifyManifestRequest: (request, manifestInfo) => {},
43
+ modifySegmentRequest: (request, segmentInfo) => {},
42
44
  filter: (manifest) => Promise.resolve(),
43
45
  makeTextStreamsForClosedCaptions: (manifest) => {},
44
46
  onTimelineRegionAdded: fail, // Should not have any EventStream elements.
@@ -364,7 +366,7 @@ describe('DashParser Live', () => {
364
366
  });
365
367
  }
366
368
 
367
- it('can add Periods', async () => {
369
+ it('can add Periods with SegmentTemplate', async () => {
368
370
  const template1 = [
369
371
  '<MPD type="dynamic" availabilityStartTime="1970-01-01T00:00:00Z"',
370
372
  ' suggestedPresentationDelay="PT5S"',
@@ -440,6 +442,104 @@ describe('DashParser Live', () => {
440
442
  // two segments (10-14s).
441
443
  expect(stream.segmentIndex.find(9)).not.toBe(null);
442
444
  expect(stream.segmentIndex.find(13)).not.toBe(null);
445
+
446
+ stream.closeSegmentIndex();
447
+ await stream.createSegmentIndex();
448
+
449
+ expect(stream.segmentIndex.find(9)).not.toBe(null);
450
+ expect(stream.segmentIndex.find(13)).not.toBe(null);
451
+ });
452
+
453
+ it('can add Periods with SegmentList', async () => {
454
+ const list1 = [
455
+ '<MPD type="dynamic" availabilityStartTime="1970-01-01T00:00:00Z"',
456
+ ' suggestedPresentationDelay="PT5S"',
457
+ ' minimumUpdatePeriod="PT%(updateTime)dS">',
458
+ ' <Period id="1">',
459
+ ' <AdaptationSet mimeType="video/mp4">',
460
+ ' <Representation id="1" bandwidth="500">',
461
+ ' <BaseURL>http://example.com</BaseURL>',
462
+ ' <SegmentList>',
463
+ ' <SegmentURL media="s1.mp4" />',
464
+ ' <SegmentURL media="s2.mp4" />',
465
+ ' <SegmentURL media="s3.mp4" />',
466
+ ' <SegmentTimeline>',
467
+ ' <S d="10" t="0" r="2"/>',
468
+ ' </SegmentTimeline>',
469
+ ' </SegmentList>',
470
+ ' </Representation>',
471
+ ' </AdaptationSet>',
472
+ ' </Period>',
473
+ '</MPD>',
474
+ ].join('\n');
475
+ const list2 = [
476
+ '<MPD type="dynamic" availabilityStartTime="1970-01-01T00:00:00Z"',
477
+ ' suggestedPresentationDelay="PT5S"',
478
+ ' minimumUpdatePeriod="PT%(updateTime)dS">',
479
+ ' <Period id="1" duration="PT40S">',
480
+ ' <AdaptationSet mimeType="video/mp4">',
481
+ ' <Representation id="1" bandwidth="500">',
482
+ ' <BaseURL>http://example.com</BaseURL>',
483
+ ' <SegmentList>',
484
+ ' <SegmentURL media="s1.mp4" />',
485
+ ' <SegmentURL media="s2.mp4" />',
486
+ ' <SegmentURL media="s3.mp4" />',
487
+ ' <SegmentURL media="s4.mp4" />',
488
+ ' <SegmentTimeline>',
489
+ ' <S d="10" t="0" r="3"/>',
490
+ ' </SegmentTimeline>',
491
+ ' </SegmentList>',
492
+ ' </Representation>',
493
+ ' </AdaptationSet>',
494
+ ' </Period>',
495
+ ' <Period id="2">',
496
+ ' <AdaptationSet mimeType="video/mp4">',
497
+ ' <Representation id="2" bandwidth="500">',
498
+ ' <BaseURL>http://example.com</BaseURL>',
499
+ ' <SegmentList>',
500
+ ' <SegmentURL media="s1.mp4" />',
501
+ ' <SegmentURL media="s2.mp4" />',
502
+ ' <SegmentTimeline>',
503
+ ' <S d="10" t="0" r="1"/>',
504
+ ' </SegmentTimeline>',
505
+ ' </SegmentList>',
506
+ ' </Representation>',
507
+ ' </AdaptationSet>',
508
+ ' </Period>',
509
+ '</MPD>',
510
+ ].join('\n');
511
+ const firstManifest = sprintf(list1, {updateTime: updateTime});
512
+ const secondManifest = sprintf(list2, {updateTime: updateTime});
513
+
514
+ fakeNetEngine.setResponseText('dummy://foo', firstManifest);
515
+ // First three segments should exist.
516
+ Date.now = () => 5;
517
+
518
+ const manifest = await parser.start('dummy://foo', playerInterface);
519
+ const variant = manifest.variants[0];
520
+ const stream = variant.video;
521
+ await stream.createSegmentIndex();
522
+
523
+ // First three segments exist, but not the fourth.
524
+ expect(stream.segmentIndex.find(25)).not.toBe(null);
525
+ expect(stream.segmentIndex.find(45)).toBe(null);
526
+
527
+ fakeNetEngine.setResponseText('dummy://foo', secondManifest);
528
+ Date.now = () => 25;
529
+
530
+ await updateManifest();
531
+
532
+ // The update should have affected the same variant object we captured
533
+ // before. Now the entire first period should exist (0-40s), plus the next
534
+ // two segments of the second period(40-60s).
535
+ expect(stream.segmentIndex.find(25)).not.toBe(null);
536
+ expect(stream.segmentIndex.find(45)).not.toBe(null);
537
+
538
+ stream.closeSegmentIndex();
539
+ await stream.createSegmentIndex();
540
+
541
+ expect(stream.segmentIndex.find(25)).not.toBe(null);
542
+ expect(stream.segmentIndex.find(45)).not.toBe(null);
443
543
  });
444
544
 
445
545
  it('uses redirect URL for manifest BaseURL and updates', async () => {