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
@@ -56,11 +56,12 @@ shaka.test.ManifestParser = class {
56
56
  * @param {?number=} endByte
57
57
  * @param {number=} timestampOffset
58
58
  * @param {!Array.<!shaka.media.SegmentReference>=} partialReferences
59
+ * @param {?string=} tilesLayout
59
60
  * @return {!shaka.media.SegmentReference}
60
61
  */
61
62
  static makeReference(uri, start, end, baseUri = '',
62
63
  startByte = 0, endByte = null, timestampOffset = 0,
63
- partialReferences = []) {
64
+ partialReferences = [], tilesLayout = '') {
64
65
  const getUris = () => uri.length ? [baseUri + uri] : [];
65
66
 
66
67
  // If a test wants to verify these, they can be set explicitly after
@@ -84,6 +85,7 @@ shaka.test.ManifestParser = class {
84
85
  appendWindowStart,
85
86
  appendWindowEnd,
86
87
  partialReferences,
88
+ tilesLayout,
87
89
  );
88
90
  }
89
91
  };
@@ -476,6 +476,15 @@ describe('TtmlTextParser', () => {
476
476
  {periodStart: 0, segmentStart: 0, segmentEnd: 0});
477
477
  });
478
478
 
479
+ it('supports comments in the body', () => {
480
+ verifyHelper(
481
+ [],
482
+ '<tt><body><div>' +
483
+ '<!-- text-based TTML -->' +
484
+ '</div></body></tt>',
485
+ {periodStart: 0, segmentStart: 0, segmentEnd: 0});
486
+ });
487
+
479
488
  it('parses alignment from textAlign attribute of a region', () => {
480
489
  verifyHelper(
481
490
  [
@@ -84,20 +84,16 @@ describe('UITextDisplayer', () => {
84
84
  // Wait until updateCaptions_() gets called.
85
85
  await shaka.test.Util.delay(0.5);
86
86
 
87
- const textContainer =
88
- videoContainer.querySelector('.shaka-text-container');
89
- const captions =
90
- textContainer.querySelector('span:not(.shaka-text-wrapper)');
87
+ const textContainer = videoContainer.querySelector('.shaka-text-container');
88
+ const captions = textContainer.querySelector('div');
91
89
  const cssObj = parseCssText(captions.style.cssText);
92
90
 
93
91
  const expectCssObj = {
94
92
  'color': 'green',
95
- 'background-color': 'black',
96
93
  'direction': 'ltr',
97
94
  'font-size': '10px',
98
95
  'font-style': 'normal',
99
96
  'font-weight': 400,
100
- 'line-height': 2,
101
97
  'text-align': 'center',
102
98
  };
103
99
 
@@ -114,6 +110,8 @@ describe('UITextDisplayer', () => {
114
110
  }
115
111
 
116
112
  expect(cssObj).toEqual(jasmine.objectContaining(expectCssObj));
113
+ expect(parseCssText(textContainer.querySelector('span').style.cssText))
114
+ .toEqual(jasmine.objectContaining({'background-color': 'black'}));
117
115
  });
118
116
 
119
117
  it('correctly displays styles for nested cues', async () => {
@@ -137,15 +135,13 @@ describe('UITextDisplayer', () => {
137
135
  await shaka.test.Util.delay(0.5);
138
136
 
139
137
  // Verify styles applied to the nested cues.
140
- const textContainer =
141
- videoContainer.querySelector('.shaka-text-container');
138
+ const textContainer = videoContainer.querySelector('.shaka-text-container');
142
139
  const captions =
143
140
  textContainer.querySelector('span:not(.shaka-text-wrapper)');
144
141
  const cssObj = parseCssText(captions.style.cssText);
145
142
 
146
143
  const expectCssObj = {
147
144
  'color': 'green',
148
- 'background-color': 'black',
149
145
  'font-size': '10px',
150
146
  'font-style': 'normal',
151
147
  'font-weight': 400,
@@ -165,6 +161,8 @@ describe('UITextDisplayer', () => {
165
161
  }
166
162
 
167
163
  expect(cssObj).toEqual(jasmine.objectContaining(expectCssObj));
164
+ expect(parseCssText(captions.querySelector('span').style.cssText))
165
+ .toEqual(jasmine.objectContaining({'background-color': 'black'}));
168
166
  });
169
167
 
170
168
  it('correctly displays styles for cellResolution units', async () => {
@@ -191,10 +189,8 @@ describe('UITextDisplayer', () => {
191
189
  // style.
192
190
  const expectedLinePadding = '11.25px';
193
191
 
194
- const textContainer =
195
- videoContainer.querySelector('.shaka-text-container');
196
- const captions =
197
- textContainer.querySelector('span:not(.shaka-text-wrapper)');
192
+ const textContainer = videoContainer.querySelector('.shaka-text-container');
193
+ const captions = textContainer.querySelector('div');
198
194
  const cssObj = parseCssText(captions.style.cssText);
199
195
  expect(cssObj).toEqual(
200
196
  jasmine.objectContaining({
@@ -222,10 +218,8 @@ describe('UITextDisplayer', () => {
222
218
  // videoContainerHeight=450px and tts:fontSize="90%" on the default style.
223
219
  const expectedFontSize = '27px';
224
220
 
225
- const textContainer =
226
- videoContainer.querySelector('.shaka-text-container');
227
- const captions =
228
- textContainer.querySelector('span:not(.shaka-text-wrapper)');
221
+ const textContainer = videoContainer.querySelector('.shaka-text-container');
222
+ const captions = textContainer.querySelector('div');
229
223
  const cssObj = parseCssText(captions.style.cssText);
230
224
  expect(cssObj).toEqual(
231
225
  jasmine.objectContaining({'font-size': expectedFontSize}));
@@ -319,6 +313,24 @@ describe('UITextDisplayer', () => {
319
313
  expect(captions.length).toBe(3);
320
314
  });
321
315
 
316
+ it('hides currently displayed cue when removed', async () => {
317
+ const cue = new shaka.text.Cue(0, 50, 'One');
318
+ textDisplayer.setTextVisibility(true);
319
+ textDisplayer.append([cue]);
320
+ video.currentTime = 10;
321
+ await shaka.test.Util.delay(0.5);
322
+ const textContainer = videoContainer.querySelector('.shaka-text-container');
323
+
324
+ let cueElements = textContainer.querySelectorAll('div');
325
+ expect(cueElements.length).toBe(1);
326
+ expect(cueElements[0].textContent).toBe('One');
327
+
328
+ textDisplayer.remove(0, 100);
329
+
330
+ cueElements = textContainer.querySelectorAll('div');
331
+ expect(cueElements.length).toBe(0);
332
+ });
333
+
322
334
  it('hides and shows nested cues at appropriate times', async () => {
323
335
  const parentCue1 = new shaka.text.Cue(0, 100, '');
324
336
  const cue1 = new shaka.text.Cue(0, 50, 'One');
@@ -9,23 +9,45 @@ goog.require('shaka.text.WebVttGenerator');
9
9
 
10
10
  describe('WebVttGenerator', () => {
11
11
  it('supports no cues', () => {
12
- verifyHelper([], 'WEBVTT\n\n');
12
+ verifyHelper([], [], 'WEBVTT\n\n');
13
13
  });
14
14
 
15
15
  it('convert cues to WebVTT', () => {
16
16
  const shakaCue1 = new shaka.text.Cue(20, 40, 'Test');
17
+ shakaCue1.textAlign = shaka.text.Cue.textAlign.LEFT;
18
+ shakaCue1.writingMode = shaka.text.Cue.writingMode.VERTICAL_LEFT_TO_RIGHT;
17
19
  const shakaCue2 = new shaka.text.Cue(40, 50, 'Test2');
20
+ shakaCue2.textAlign = shaka.text.Cue.textAlign.RIGHT;
21
+ shakaCue2.writingMode = shaka.text.Cue.writingMode.VERTICAL_RIGHT_TO_LEFT;
22
+ const shakaCue3 = new shaka.text.Cue(50, 51, 'Test3');
23
+ shakaCue3.textAlign = shaka.text.Cue.textAlign.CENTER;
24
+ const shakaCue4 = new shaka.text.Cue(52, 53, 'Test4');
25
+ shakaCue4.textAlign = shaka.text.Cue.textAlign.START;
26
+ const shakaCue5 = new shaka.text.Cue(53, 54, 'Test5');
27
+ shakaCue5.textAlign = shaka.text.Cue.textAlign.END;
28
+
29
+ const adCuePoints = [];
18
30
 
19
31
  verifyHelper(
20
32
  [
21
33
  shakaCue1,
22
34
  shakaCue2,
35
+ shakaCue3,
36
+ shakaCue4,
37
+ shakaCue5,
23
38
  ],
39
+ adCuePoints,
24
40
  'WEBVTT\n\n' +
25
- '00:00:20.000 --> 00:00:40.000\n' +
41
+ '00:00:20.000 --> 00:00:40.000 align:left vertical:lr\n' +
26
42
  'Test\n\n' +
27
- '00:00:40.000 --> 00:00:50.000\n' +
28
- 'Test2\n\n');
43
+ '00:00:40.000 --> 00:00:50.000 align:right vertical:rl\n' +
44
+ 'Test2\n\n' +
45
+ '00:00:50.000 --> 00:00:51.000 align:middle\n' +
46
+ 'Test3\n\n' +
47
+ '00:00:52.000 --> 00:00:53.000 align:start\n' +
48
+ 'Test4\n\n' +
49
+ '00:00:53.000 --> 00:00:54.000 align:end\n' +
50
+ 'Test5\n\n');
29
51
  });
30
52
 
31
53
  it('creates style tags for cues with underline/italics/bold', () => {
@@ -49,19 +71,71 @@ describe('WebVttGenerator', () => {
49
71
  nestedCue4.textDecoration.push(shaka.text.Cue.textDecoration.UNDERLINE);
50
72
 
51
73
  shakaCue.nestedCues = [nestedCue1, nestedCue2, nestedCue3, nestedCue4];
74
+
75
+ const adCuePoints = [];
76
+
52
77
  verifyHelper(
53
78
  [shakaCue],
79
+ adCuePoints,
54
80
  'WEBVTT\n\n' +
55
- '00:00:10.000 --> 00:00:20.000\n' +
81
+ '00:00:10.000 --> 00:00:20.000 align:middle\n' +
56
82
  '<i><u>Test1</u></i><b><i>Test2</i></b>Test3<u>Test4</u>\n\n');
57
83
  });
58
84
 
85
+ it('computes the time with ad cue points', () => {
86
+ const shakaCue1 = new shaka.text.Cue(20, 30, 'Test');
87
+ shakaCue1.textAlign = shaka.text.Cue.textAlign.LEFT;
88
+ shakaCue1.writingMode = shaka.text.Cue.writingMode.VERTICAL_LEFT_TO_RIGHT;
89
+ const shakaCue2 = new shaka.text.Cue(40, 50, 'Test2');
90
+ shakaCue2.textAlign = shaka.text.Cue.textAlign.RIGHT;
91
+ shakaCue2.writingMode = shaka.text.Cue.writingMode.VERTICAL_RIGHT_TO_LEFT;
92
+ const shakaCue3 = new shaka.text.Cue(50, 51, 'Test3');
93
+ shakaCue3.textAlign = shaka.text.Cue.textAlign.CENTER;
94
+ const shakaCue4 = new shaka.text.Cue(52, 53, 'Test4');
95
+ shakaCue4.textAlign = shaka.text.Cue.textAlign.START;
96
+ const shakaCue5 = new shaka.text.Cue(53, 54, 'Test5');
97
+ shakaCue5.textAlign = shaka.text.Cue.textAlign.END;
98
+
99
+ const adCuePoints = [
100
+ {
101
+ start: 0,
102
+ end: 10,
103
+ },
104
+ {
105
+ start: 35,
106
+ end: 45,
107
+ },
108
+ ];
109
+
110
+ verifyHelper(
111
+ [
112
+ shakaCue1,
113
+ shakaCue2,
114
+ shakaCue3,
115
+ shakaCue4,
116
+ shakaCue5,
117
+ ],
118
+ adCuePoints,
119
+ 'WEBVTT\n\n' +
120
+ '00:00:30.000 --> 00:00:40.000 align:left vertical:lr\n' +
121
+ 'Test\n\n' +
122
+ '00:01:00.000 --> 00:01:10.000 align:right vertical:rl\n' +
123
+ 'Test2\n\n' +
124
+ '00:01:10.000 --> 00:01:11.000 align:middle\n' +
125
+ 'Test3\n\n' +
126
+ '00:01:12.000 --> 00:01:13.000 align:start\n' +
127
+ 'Test4\n\n' +
128
+ '00:01:13.000 --> 00:01:14.000 align:end\n' +
129
+ 'Test5\n\n');
130
+ });
131
+
59
132
  /**
60
133
  * @param {!Array} cues
134
+ * @param {!Array} adCuePoints
61
135
  * @param {string} text
62
136
  */
63
- function verifyHelper(cues, text) {
64
- const result = shaka.text.WebVttGenerator.convert(cues);
137
+ function verifyHelper(cues, adCuePoints, text) {
138
+ const result = shaka.text.WebVttGenerator.convert(cues, adCuePoints);
65
139
  expect(text).toBe(result);
66
140
  }
67
141
  });
@@ -198,7 +198,7 @@ describe('Localization', () => {
198
198
  localization.changeLocale([ELVISH_WOODLAND]);
199
199
 
200
200
  expect(events.length).toBe(1);
201
- expect(events[0].locales).toEqual([ELVISH_WOODLAND]);
201
+ expect(events[0]['locales']).toEqual([ELVISH_WOODLAND]);
202
202
  });
203
203
 
204
204
 
@@ -214,23 +214,23 @@ describe('Localization', () => {
214
214
  localization.changeLocale([ELVISH_WOODLAND, DWARFISH_NORTH]);
215
215
 
216
216
  expect(events.length).toBe(1);
217
- expect(events[0].locales).toEqual([ELVISH_WOODLAND, DWARFISH_NORTH]);
217
+ expect(events[0]['locales']).toEqual([ELVISH_WOODLAND, DWARFISH_NORTH]);
218
218
 
219
219
  // We should see an event telling us that dwarfish is still missing.
220
220
  localization.insert(ELVISH_WOODLAND, new Map());
221
221
  localization.changeLocale([ELVISH_WOODLAND, DWARFISH_NORTH]);
222
222
 
223
223
  expect(events.length).toBe(2);
224
- expect(events[0].locales).toEqual([ELVISH_WOODLAND, DWARFISH_NORTH]);
225
- expect(events[1].locales).toEqual([DWARFISH_NORTH]);
224
+ expect(events[0]['locales']).toEqual([ELVISH_WOODLAND, DWARFISH_NORTH]);
225
+ expect(events[1]['locales']).toEqual([DWARFISH_NORTH]);
226
226
 
227
227
  // There should be no more events now that we added the last language.
228
228
  localization.insert(DWARFISH_NORTH, new Map());
229
229
  localization.changeLocale([ELVISH_WOODLAND, DWARFISH_NORTH]);
230
230
 
231
231
  expect(events.length).toBe(2);
232
- expect(events[0].locales).toEqual([ELVISH_WOODLAND, DWARFISH_NORTH]);
233
- expect(events[1].locales).toEqual([DWARFISH_NORTH]);
232
+ expect(events[0]['locales']).toEqual([ELVISH_WOODLAND, DWARFISH_NORTH]);
233
+ expect(events[1]['locales']).toEqual([DWARFISH_NORTH]);
234
234
  });
235
235
  });
236
236
 
@@ -373,8 +373,8 @@ describe('Localization', () => {
373
373
  // it was in the fallback (HALFLING) but not our preferred language
374
374
  // (EVLISH).
375
375
  expect(events.length).toBe(1);
376
- expect(events[0].locales).toEqual([ELVISH_WOODLAND]);
377
- expect(events[0].missing).toEqual(['hello']);
376
+ expect(events[0]['locales']).toEqual([ELVISH_WOODLAND]);
377
+ expect(events[0]['missing']).toEqual(['hello']);
378
378
  });
379
379
 
380
380
  it('fires when key/value is missing from preferred but found in base',
@@ -400,8 +400,8 @@ describe('Localization', () => {
400
400
  // because it was in the base (ELVISH) but not our preferred language
401
401
  // (EVLISH_WOODLAND).
402
402
  expect(events.length).toBe(1);
403
- expect(events[0].locales).toEqual([ELVISH_WOODLAND]);
404
- expect(events[0].missing).toEqual(['Best Wishes']);
403
+ expect(events[0]['locales']).toEqual([ELVISH_WOODLAND]);
404
+ expect(events[0]['missing']).toEqual(['Best Wishes']);
405
405
  });
406
406
 
407
407
  it('fires when key/value is missing from preferred but found in sibling',
@@ -427,8 +427,8 @@ describe('Localization', () => {
427
427
  // understand" because it was in a sibling locale (HALFLING_SHIRE)
428
428
  // but not our preferred language (HALFLING_COMMON).
429
429
  expect(events.length).toBe(1);
430
- expect(events[0].locales).toEqual([HALFLING_COMMON]);
431
- expect(events[0].missing).toEqual(['Do you understand']);
430
+ expect(events[0]['locales']).toEqual([HALFLING_COMMON]);
431
+ expect(events[0]['missing']).toEqual(['Do you understand']);
432
432
  });
433
433
 
434
434
  it('fires when key/value is missing from some preferred languages',
@@ -454,8 +454,9 @@ describe('Localization', () => {
454
454
 
455
455
  // There should have no missing localization events.
456
456
  expect(events.length).toBe(1);
457
- expect(events[0].locales).toEqual([ELVISH_WOODLAND, DWARFISH_NORTH]);
458
- expect(events[0].missing).toEqual(['may your forge burn bright']);
457
+ expect(events[0]['locales']).toEqual(
458
+ [ELVISH_WOODLAND, DWARFISH_NORTH]);
459
+ expect(events[0]['missing']).toEqual(['may your forge burn bright']);
459
460
  });
460
461
  });
461
462
 
@@ -141,7 +141,9 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
141
141
  cue.region.id = '1';
142
142
  // Position the cue *explicitly* at the bottom of the screen.
143
143
  cue.region.viewportAnchorX = 0; // %
144
- cue.region.viewportAnchorY = 100; // %
144
+ cue.region.viewportAnchorY = 90; // %
145
+ cue.region.width = 100; // %
146
+ cue.region.height = 10; // %
145
147
  textDisplayer.append([cue]);
146
148
 
147
149
  await checkScreenshot('ui', 'cue-with-controls');
@@ -314,6 +316,16 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
314
316
  await checkScreenshot(prefix, 'nested-cues-with-linebreak');
315
317
  });
316
318
 
319
+ // Regression test for #3600
320
+ it('cue positioning', async () => {
321
+ const cue = new shaka.text.Cue(0, 1, 'Text');
322
+ cue.line = 10;
323
+ cue.lineInterpretation = shaka.text.Cue.lineInterpretation.PERCENTAGE;
324
+ textDisplayer.append([cue]);
325
+
326
+ await checkScreenshot(prefix, 'cue-position');
327
+ });
328
+
317
329
  // Regression test for #2157 and #2584
318
330
  it('region positioning', async () => {
319
331
  const nestedCue = new shaka.text.Cue(
@@ -537,6 +537,41 @@ describe('StreamUtils', () => {
537
537
  expect(manifest.variants.length).toBe(1);
538
538
  expect(manifest.variants[0].decodingInfos.length).toBe(0);
539
539
  });
540
+
541
+ it('includes transferFunction in config when hdr', async () => {
542
+ window.shakaMediaCapabilities.decodingInfo =
543
+ shaka.test.Util.spyFunc(decodingInfoSpy);
544
+
545
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
546
+ manifest.addVariant(0, (variant) => {
547
+ variant.addVideo(0, (stream) => {
548
+ stream.mime('video/mp4', 'avc1.640028');
549
+ stream.hdr = 'SDR';
550
+ });
551
+ });
552
+ manifest.addVariant(1, (variant) => {
553
+ variant.addVideo(1, (stream) => {
554
+ stream.mime('video/mp4', 'hvc1.2.4.L150.90');
555
+ stream.hdr = 'PQ';
556
+ });
557
+ });
558
+ manifest.addVariant(2, (variant) => {
559
+ variant.addVideo(2, (stream) => {
560
+ stream.mime('video/mp4', 'hvc1.2.4.L153.B0');
561
+ stream.hdr = 'HLG';
562
+ });
563
+ });
564
+ });
565
+
566
+ await StreamUtils.getDecodingInfosForVariants(manifest.variants,
567
+ /* usePersistentLicenses= */ false, /* srcEquals= */ false);
568
+ expect(decodingInfoSpy.calls.argsFor(0)[0].video.transferFunction)
569
+ .toBe('srgb');
570
+ expect(decodingInfoSpy.calls.argsFor(1)[0].video.transferFunction)
571
+ .toBe('pq');
572
+ expect(decodingInfoSpy.calls.argsFor(2)[0].video.transferFunction)
573
+ .toBe('hlg');
574
+ });
540
575
  });
541
576
 
542
577
  describe('filterManifest', () => {
@@ -617,8 +652,7 @@ describe('StreamUtils', () => {
617
652
  });
618
653
 
619
654
  await shaka.util.StreamUtils.filterManifest(
620
- fakeDrmEngine, /* currentVariant= */ null, manifest,
621
- /* useMediaCapabilities= */ true);
655
+ fakeDrmEngine, /* currentVariant= */ null, manifest);
622
656
 
623
657
  // Covers a regression in which we would remove streams with codecs.
624
658
  // The last two streams should be removed because their full MIME types
@@ -645,8 +679,7 @@ describe('StreamUtils', () => {
645
679
  });
646
680
 
647
681
  await shaka.util.StreamUtils.filterManifest(
648
- fakeDrmEngine, /* currentVariant= */ null, manifest,
649
- /* useMediaCapabilities= */ true);
682
+ fakeDrmEngine, /* currentVariant= */ null, manifest);
650
683
  expect(manifest.variants.length).toBe(1);
651
684
  });
652
685
 
@@ -663,8 +696,7 @@ describe('StreamUtils', () => {
663
696
  });
664
697
 
665
698
  await shaka.util.StreamUtils.filterManifest(
666
- fakeDrmEngine, /* currentVariant= */ null, manifest,
667
- /* useMediaCapabilities= */ true);
699
+ fakeDrmEngine, /* currentVariant= */ null, manifest);
668
700
 
669
701
  expect(manifest.variants.length).toBe(1);
670
702
  });
@@ -679,6 +711,7 @@ describe('StreamUtils', () => {
679
711
  variant.bandwidth = 5058558;
680
712
  variant.addAudio(1, (stream) => {
681
713
  stream.bandwidth = 129998;
714
+ stream.codecs = 'opus';
682
715
  });
683
716
  variant.addVideo(2, (stream) => {
684
717
  stream.bandwidth = 4928560;
@@ -693,6 +726,7 @@ describe('StreamUtils', () => {
693
726
  variant.bandwidth = 4911000;
694
727
  variant.addAudio(4, (stream) => {
695
728
  stream.bandwidth = 129998;
729
+ stream.codecs = 'vorbis';
696
730
  });
697
731
  variant.addVideo(5, (stream) => {
698
732
  stream.bandwidth = 4781002;
@@ -707,6 +741,7 @@ describe('StreamUtils', () => {
707
741
  variant.bandwidth = 10850316;
708
742
  variant.addAudio(7, (stream) => {
709
743
  stream.bandwidth = 129998;
744
+ stream.codecs = 'opus';
710
745
  });
711
746
  variant.addVideo(8, (stream) => {
712
747
  stream.bandwidth = 10784324;
@@ -716,6 +751,62 @@ describe('StreamUtils', () => {
716
751
  });
717
752
  };
718
753
 
754
+ it('chooses preferred audio and video codecs', () => {
755
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
756
+ addVariant1080Avc1(manifest);
757
+ addVariant1080Vp9(manifest);
758
+ addVariant2160Vp9(manifest);
759
+ });
760
+ const variants =
761
+ shaka.util.StreamUtils.choosePreferredCodecs(manifest.variants,
762
+ /* preferredVideoCodecs= */['vp09'],
763
+ /* preferredAudioCodecs= */['opus']);
764
+
765
+ expect(variants.length).toBe(1);
766
+ expect(variants[0].video.codecs).toBe(vp09Codecs);
767
+ expect(variants[0].audio.codecs).toBe('opus');
768
+ });
769
+
770
+ it('chooses preferred video codecs', () => {
771
+ // If no preferred audio codecs is specified or can be found, choose the
772
+ // variants with preferred video codecs.
773
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
774
+ addVariant1080Avc1(manifest);
775
+ addVariant1080Vp9(manifest);
776
+ addVariant2160Vp9(manifest);
777
+ });
778
+ const variants =
779
+ shaka.util.StreamUtils.choosePreferredCodecs(manifest.variants,
780
+ /* preferredVideoCodecs= */['vp09'],
781
+ /* preferredAudioCodecs= */[]);
782
+
783
+ expect(variants.length).toBe(2);
784
+ expect(variants[0].video.codecs).toBe(vp09Codecs);
785
+ expect(variants[0].audio.codecs).toBe('vorbis');
786
+ expect(variants[1].video.codecs).toBe(vp09Codecs);
787
+ expect(variants[1].audio.codecs).toBe('opus');
788
+ });
789
+
790
+ it('chooses preferred audio codecs', () => {
791
+ // If no preferred video codecs is specified or can be found, choose the
792
+ // variants with preferred audio codecs.
793
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
794
+ addVariant1080Avc1(manifest);
795
+ addVariant1080Vp9(manifest);
796
+ addVariant2160Vp9(manifest);
797
+ });
798
+ const variants =
799
+ shaka.util.StreamUtils.choosePreferredCodecs(manifest.variants,
800
+ /* preferredVideoCodecs= */['foo'],
801
+ /* preferredAudioCodecs= */['opus']);
802
+
803
+ expect(variants.length).toBe(2);
804
+ expect(variants[0].video.codecs).toBe(avc1Codecs);
805
+ expect(variants[0].audio.codecs).toBe('opus');
806
+ expect(variants[1].video.codecs).toBe(vp09Codecs);
807
+ expect(variants[1].audio.codecs).toBe('opus');
808
+ });
809
+
719
810
  it('chooses variants with different sizes (density) by codecs', () => {
720
811
  manifest = shaka.test.ManifestGenerator.generate((manifest) => {
721
812
  addVariant1080Avc1(manifest);
@@ -723,11 +814,14 @@ describe('StreamUtils', () => {
723
814
  addVariant2160Vp9(manifest);
724
815
  });
725
816
 
726
- shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest, 2);
817
+ shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
818
+ /* preferredVideoCodecs= */[],
819
+ /* preferredAudioCodecs= */[],
820
+ /* preferredAudioChannelCount= */2,
821
+ /* preferredDecodingAttributes= */[]);
727
822
 
728
- expect(manifest.variants.length).toBe(2);
823
+ expect(manifest.variants.length).toBe(1);
729
824
  expect(manifest.variants[0].video.codecs).toBe(vp09Codecs);
730
- expect(manifest.variants[1].video.codecs).toBe(vp09Codecs);
731
825
  });
732
826
 
733
827
  it('chooses variants with same sizes (density) by codecs', () => {
@@ -736,10 +830,59 @@ describe('StreamUtils', () => {
736
830
  addVariant1080Vp9(manifest);
737
831
  });
738
832
 
739
- shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest, 2);
833
+ shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
834
+ /* preferredVideoCodecs= */[],
835
+ /* preferredAudioCodecs= */[],
836
+ /* preferredAudioChannelCount= */2,
837
+ /* preferredDecodingAttributes= */[]);
740
838
 
741
839
  expect(manifest.variants.length).toBe(1);
742
840
  expect(manifest.variants[0].video.codecs).toBe(vp09Codecs);
743
841
  });
842
+
843
+ it('chooses variants by decoding attributes', async () => {
844
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
845
+ manifest.addVariant(0, (variant) => {
846
+ variant.bandwidth = 4058558;
847
+ variant.addVideo(1, (stream) => {
848
+ stream.mime('video', 'notsmooth');
849
+ });
850
+ });
851
+ manifest.addVariant(1, (variant) => {
852
+ variant.bandwidth = 4781002;
853
+ variant.addVideo(2, (stream) => {
854
+ stream.mime('video', 'smooth');
855
+ });
856
+ });
857
+ manifest.addVariant(3, (variant) => {
858
+ variant.addVideo(4, (stream) => {
859
+ variant.bandwidth = 5058558;
860
+ stream.mime('video', 'smooth-2');
861
+ });
862
+ });
863
+ });
864
+ window.shakaMediaCapabilities.decodingInfo =
865
+ shaka.test.Util.spyFunc(decodingInfoSpy);
866
+ decodingInfoSpy.and.callFake((config) => {
867
+ const res = config.video.contentType.includes('notsmooth') ?
868
+ {supported: true, smooth: false} :
869
+ {supported: true, smooth: true};
870
+ return Promise.resolve(res);
871
+ });
872
+
873
+ await StreamUtils.getDecodingInfosForVariants(manifest.variants,
874
+ /* usePersistentLicenses= */false, /* srcEquals= */ false);
875
+
876
+ shaka.util.StreamUtils.chooseCodecsAndFilterManifest(manifest,
877
+ /* preferredVideoCodecs= */[],
878
+ /* preferredAudioCodecs= */[],
879
+ /* preferredAudioChannelCount= */2,
880
+ /* preferredDecodingAttributes= */
881
+ [shaka.util.StreamUtils.DecodingAttributes.SMOOTH]);
882
+ // 2 video codecs are smooth. Choose the one with the lowest bandwidth.
883
+ expect(manifest.variants.length).toBe(1);
884
+ expect(manifest.variants[0].id).toBe(1);
885
+ expect(manifest.variants[0].video.id).toBe(2);
886
+ });
744
887
  });
745
888
  });
@@ -36,7 +36,7 @@ shaka.ui.AirPlayButton = class extends shaka.ui.Element {
36
36
  /** @private {!HTMLButtonElement} */
37
37
  this.airplayButton_ = shaka.util.Dom.createButton();
38
38
  this.airplayButton_.classList.add('shaka-airplay-button');
39
- this.airplayButton_.setAttribute('aria-pressed', 'false');
39
+ this.airplayButton_.ariaPressed = 'false';
40
40
 
41
41
  /** @private {!HTMLElement} */
42
42
  this.airplayIcon_ = shaka.util.Dom.createHTMLElement('i');
@@ -7,7 +7,6 @@
7
7
 
8
8
  goog.provide('shaka.ui.AudioLanguageSelection');
9
9
 
10
- goog.require('shaka.ui.Constants');
11
10
  goog.require('shaka.ui.Enums');
12
11
  goog.require('shaka.ui.LanguageUtils');
13
12
  goog.require('shaka.ui.Locales');
@@ -96,10 +95,8 @@ shaka.ui.AudioLanguageSelection = class extends shaka.ui.SettingsMenu {
96
95
  updateLocalizedStrings_() {
97
96
  const LocIds = shaka.ui.Locales.Ids;
98
97
 
99
- this.backButton.setAttribute(shaka.ui.Constants.ARIA_LABEL,
100
- this.localization.resolve(LocIds.BACK));
101
- this.button.setAttribute(shaka.ui.Constants.ARIA_LABEL,
102
- this.localization.resolve(LocIds.LANGUAGE));
98
+ this.backButton.ariaLabel = this.localization.resolve(LocIds.BACK);
99
+ this.button.ariaLabel = this.localization.resolve(LocIds.LANGUAGE);
103
100
  this.nameSpan.textContent =
104
101
  this.localization.resolve(LocIds.LANGUAGE);
105
102
  this.backSpan.textContent =