shaka-player 4.2.12 → 4.2.13

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 (42) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +11 -0
  2. package/.github/workflows/build-and-test.yaml +15 -0
  3. package/.github/workflows/selenium-lab-tests.yaml +3 -2
  4. package/.github/workflows/update-issues.yaml +1 -0
  5. package/CHANGELOG.md +17 -0
  6. package/dist/deps.js +1 -1
  7. package/dist/locales.js +31 -31
  8. package/dist/shaka-player.compiled.debug.js +23 -24
  9. package/dist/shaka-player.compiled.debug.map +3 -3
  10. package/dist/shaka-player.compiled.js +368 -369
  11. package/dist/shaka-player.compiled.map +3 -3
  12. package/dist/shaka-player.ui.debug.js +27 -29
  13. package/dist/shaka-player.ui.debug.map +3 -3
  14. package/dist/shaka-player.ui.js +383 -383
  15. package/dist/shaka-player.ui.map +2 -2
  16. package/docs/tutorials/selenium-grid-config.md +60 -8
  17. package/karma.conf.js +50 -7
  18. package/lib/abr/simple_abr_manager.js +5 -5
  19. package/lib/player.js +1 -5
  20. package/lib/polyfill/orientation.js +34 -7
  21. package/lib/text/vtt_text_parser.js +1 -0
  22. package/lib/util/manifest_parser_utils.js +4 -2
  23. package/lib/util/platform.js +14 -0
  24. package/lib/util/stream_utils.js +69 -26
  25. package/package.json +2 -2
  26. package/test/cast/cast_utils_unit.js +4 -1
  27. package/test/hls/hls_parser_unit.js +72 -0
  28. package/test/media/drm_engine_integration.js +2 -2
  29. package/test/media/segment_index_unit.js +3 -3
  30. package/test/media/streaming_engine_integration.js +14 -11
  31. package/test/offline/offline_integration.js +6 -3
  32. package/test/player_external.js +19 -16
  33. package/test/player_integration.js +35 -48
  34. package/test/player_src_equals_integration.js +9 -5
  35. package/test/test/util/fake_demo_main.js +7 -3
  36. package/test/test/util/layout_tests.js +2 -2
  37. package/test/test/util/ui_utils.js +9 -2
  38. package/test/test/util/util.js +6 -27
  39. package/test/test/util/waiter.js +73 -3
  40. package/test/ui/ad_ui_unit.js +9 -9
  41. package/test/util/stream_utils_unit.js +46 -0
  42. package/ui/range_element.js +5 -0
@@ -255,33 +255,12 @@ shaka.test.Util = class {
255
255
  * @param {string} uri
256
256
  * @return {!Promise.<!ArrayBuffer>}
257
257
  */
258
- static fetch(uri) {
259
- return new Promise(((resolve, reject) => {
260
- const xhr = new XMLHttpRequest();
261
- xhr.open('GET', uri, /* asynchronous= */ true);
262
- xhr.responseType = 'arraybuffer';
263
-
264
- xhr.onload = (event) => {
265
- if (xhr.status >= 200 &&
266
- xhr.status <= 299 &&
267
- !!xhr.response) {
268
- resolve(/** @type {!ArrayBuffer} */(xhr.response));
269
- } else {
270
- let message = '';
271
- if (xhr.response) {
272
- message = ': ' + shaka.util.StringUtils.fromUTF8(
273
- /** @type {!ArrayBuffer} */(xhr.response));
274
- }
275
- reject(xhr.status + message);
276
- }
277
- };
278
-
279
- xhr.onerror = (event) => {
280
- reject('shaka.test.Util.fetch failed: ' + uri);
281
- };
282
-
283
- xhr.send(/* body= */ null);
284
- }));
258
+ static async fetch(uri) {
259
+ const response = await fetch(uri);
260
+ if (!response.ok) {
261
+ throw new Error('shaka.test.Util.fetch failed: ' + uri);
262
+ }
263
+ return response.arrayBuffer();
285
264
  }
286
265
 
287
266
  /**
@@ -109,6 +109,8 @@ shaka.test.Waiter = class {
109
109
  * @return {!Promise}
110
110
  */
111
111
  waitUntilPlayheadReaches(mediaElement, timeGoal) {
112
+ this.macPlaybackWorkaround_(mediaElement);
113
+
112
114
  // The name of what we're waiting for
113
115
  const goalName = 'movement from ' + mediaElement.currentTime +
114
116
  ' to ' + timeGoal;
@@ -153,6 +155,8 @@ shaka.test.Waiter = class {
153
155
  * @return {!Promise}
154
156
  */
155
157
  waitForEnd(mediaElement) {
158
+ this.macPlaybackWorkaround_(mediaElement);
159
+
156
160
  // The name of what we're waiting for.
157
161
  const goalName = 'end of media';
158
162
 
@@ -207,13 +211,64 @@ shaka.test.Waiter = class {
207
211
  * Wait for the video to end or for |timeout| seconds to pass, whichever
208
212
  * occurs first. The Promise is resolved when either of these happens.
209
213
  *
210
- * @param {!HTMLMediaElement} target
214
+ * @param {!HTMLMediaElement} mediaElement
211
215
  * @param {number} timeout in seconds, after which the Promise succeeds
212
216
  * @return {!Promise}
213
217
  */
214
- waitForEndOrTimeout(target, timeout) {
218
+ waitForEndOrTimeout(mediaElement, timeout) {
215
219
  this.failOnTimeout(false).timeoutAfter(timeout);
216
- return this.waitForEnd(target);
220
+ return this.waitForEnd(mediaElement);
221
+ }
222
+
223
+ /**
224
+ * Wait until a certain amount of content is buffered.
225
+ *
226
+ * @param {!HTMLMediaElement} mediaElement
227
+ * @param {number} bufferingGoal in seconds, after which the Promise succeeds
228
+ * @return {!Promise}
229
+ */
230
+ waitUntilBuffered(mediaElement, bufferingGoal) {
231
+ // The name of what we're waiting for.
232
+ const goalName = `${bufferingGoal} seconds buffered`;
233
+
234
+ // The conditions for success.
235
+ const bufferedEnough = () => {
236
+ const end = shaka.media.TimeRangesUtils.bufferEnd(mediaElement.buffered);
237
+ if (end == null) {
238
+ return false;
239
+ }
240
+ return end - mediaElement.currentTime >= bufferingGoal;
241
+ };
242
+
243
+ if (bufferedEnough()) {
244
+ return Promise.resolve();
245
+ }
246
+
247
+ // Cleanup on timeout.
248
+ let timer = null;
249
+ const cleanup = () => {
250
+ if (timer) {
251
+ timer.stop();
252
+ }
253
+ this.eventManager_.unlisten(mediaElement, 'timeupdate');
254
+ this.eventManager_.unlisten(mediaElement, 'ended');
255
+ };
256
+
257
+ const p = new Promise((resolve) => {
258
+ const check = () => {
259
+ if (bufferedEnough()) {
260
+ cleanup();
261
+ resolve();
262
+ }
263
+ };
264
+
265
+ timer = new shaka.util.Timer(check);
266
+ timer.tickEvery(/* seconds= */ 1);
267
+ this.eventManager_.listen(mediaElement, 'timeupdate', check);
268
+ this.eventManager_.listen(mediaElement, 'ended', check);
269
+ });
270
+
271
+ return this.waitUntilGeneric_(goalName, p, cleanup, mediaElement);
217
272
  }
218
273
 
219
274
  /**
@@ -333,4 +388,19 @@ shaka.test.Waiter = class {
333
388
  `buffered: ${JSON.stringify(buffered)}\n`;
334
389
  shaka.log.error(error.message);
335
390
  }
391
+
392
+ /**
393
+ * @param {!HTMLMediaElement} mediaElement
394
+ * @private
395
+ */
396
+ macPlaybackWorkaround_(mediaElement) {
397
+ if (shaka.util.Platform.isMac()) {
398
+ // Work around bizarre playback slowdowns that only seem to occur with
399
+ // WebDriver and only on Mac. Increasing the playback rate allows tests
400
+ // to complete without timing out.
401
+ if (mediaElement.playbackRate == 1) {
402
+ mediaElement.playbackRate = 2;
403
+ }
404
+ }
405
+ }
336
406
  };
@@ -25,15 +25,6 @@ describe('Ad UI', () => {
25
25
  shaka.Player.setAdManagerFactory(() => new shaka.test.FakeAdManager());
26
26
  });
27
27
 
28
- afterEach(async () => {
29
- await UiUtils.cleanupUI();
30
- });
31
-
32
- afterAll(() => {
33
- document.head.removeChild(cssLink);
34
- shaka.Player.setAdManagerFactory(() => new shaka.ads.AdManager());
35
- });
36
-
37
28
  beforeEach(() => {
38
29
  container =
39
30
  /** @type {!HTMLElement} */ (document.createElement('div'));
@@ -45,6 +36,15 @@ describe('Ad UI', () => {
45
36
  adManager = video['ui'].getControls().getPlayer().getAdManager();
46
37
  });
47
38
 
39
+ afterEach(async () => {
40
+ await UiUtils.cleanupUI();
41
+ });
42
+
43
+ afterAll(() => {
44
+ document.head.removeChild(cssLink);
45
+ shaka.Player.setAdManagerFactory(() => new shaka.ads.AdManager());
46
+ });
47
+
48
48
  it('is invisible if no ad is playing', () => {
49
49
  const adControlsContainer =
50
50
  UiUtils.getElementByClassName(container, 'shaka-ad-controls');
@@ -718,6 +718,52 @@ describe('StreamUtils', () => {
718
718
  expect(manifest.variants.length).toBe(1);
719
719
  });
720
720
 
721
+ it('supports fLaC codec', async () => {
722
+ if (!MediaSource.isTypeSupported('audio/mp4; codecs="flac"')) {
723
+ pending('Codec fLaC is not supported by the platform.');
724
+ }
725
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
726
+ manifest.addVariant(0, (variant) => {
727
+ variant.addAudio(1, (stream) => {
728
+ stream.mime('audio/mp4', 'fLaC');
729
+ });
730
+ });
731
+ manifest.addVariant(2, (variant) => {
732
+ variant.addAudio(3, (stream) => {
733
+ stream.mime('audio/mp4', 'flac');
734
+ });
735
+ });
736
+ });
737
+
738
+ await shaka.util.StreamUtils.filterManifest(
739
+ fakeDrmEngine, /* currentVariant= */ null, manifest);
740
+
741
+ expect(manifest.variants.length).toBe(2);
742
+ });
743
+
744
+ it('supports Opus codec', async () => {
745
+ if (!MediaSource.isTypeSupported('audio/mp4; codecs="opus"')) {
746
+ pending('Codec Opus is not supported by the platform.');
747
+ }
748
+ manifest = shaka.test.ManifestGenerator.generate((manifest) => {
749
+ manifest.addVariant(0, (variant) => {
750
+ variant.addAudio(1, (stream) => {
751
+ stream.mime('audio/mp4', 'Opus');
752
+ });
753
+ });
754
+ manifest.addVariant(2, (variant) => {
755
+ variant.addAudio(3, (stream) => {
756
+ stream.mime('audio/mp4', 'opus');
757
+ });
758
+ });
759
+ });
760
+
761
+ await shaka.util.StreamUtils.filterManifest(
762
+ fakeDrmEngine, /* currentVariant= */ null, manifest);
763
+
764
+ expect(manifest.variants.length).toBe(2);
765
+ });
766
+
721
767
  it('supports legacy AVC1 codec', async () => {
722
768
  if (!MediaSource.isTypeSupported('video/mp4; codecs="avc1.42001e"')) {
723
769
  pending('Codec avc1.42001e is not supported by the platform.');
@@ -110,6 +110,11 @@ shaka.ui.RangeElement = class extends shaka.ui.Element {
110
110
  this.onChangeEnd();
111
111
  }
112
112
  });
113
+
114
+ this.eventManager.listen(this.bar, 'contextmenu', (e) => {
115
+ e.preventDefault();
116
+ e.stopPropagation();
117
+ });
113
118
  }
114
119
 
115
120
  /** @override */