shaka-player 4.5.0 → 4.6.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 (214) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/AUTHORS +2 -0
  3. package/CHANGELOG.md +109 -0
  4. package/CODE_OF_CONDUCT.md +1 -1
  5. package/CONTRIBUTORS +2 -0
  6. package/README.md +38 -32
  7. package/demo/common/asset.js +11 -17
  8. package/demo/common/assets.js +117 -11
  9. package/demo/config.js +28 -1
  10. package/demo/custom.js +52 -38
  11. package/demo/main.js +11 -3
  12. package/demo/search.js +7 -0
  13. package/dist/controls.css +1 -1
  14. package/dist/controls.css.map +1 -1
  15. package/dist/demo.compiled.debug.js +133 -124
  16. package/dist/demo.compiled.debug.map +3 -3
  17. package/dist/demo.compiled.js +133 -124
  18. package/dist/demo.compiled.map +3 -3
  19. package/dist/deps.js +20 -18
  20. package/dist/locales.js +34 -30
  21. package/dist/receiver.compiled.debug.js +58 -50
  22. package/dist/receiver.compiled.debug.map +3 -3
  23. package/dist/receiver.compiled.js +58 -50
  24. package/dist/receiver.compiled.map +3 -3
  25. package/dist/shaka-player.compiled.d.ts +440 -390
  26. package/dist/shaka-player.compiled.debug.d.ts +440 -390
  27. package/dist/shaka-player.compiled.debug.externs.js +162 -77
  28. package/dist/shaka-player.compiled.debug.js +789 -738
  29. package/dist/shaka-player.compiled.debug.map +4 -4
  30. package/dist/shaka-player.compiled.externs.js +162 -77
  31. package/dist/shaka-player.compiled.js +1147 -1113
  32. package/dist/shaka-player.compiled.map +4 -4
  33. package/dist/shaka-player.ui.d.ts +491 -437
  34. package/dist/shaka-player.ui.debug.d.ts +491 -437
  35. package/dist/shaka-player.ui.debug.externs.js +167 -77
  36. package/dist/shaka-player.ui.debug.js +857 -791
  37. package/dist/shaka-player.ui.debug.map +4 -4
  38. package/dist/shaka-player.ui.externs.js +167 -77
  39. package/dist/shaka-player.ui.js +1359 -1314
  40. package/dist/shaka-player.ui.map +4 -4
  41. package/docs/tutorials/ad_monetization.md +54 -0
  42. package/docs/tutorials/basic-usage.md +2 -1
  43. package/docs/tutorials/errors.md +2 -1
  44. package/docs/tutorials/offline.md +10 -8
  45. package/docs/tutorials/plugins.md +5 -0
  46. package/docs/tutorials/ui-customization.md +13 -0
  47. package/docs/tutorials/ui.md +2 -1
  48. package/docs/tutorials/upgrade.md +3 -0
  49. package/externs/managedmediasource.js +24 -0
  50. package/externs/shaka/abr_manager.js +6 -2
  51. package/externs/shaka/cea.js +7 -0
  52. package/externs/shaka/codecs.js +5 -3
  53. package/externs/shaka/manifest.js +21 -5
  54. package/externs/shaka/manifest_parser.js +17 -0
  55. package/externs/shaka/net.js +2 -2
  56. package/externs/shaka/offline.js +9 -2
  57. package/externs/shaka/player.js +53 -7
  58. package/externs/shaka/text.js +3 -1
  59. package/externs/shaka/transmuxer.js +1 -1
  60. package/lib/abr/simple_abr_manager.js +25 -8
  61. package/lib/ads/media_tailor_ad_manager.js +14 -3
  62. package/lib/cast/cast_receiver.js +1 -1
  63. package/lib/cea/cea_decoder.js +28 -0
  64. package/lib/cea/dummy_caption_decoder.js +5 -0
  65. package/lib/dash/dash_parser.js +251 -84
  66. package/lib/dash/mpd_utils.js +52 -31
  67. package/lib/dash/segment_base.js +4 -5
  68. package/lib/dash/segment_list.js +5 -4
  69. package/lib/dash/segment_template.js +92 -29
  70. package/lib/hls/hls_classes.js +28 -43
  71. package/lib/hls/hls_parser.js +770 -652
  72. package/lib/hls/hls_utils.js +64 -5
  73. package/lib/hls/manifest_text_parser.js +7 -11
  74. package/lib/media/adaptation_set.js +20 -13
  75. package/lib/media/adaptation_set_criteria.js +70 -18
  76. package/lib/media/closed_caption_parser.js +13 -0
  77. package/lib/media/content_workarounds.js +6 -0
  78. package/lib/media/drm_engine.js +8 -13
  79. package/lib/media/manifest_parser.js +8 -113
  80. package/lib/media/media_source_capabilities.js +10 -3
  81. package/lib/media/media_source_engine.js +75 -21
  82. package/lib/media/play_rate_controller.js +8 -38
  83. package/lib/media/presentation_timeline.js +7 -1
  84. package/lib/media/quality_observer.js +1 -1
  85. package/lib/media/segment_index.js +5 -5
  86. package/lib/media/segment_prefetch.js +92 -24
  87. package/lib/media/segment_reference.js +67 -1
  88. package/lib/media/segment_utils.js +343 -0
  89. package/lib/media/stall_detector.js +0 -3
  90. package/lib/media/streaming_engine.js +72 -44
  91. package/lib/mss/mss_parser.js +18 -2
  92. package/lib/net/networking_engine.js +66 -12
  93. package/lib/net/networking_utils.js +95 -0
  94. package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
  95. package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
  96. package/lib/offline/manifest_converter.js +2 -0
  97. package/lib/offline/offline_manifest_parser.js +10 -0
  98. package/lib/offline/storage.js +11 -7
  99. package/lib/player.js +998 -1503
  100. package/lib/polyfill/mediasource.js +22 -1
  101. package/lib/text/mp4_ttml_parser.js +2 -2
  102. package/lib/text/srt_text_parser.js +2 -2
  103. package/lib/text/stub_text_displayer.js +51 -0
  104. package/lib/text/text_engine.js +3 -2
  105. package/lib/text/ttml_text_parser.js +28 -5
  106. package/lib/text/ui_text_displayer.js +4 -0
  107. package/lib/text/vtt_text_parser.js +7 -2
  108. package/lib/transmuxer/aac_transmuxer.js +1 -1
  109. package/lib/transmuxer/ac3_transmuxer.js +1 -1
  110. package/lib/transmuxer/ec3_transmuxer.js +1 -1
  111. package/lib/transmuxer/h264.js +5 -4
  112. package/lib/transmuxer/h265.js +5 -4
  113. package/lib/transmuxer/mp3_transmuxer.js +1 -1
  114. package/lib/transmuxer/mpeg_ts_transmuxer.js +1 -1
  115. package/lib/transmuxer/mss_transmuxer.js +1 -1
  116. package/lib/transmuxer/ts_transmuxer.js +33 -13
  117. package/lib/util/buffer_utils.js +26 -4
  118. package/lib/util/content_steering_manager.js +358 -0
  119. package/lib/util/error.js +2 -6
  120. package/lib/util/fairplay_utils.js +1 -1
  121. package/lib/util/fake_event.js +5 -1
  122. package/lib/util/id3_utils.js +50 -1
  123. package/lib/util/manifest_parser_utils.js +12 -8
  124. package/lib/util/mp4_generator.js +2 -4
  125. package/lib/util/mutex.js +59 -0
  126. package/lib/util/object_utils.js +1 -1
  127. package/lib/util/periods.js +154 -179
  128. package/lib/util/platform.js +4 -3
  129. package/lib/util/player_configuration.js +35 -6
  130. package/lib/util/stream_utils.js +105 -98
  131. package/lib/util/ts_parser.js +124 -73
  132. package/lib/util/uint8array_utils.js +5 -1
  133. package/lib/util/xml_utils.js +5 -0
  134. package/maintained-branches.md +2 -2
  135. package/package.json +1 -1
  136. package/roadmap.md +15 -5
  137. package/shaka-player.uncompiled.js +0 -1
  138. package/test/abr/simple_abr_manager_unit.js +33 -33
  139. package/test/ads/ad_manager_unit.js +3 -2
  140. package/test/cast/cast_receiver_integration.js +3 -4
  141. package/test/cast/cast_utils_unit.js +2 -0
  142. package/test/cea/cea_decoder_unit.js +7 -0
  143. package/test/codec_switching/codec_switching_integration.js +2 -1
  144. package/test/dash/dash_parser_integration.js +2 -1
  145. package/test/dash/dash_parser_live_unit.js +0 -19
  146. package/test/dash/dash_parser_manifest_unit.js +494 -2
  147. package/test/dash/mpd_utils_unit.js +61 -30
  148. package/test/hls/hls_live_unit.js +12 -3
  149. package/test/hls/hls_parser_unit.js +417 -27
  150. package/test/hls/manifest_text_parser_unit.js +32 -99
  151. package/test/media/adaptation_set_criteria_unit.js +172 -21
  152. package/test/media/adaptation_set_unit.js +1 -0
  153. package/test/media/content_workarounds_unit.js +1 -1
  154. package/test/media/drm_engine_unit.js +3 -3
  155. package/test/media/media_source_engine_unit.js +1 -1
  156. package/test/media/play_rate_controller_unit.js +0 -48
  157. package/test/media/segment_index_unit.js +2 -1
  158. package/test/mss/mss_player_integration.js +3 -2
  159. package/test/net/networking_engine_unit.js +3 -3
  160. package/test/{media/manifest_parser_unit.js → net/networking_utils_unit.js} +2 -2
  161. package/test/offline/manifest_convert_unit.js +9 -0
  162. package/test/offline/offline_integration.js +2 -1
  163. package/test/offline/storage_integration.js +21 -9
  164. package/test/player_external.js +4 -2
  165. package/test/player_integration.js +15 -4
  166. package/test/player_load_graph_integration.js +47 -151
  167. package/test/player_src_equals_external.js +1 -0
  168. package/test/player_src_equals_integration.js +71 -4
  169. package/test/player_unit.js +80 -27
  170. package/test/test/util/fake_media_source_engine.js +5 -0
  171. package/test/test/util/fake_networking_engine.js +9 -1
  172. package/test/test/util/fake_segment_prefetch.js +3 -0
  173. package/test/test/util/manifest_generator.js +4 -0
  174. package/test/test/util/manifest_parser_util.js +14 -2
  175. package/test/test/util/offline_utils.js +1 -0
  176. package/test/test/util/simple_fakes.js +2 -2
  177. package/test/test/util/streaming_engine_util.js +3 -0
  178. package/test/test/util/test_scheme.js +6 -0
  179. package/test/test/util/ui_utils.js +4 -3
  180. package/test/text/mp4_ttml_parser_unit.js +4 -4
  181. package/test/text/srt_text_parser_unit.js +1 -1
  182. package/test/text/text_displayer_layout_unit.js +1 -1
  183. package/test/text/text_engine_unit.js +6 -0
  184. package/test/text/ttml_text_parser_unit.js +33 -2
  185. package/test/transmuxer/transmuxer_engine_integration.js +9 -0
  186. package/test/transmuxer/transmuxer_integration.js +33 -3
  187. package/test/ui/ad_ui_unit.js +2 -2
  188. package/test/ui/ui_customization_unit.js +17 -16
  189. package/test/ui/ui_integration.js +30 -20
  190. package/test/ui/ui_unit.js +25 -19
  191. package/test/util/buffer_utils_unit.js +1 -1
  192. package/test/util/content_steering_manager_unit.js +427 -0
  193. package/test/util/id3_utils_unit.js +52 -0
  194. package/test/util/stream_utils_unit.js +17 -113
  195. package/test/util/ts_parser_unit.js +3 -3
  196. package/third_party/closure-uri/uri.js +13 -1
  197. package/ui/audio_language_selection.js +9 -2
  198. package/ui/externs/ui.js +17 -2
  199. package/ui/language_utils.js +43 -8
  200. package/ui/less/range_elements.less +33 -0
  201. package/ui/locales/en.json +1 -0
  202. package/ui/locales/es-419.json +1 -0
  203. package/ui/locales/es.json +1 -0
  204. package/ui/locales/source.json +4 -0
  205. package/ui/localization.js +10 -0
  206. package/ui/remote_button.js +3 -1
  207. package/ui/resolution_selection.js +47 -10
  208. package/ui/seek_bar.js +296 -3
  209. package/ui/text_selection.js +2 -1
  210. package/ui/ui.js +6 -2
  211. package/lib/routing/node.js +0 -23
  212. package/lib/routing/payload.js +0 -47
  213. package/lib/routing/walker.js +0 -587
  214. package/test/routing/walker_unit.js +0 -505
@@ -2611,8 +2611,8 @@ describe('DashParser Manifest', () => {
2611
2611
  '<MPD minBufferTime="PT75S" type="dynamic"',
2612
2612
  ' availabilityStartTime="1970-01-01T00:00:00Z">',
2613
2613
  ' <ServiceDescription id="0">',
2614
- ' <Latency max="2000" min="2000" referenceId="0" target="4000" />',
2615
- ' <PlaybackRate max="1.10" min="0.96" />',
2614
+ ' <Latency max="2000" min="1000" referenceId="0" target="4000" />',
2615
+ ' <PlaybackRate max="1.10" min="0.95" />',
2616
2616
  ' </ServiceDescription>',
2617
2617
  '</MPD>',
2618
2618
  ].join('\n');
@@ -2624,6 +2624,498 @@ describe('DashParser Manifest', () => {
2624
2624
 
2625
2625
  expect(manifest.serviceDescription.maxLatency).toBe(2);
2626
2626
  expect(manifest.serviceDescription.maxPlaybackRate).toBe(1.1);
2627
+ expect(manifest.serviceDescription.minLatency).toBe(1);
2628
+ expect(manifest.serviceDescription.minPlaybackRate).toBe(0.95);
2629
+ });
2630
+ });
2631
+
2632
+ it('parses urn:mpeg:dash:ssr:2023', async () => { // eslint-disable-line max-len
2633
+ const manifestText = [
2634
+ '<MPD minBufferTime="PT75S">',
2635
+ ' <Period id="1" duration="PT30S">',
2636
+ ' <AdaptationSet id="1" mimeType="video/mp4">',
2637
+ ' <Representation bandwidth="2" codecs="avc1.4d401f"',
2638
+ ' height="1080" width="1920">',
2639
+ ' <SegmentTemplate startNumber="1" media="l2-$Number$.mp4"',
2640
+ ' initialization="init.mp4" timescale="50" duration="100">',
2641
+ ' <SegmentTimeline>',
2642
+ ' <S t="0" d="100"/>',
2643
+ ' <S d="100"/>',
2644
+ ' </SegmentTimeline>',
2645
+ ' </SegmentTemplate>',
2646
+ ' </Representation>',
2647
+ ' </AdaptationSet>',
2648
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
2649
+ ' <EssentialProperty value="video_primary" ',
2650
+ ' schemeIdUri="urn:mpeg:dash:ssr:2023" />',
2651
+ ' <Representation bandwidth="1" codecs="avc1.4d401f"',
2652
+ ' height="720" width="1280">',
2653
+ ' <SegmentTemplate startNumber="1"',
2654
+ ' media="l-$Number$-p$SubNumber$.mp4"',
2655
+ ' initialization="init.mp4" timescale="50" duration="100">',
2656
+ ' <SegmentTimeline>',
2657
+ ' <S t="0" d="100" k="4"/>',
2658
+ ' <S d="100" k="4"/>',
2659
+ ' </SegmentTimeline>',
2660
+ ' </SegmentTemplate>',
2661
+ ' </Representation>',
2662
+ ' </AdaptationSet>',
2663
+ ' </Period>',
2664
+ '</MPD>',
2665
+ ].join('\n');
2666
+
2667
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2668
+ /** @type {shaka.extern.Manifest} */
2669
+ const manifest = await parser.start('dummy://foo', playerInterface);
2670
+ expect(manifest.variants.length).toBe(2);
2671
+
2672
+ const normalStream = manifest.variants[0].video;
2673
+ expect(normalStream.width).toBe(1920);
2674
+ expect(normalStream.height).toBe(1080);
2675
+ expect(normalStream.fastSwitching).toBe(false);
2676
+ await normalStream.createSegmentIndex();
2677
+ goog.asserts.assert(normalStream.segmentIndex != null,
2678
+ 'Null segmentIndex!');
2679
+
2680
+ const firstNormalReference = normalStream.segmentIndex.get(0);
2681
+ expect(firstNormalReference.partialReferences.length).toBe(0);
2682
+
2683
+ const stream = manifest.variants[1].video;
2684
+ expect(stream.width).toBe(1280);
2685
+ expect(stream.height).toBe(720);
2686
+ expect(stream.fastSwitching).toBe(true);
2687
+ await stream.createSegmentIndex();
2688
+ goog.asserts.assert(stream.segmentIndex != null,
2689
+ 'Null segmentIndex!');
2690
+
2691
+ const firstReference = stream.segmentIndex.get(0);
2692
+ expect(firstReference.partialReferences.length).toBe(4);
2693
+ });
2694
+
2695
+ describe('parses partial segments correctly', () => {
2696
+ it('whitout cadence', async () => {
2697
+ const manifestText = [
2698
+ '<MPD minBufferTime="PT75S">',
2699
+ ' <Period id="1" duration="PT30S">',
2700
+ ' <AdaptationSet id="1" mimeType="video/mp4">',
2701
+ ' <Representation bandwidth="1" codecs="avc1.4d401f">',
2702
+ ' <SegmentTemplate startNumber="1"',
2703
+ ' media="l-$Number$-p$SubNumber$.mp4"',
2704
+ ' initialization="init.mp4" timescale="50" duration="100">',
2705
+ ' <SegmentTimeline>',
2706
+ ' <S t="0" d="100" k="4"/>',
2707
+ ' <S d="100" k="4"/>',
2708
+ ' </SegmentTimeline>',
2709
+ ' </SegmentTemplate>',
2710
+ ' </Representation>',
2711
+ ' </AdaptationSet>',
2712
+ ' </Period>',
2713
+ '</MPD>',
2714
+ ].join('\n');
2715
+
2716
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2717
+ /** @type {shaka.extern.Manifest} */
2718
+ const manifest = await parser.start('dummy://foo', playerInterface);
2719
+ const stream = manifest.variants[0].video;
2720
+ await stream.createSegmentIndex();
2721
+ goog.asserts.assert(stream.segmentIndex != null, 'Null segmentIndex!');
2722
+
2723
+ const firstReference = stream.segmentIndex.get(0);
2724
+ expect(firstReference.startTime).toBe(0);
2725
+ expect(firstReference.endTime).toBe(2);
2726
+ expect(firstReference.getUris()).toEqual([]);
2727
+ expect(firstReference.partialReferences.length).toBe(4);
2728
+ const firstPartialReference = firstReference.partialReferences[0];
2729
+ expect(firstPartialReference.startTime).toBe(0);
2730
+ expect(firstPartialReference.endTime).toBe(0.5);
2731
+ expect(firstPartialReference.getUris())
2732
+ .toEqual(['dummy://foo/l-1-p1.mp4']);
2733
+ const secondPartialReference = firstReference.partialReferences[1];
2734
+ expect(secondPartialReference.startTime).toBe(0.5);
2735
+ expect(secondPartialReference.endTime).toBe(1);
2736
+ expect(secondPartialReference.getUris())
2737
+ .toEqual(['dummy://foo/l-1-p2.mp4']);
2738
+ const thirdPartialReference = firstReference.partialReferences[2];
2739
+ expect(thirdPartialReference.startTime).toBe(1);
2740
+ expect(thirdPartialReference.endTime).toBe(1.5);
2741
+ expect(thirdPartialReference.getUris())
2742
+ .toEqual(['dummy://foo/l-1-p3.mp4']);
2743
+ const fourthPartialReference = firstReference.partialReferences[3];
2744
+ expect(fourthPartialReference.startTime).toBe(1.5);
2745
+ expect(fourthPartialReference.endTime).toBe(2);
2746
+ expect(fourthPartialReference.getUris())
2747
+ .toEqual(['dummy://foo/l-1-p4.mp4']);
2748
+ });
2749
+
2750
+ it('with cadence equal to 1', async () => {
2751
+ const manifestText = [
2752
+ '<MPD minBufferTime="PT75S">',
2753
+ ' <Period id="1" duration="PT30S">',
2754
+ ' <AdaptationSet id="1" mimeType="video/mp4">',
2755
+ ' <Representation bandwidth="1" codecs="avc1.4d401f">',
2756
+ ' <SegmentTemplate startNumber="1"',
2757
+ ' media="l-$Number$-p$SubNumber$.mp4"',
2758
+ ' initialization="init.mp4" timescale="50" duration="100">',
2759
+ ' <SegmentTimeline>',
2760
+ ' <S t="0" d="100" k="4"/>',
2761
+ ' <S d="100" k="4"/>',
2762
+ ' </SegmentTimeline>',
2763
+ ' </SegmentTemplate>',
2764
+ ' <SegmentSequenceProperties>',
2765
+ ' <SAP type="1" cadence="1" />',
2766
+ ' </SegmentSequenceProperties>',
2767
+ ' </Representation>',
2768
+ ' </AdaptationSet>',
2769
+ ' </Period>',
2770
+ '</MPD>',
2771
+ ].join('\n');
2772
+
2773
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2774
+ /** @type {shaka.extern.Manifest} */
2775
+ const manifest = await parser.start('dummy://foo', playerInterface);
2776
+ const stream = manifest.variants[0].video;
2777
+ await stream.createSegmentIndex();
2778
+ goog.asserts.assert(stream.segmentIndex != null, 'Null segmentIndex!');
2779
+
2780
+ const firstReference = stream.segmentIndex.get(0);
2781
+ const firstPartialReference = firstReference.partialReferences[0];
2782
+ expect(firstPartialReference.isIndependent()).toBeTruthy();
2783
+ const secondPartialReference = firstReference.partialReferences[1];
2784
+ expect(secondPartialReference.isIndependent()).toBeTruthy();
2785
+ const thirdPartialReference = firstReference.partialReferences[2];
2786
+ expect(thirdPartialReference.isIndependent()).toBeTruthy();
2787
+ const fourthPartialReference = firstReference.partialReferences[3];
2788
+ expect(fourthPartialReference.isIndependent()).toBeTruthy();
2789
+ });
2790
+
2791
+ it('with cadence equal to 2', async () => {
2792
+ const manifestText = [
2793
+ '<MPD minBufferTime="PT75S">',
2794
+ ' <Period id="1" duration="PT30S">',
2795
+ ' <AdaptationSet id="1" mimeType="video/mp4">',
2796
+ ' <Representation bandwidth="1" codecs="avc1.4d401f">',
2797
+ ' <SegmentTemplate startNumber="1"',
2798
+ ' media="l-$Number$-p$SubNumber$.mp4"',
2799
+ ' initialization="init.mp4" timescale="50" duration="100">',
2800
+ ' <SegmentTimeline>',
2801
+ ' <S t="0" d="100" k="4"/>',
2802
+ ' <S d="100" k="4"/>',
2803
+ ' </SegmentTimeline>',
2804
+ ' </SegmentTemplate>',
2805
+ ' <SegmentSequenceProperties>',
2806
+ ' <SAP type="1" cadence="2" />',
2807
+ ' </SegmentSequenceProperties>',
2808
+ ' </Representation>',
2809
+ ' </AdaptationSet>',
2810
+ ' </Period>',
2811
+ '</MPD>',
2812
+ ].join('\n');
2813
+
2814
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2815
+ /** @type {shaka.extern.Manifest} */
2816
+ const manifest = await parser.start('dummy://foo', playerInterface);
2817
+ const stream = manifest.variants[0].video;
2818
+ await stream.createSegmentIndex();
2819
+ goog.asserts.assert(stream.segmentIndex != null, 'Null segmentIndex!');
2820
+
2821
+ const firstReference = stream.segmentIndex.get(0);
2822
+ const firstPartialReference = firstReference.partialReferences[0];
2823
+ expect(firstPartialReference.isIndependent()).toBeTruthy();
2824
+ const secondPartialReference = firstReference.partialReferences[1];
2825
+ expect(secondPartialReference.isIndependent()).toBeFalsy();
2826
+ const thirdPartialReference = firstReference.partialReferences[2];
2827
+ expect(thirdPartialReference.isIndependent()).toBeTruthy();
2828
+ const fourthPartialReference = firstReference.partialReferences[3];
2829
+ expect(fourthPartialReference.isIndependent()).toBeFalsy();
2830
+ });
2831
+ });
2832
+
2833
+ describe('supports ContentSteering', () => {
2834
+ it('with defaultServiceLocation', async () => {
2835
+ const manifestText = [
2836
+ '<MPD type="static">',
2837
+ ' <BaseURL serviceLocation="a">http://example.com/r0/</BaseURL>',
2838
+ ' <BaseURL serviceLocation="b">http://example.com/r1/</BaseURL>',
2839
+ ' <ContentSteering defaultServiceLocation="a,b" ',
2840
+ 'queryBeforeStart="true">http://contentsteering</ContentSteering>',
2841
+ ' <Period id="1" duration="PT30S">',
2842
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
2843
+ ' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
2844
+ ' <SegmentTimeline>',
2845
+ ' <S t="0" d="30" />',
2846
+ ' </SegmentTimeline>',
2847
+ ' </SegmentTemplate>',
2848
+ ' <Representation id="video-sd" width="640" height="480">',
2849
+ ' </Representation>',
2850
+ ' </AdaptationSet>',
2851
+ ' </Period>',
2852
+ '</MPD>',
2853
+ ].join('\n');
2854
+
2855
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2856
+
2857
+ const contentSteering = JSON.stringify({
2858
+ 'VERSION': 1,
2859
+ 'TTL': 1,
2860
+ 'RELOAD-URI': 'http://contentsteering/update',
2861
+ 'PATHWAY-PRIORITY': [],
2862
+ });
2863
+
2864
+ fakeNetEngine.setResponseText('http://contentsteering', contentSteering);
2865
+
2866
+ /** @type {shaka.extern.Manifest} */
2867
+ const manifest = await parser.start('dummy://foo', playerInterface);
2868
+
2869
+ const video0 = manifest.variants[0].video;
2870
+ await video0.createSegmentIndex();
2871
+ goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
2872
+ const segment0 = Array.from(video0.segmentIndex)[0];
2873
+ const uri0 = segment0.getUris()[0];
2874
+ const uri1 = segment0.getUris()[1];
2875
+
2876
+ expect(uri0).toBe('http://example.com/r0/1.mp4');
2877
+ expect(uri1).toBe('http://example.com/r1/1.mp4');
2878
+ });
2879
+
2880
+ it('without defaultServiceLocation', async () => {
2881
+ const manifestText = [
2882
+ '<MPD type="static">',
2883
+ ' <BaseURL serviceLocation="a">http://example.com/r0/</BaseURL>',
2884
+ ' <BaseURL serviceLocation="b">http://example.com/r1/</BaseURL>',
2885
+ ' <ContentSteering',
2886
+ 'queryBeforeStart="true">http://contentsteering</ContentSteering>',
2887
+ ' <Period id="1" duration="PT30S">',
2888
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
2889
+ ' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
2890
+ ' <SegmentTimeline>',
2891
+ ' <S t="0" d="30" />',
2892
+ ' </SegmentTimeline>',
2893
+ ' </SegmentTemplate>',
2894
+ ' <Representation id="video-sd" width="640" height="480">',
2895
+ ' </Representation>',
2896
+ ' </AdaptationSet>',
2897
+ ' </Period>',
2898
+ '</MPD>',
2899
+ ].join('\n');
2900
+
2901
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2902
+
2903
+ const contentSteering = JSON.stringify({
2904
+ 'VERSION': 1,
2905
+ 'TTL': 1,
2906
+ 'RELOAD-URI': 'http://contentsteering/update',
2907
+ 'PATHWAY-PRIORITY': [
2908
+ 'b',
2909
+ 'a',
2910
+ ],
2911
+ });
2912
+
2913
+ fakeNetEngine.setResponseText('http://contentsteering', contentSteering);
2914
+
2915
+ /** @type {shaka.extern.Manifest} */
2916
+ const manifest = await parser.start('dummy://foo', playerInterface);
2917
+
2918
+ const video0 = manifest.variants[0].video;
2919
+ await video0.createSegmentIndex();
2920
+ goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
2921
+ const segment0 = Array.from(video0.segmentIndex)[0];
2922
+ const uri0 = segment0.getUris()[0];
2923
+ const uri1 = segment0.getUris()[1];
2924
+
2925
+ expect(uri0).toBe('http://example.com/r1/1.mp4');
2926
+ expect(uri1).toBe('http://example.com/r0/1.mp4');
2927
+ });
2928
+
2929
+ it('with queryBeforeStart', async () => {
2930
+ const manifestText = [
2931
+ '<MPD type="static">',
2932
+ ' <BaseURL serviceLocation="a">http://example.com/r0/</BaseURL>',
2933
+ ' <BaseURL serviceLocation="b">http://example.com/r1/</BaseURL>',
2934
+ ' <ContentSteering defaultServiceLocation="b" ',
2935
+ 'queryBeforeStart="true">http://contentsteering</ContentSteering>',
2936
+ ' <Period id="1" duration="PT30S">',
2937
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
2938
+ ' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
2939
+ ' <SegmentTimeline>',
2940
+ ' <S t="0" d="30" />',
2941
+ ' </SegmentTimeline>',
2942
+ ' </SegmentTemplate>',
2943
+ ' <Representation id="video-sd" width="640" height="480">',
2944
+ ' </Representation>',
2945
+ ' </AdaptationSet>',
2946
+ ' </Period>',
2947
+ '</MPD>',
2948
+ ].join('\n');
2949
+
2950
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2951
+
2952
+ const contentSteering = JSON.stringify({
2953
+ 'VERSION': 1,
2954
+ 'TTL': 1,
2955
+ 'RELOAD-URI': 'http://contentsteering/update',
2956
+ 'PATHWAY-PRIORITY': [
2957
+ 'a',
2958
+ ],
2959
+ });
2960
+
2961
+ fakeNetEngine.setResponseText('http://contentsteering', contentSteering);
2962
+
2963
+ /** @type {shaka.extern.Manifest} */
2964
+ const manifest = await parser.start('dummy://foo', playerInterface);
2965
+
2966
+ const video0 = manifest.variants[0].video;
2967
+ await video0.createSegmentIndex();
2968
+ goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
2969
+ const segment0 = Array.from(video0.segmentIndex)[0];
2970
+ expect(segment0.getUris().length).toBe(1);
2971
+ const uri0 = segment0.getUris()[0];
2972
+
2973
+ expect(uri0).toBe('http://example.com/r0/1.mp4');
2974
+ });
2975
+
2976
+ it('without queryBeforeStart', async () => {
2977
+ const manifestText = [
2978
+ '<MPD type="static">',
2979
+ ' <BaseURL serviceLocation="a">http://example.com/r0/</BaseURL>',
2980
+ ' <BaseURL serviceLocation="b">http://example.com/r1/</BaseURL>',
2981
+ ' <ContentSteering defaultServiceLocation="b">',
2982
+ 'http://contentsteering</ContentSteering>',
2983
+ ' <Period id="1" duration="PT30S">',
2984
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
2985
+ ' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
2986
+ ' <SegmentTimeline>',
2987
+ ' <S t="0" d="30" />',
2988
+ ' </SegmentTimeline>',
2989
+ ' </SegmentTemplate>',
2990
+ ' <Representation id="video-sd" width="640" height="480">',
2991
+ ' </Representation>',
2992
+ ' </AdaptationSet>',
2993
+ ' </Period>',
2994
+ '</MPD>',
2995
+ ].join('\n');
2996
+
2997
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2998
+
2999
+ fakeNetEngine.setResponseText('http://contentsteering', 'foo');
3000
+
3001
+ /** @type {shaka.extern.Manifest} */
3002
+ const manifest = await parser.start('dummy://foo', playerInterface);
3003
+
3004
+ const video0 = manifest.variants[0].video;
3005
+ await video0.createSegmentIndex();
3006
+ goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
3007
+ const segment0 = Array.from(video0.segmentIndex)[0];
3008
+ expect(segment0.getUris().length).toBe(1);
3009
+ const uri0 = segment0.getUris()[0];
3010
+
3011
+ expect(uri0).toBe('http://example.com/r1/1.mp4');
3012
+ });
3013
+
3014
+ it('without serviceLocation in BaseURL', async () => {
3015
+ const manifestText = [
3016
+ '<MPD type="static">',
3017
+ ' <BaseURL>http://example.com/r0/</BaseURL>',
3018
+ ' <BaseURL>http://example.com/r1/</BaseURL>',
3019
+ ' <ContentSteering',
3020
+ 'queryBeforeStart="true">http://contentsteering</ContentSteering>',
3021
+ ' <Period id="1" duration="PT30S">',
3022
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
3023
+ ' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
3024
+ ' <SegmentTimeline>',
3025
+ ' <S t="0" d="30" />',
3026
+ ' </SegmentTimeline>',
3027
+ ' </SegmentTemplate>',
3028
+ ' <Representation id="video-sd" width="640" height="480">',
3029
+ ' </Representation>',
3030
+ ' </AdaptationSet>',
3031
+ ' </Period>',
3032
+ '</MPD>',
3033
+ ].join('\n');
3034
+
3035
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
3036
+
3037
+ fakeNetEngine.setResponseText('http://contentsteering', 'foo');
3038
+
3039
+ /** @type {shaka.extern.Manifest} */
3040
+ const manifest = await parser.start('dummy://foo', playerInterface);
3041
+
3042
+ const video0 = manifest.variants[0].video;
3043
+ await video0.createSegmentIndex();
3044
+ goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
3045
+ const segment0 = Array.from(video0.segmentIndex)[0];
3046
+ const uri0 = segment0.getUris()[0];
3047
+ const uri1 = segment0.getUris()[1];
3048
+
3049
+ expect(uri0).toBe('http://example.com/r0/1.mp4');
3050
+ expect(uri1).toBe('http://example.com/r1/1.mp4');
3051
+ });
3052
+
3053
+ it('specify MPD BaseURL and AdaptationSet BaseURL', async () => {
3054
+ const manifestText = [
3055
+ '<MPD type="static">',
3056
+ ' <BaseURL serviceLocation="a">http://example.com/r0/</BaseURL>',
3057
+ ' <BaseURL serviceLocation="b">http://example.com/r1/</BaseURL>',
3058
+ ' <ContentSteering defaultServiceLocation="a,b" ',
3059
+ 'queryBeforeStart="true">http://contentsteering</ContentSteering>',
3060
+ ' <Period id="1" duration="PT30S">',
3061
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
3062
+ ' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
3063
+ ' <SegmentTimeline>',
3064
+ ' <S t="0" d="30" />',
3065
+ ' </SegmentTimeline>',
3066
+ ' </SegmentTemplate>',
3067
+ ' <Representation id="video-sd" width="640" height="480">',
3068
+ ' </Representation>',
3069
+ ' </AdaptationSet>',
3070
+ ' <AdaptationSet id="3" mimeType="audio/mp4">',
3071
+ ' <BaseURL serviceLocation="c">http://example.foo/r0/</BaseURL>',
3072
+ ' <BaseURL serviceLocation="d">http://example.foo/r1/</BaseURL>',
3073
+ ' <SegmentTemplate media="$Number$.mp4" startNumber="1">',
3074
+ ' <SegmentTimeline>',
3075
+ ' <S t="0" d="30" />',
3076
+ ' </SegmentTimeline>',
3077
+ ' </SegmentTemplate>',
3078
+ ' <Representation id="audio">',
3079
+ ' </Representation>',
3080
+ ' </AdaptationSet>',
3081
+ ' </Period>',
3082
+ '</MPD>',
3083
+ ].join('\n');
3084
+
3085
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
3086
+
3087
+ const contentSteering = JSON.stringify({
3088
+ 'VERSION': 1,
3089
+ 'TTL': 1,
3090
+ 'RELOAD-URI': 'http://contentsteering/update',
3091
+ 'PATHWAY-PRIORITY': [
3092
+ 'a',
3093
+ 'c',
3094
+ ],
3095
+ });
3096
+
3097
+ fakeNetEngine.setResponseText('http://contentsteering', contentSteering);
3098
+
3099
+ /** @type {shaka.extern.Manifest} */
3100
+ const manifest = await parser.start('dummy://foo', playerInterface);
3101
+
3102
+ const video0 = manifest.variants[0].video;
3103
+ await video0.createSegmentIndex();
3104
+ goog.asserts.assert(video0.segmentIndex, 'Null segmentIndex!');
3105
+ const videoSegment0 = Array.from(video0.segmentIndex)[0];
3106
+ expect(videoSegment0.getUris().length).toBe(1);
3107
+ const videoUri0 = videoSegment0.getUris()[0];
3108
+
3109
+ expect(videoUri0).toBe('http://example.com/r0/1.mp4');
3110
+
3111
+ const audio0 = manifest.variants[0].audio;
3112
+ await audio0.createSegmentIndex();
3113
+ goog.asserts.assert(audio0.segmentIndex, 'Null segmentIndex!');
3114
+ const audioSegment0 = Array.from(audio0.segmentIndex)[0];
3115
+ expect(audioSegment0.getUris().length).toBe(1);
3116
+ const audioUri0 = audioSegment0.getUris()[0];
3117
+
3118
+ expect(audioUri0).toBe('http://example.foo/r0/1.mp4');
2627
3119
  });
2628
3120
  });
2629
3121
  });