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
@@ -47,17 +47,20 @@ vars:
47
47
  FirefoxMac:
48
48
  browser: firefox
49
49
  os: Mac
50
- extra_config: *firefox_config
50
+ extra_configs:
51
+ - *firefox_config
51
52
 
52
53
  FirefoxWindows:
53
54
  browser: firefox
54
55
  os: Windows
55
- extra_config: *firefox_config
56
+ extra_configs:
57
+ - *firefox_config
56
58
 
57
59
  FirefoxLinux:
58
60
  browser: firefox
59
61
  os: Linux
60
- extra_config: *firefox_config
62
+ extra_configs:
63
+ - *firefox_config
61
64
  ```
62
65
 
63
66
  ### Browsers
@@ -75,8 +78,8 @@ browser made available to Karma. Within each of those keys are the following:
75
78
  and must match the string and case used in the Selenium node config.
76
79
  - `disabled` (optional): If true, this browser is disabled and will not be
77
80
  used unless explicitly requested.
78
- - `extra_config` (optional): A dictionary of extra configs which will be
79
- merged with the WebDriver launcher config in Karma.
81
+ - `extra_configs` (optional): An array of dictionaries of extra configs which
82
+ will be merged with the WebDriver launcher config in Karma.
80
83
 
81
84
  Examples of basic desktop browsers definitions:
82
85
 
@@ -96,9 +99,9 @@ Safari:
96
99
  SafariTP:
97
100
  browser: safari
98
101
  os: Mac
99
- extra_config:
100
- safari.options:
101
- technologyPreview: true
102
+ extra_configs:
103
+ - safari.options:
104
+ technologyPreview: true
102
105
 
103
106
  ChromeWindows:
104
107
  browser: chrome
@@ -120,3 +123,52 @@ FirefoxLinux:
120
123
  browser: firefox
121
124
  os: Linux
122
125
  ```
126
+
127
+ ### Composing configs
128
+
129
+ You can define variables for browser configs that can be composed together in
130
+ `extra_configs`. For example, below you will see some basic definitions for
131
+ Chrome arguments and parameters, and then an additional config with an argument
132
+ that is only needed for some platforms. `karma.conf.js` will merge those
133
+ argument lists intelligently when it loads the YAML config.
134
+
135
+ ```yaml
136
+ vars:
137
+ basic_chrome_config: &basic_chrome_config
138
+ goog:chromeOptions:
139
+ args:
140
+ # Normally, Chrome disallows autoplaying videos in many cases. Enable
141
+ # it for testing.
142
+ - "--autoplay-policy=no-user-gesture-required"
143
+
144
+ # Instruct chromedriver not to disable component updater.
145
+ excludeSwitches:
146
+ - "disable-component-update"
147
+
148
+ headless_chrome_config: &headless_chrome_config
149
+ goog:chromeOptions:
150
+ args:
151
+ # Run in headless mode.
152
+ - "--headless"
153
+
154
+ ChromeLinux:
155
+ browser: chrome
156
+ os: Mac
157
+ extra_configs:
158
+ - *basic_chrome_config
159
+
160
+ ChromeWindows:
161
+ browser: chrome
162
+ os: Mac
163
+ extra_configs:
164
+ - *basic_chrome_config
165
+
166
+ ChromeMac:
167
+ browser: chrome
168
+ os: Mac
169
+ # Take the parameters and arguments for basic_chrome_config, then append the
170
+ # arguments for headless_chrome_config.
171
+ extra_configs:
172
+ - *basic_chrome_config
173
+ - *headless_chrome_config
174
+ ```
package/karma.conf.js CHANGED
@@ -7,9 +7,11 @@
7
7
  // Karma configuration
8
8
  // Install required modules by running "npm install"
9
9
 
10
- const Jimp = require('jimp');
10
+ // lodash is an indirect dependency, depended on by Karma
11
+ const _ = require('lodash');
11
12
  const fs = require('fs');
12
13
  const glob = require('glob');
14
+ const Jimp = require('jimp');
13
15
  const path = require('path');
14
16
  const rimraf = require('rimraf');
15
17
  const {ssim} = require('ssim.js');
@@ -17,6 +19,32 @@ const util = require('karma/common/util');
17
19
  const which = require('which');
18
20
  const yaml = require('js-yaml');
19
21
 
22
+ /**
23
+ * Like Object.assign, but recursive and doesn't clobber objects and arrays.
24
+ * If two arrays are merged, they are concatenated.
25
+ * Ex:
26
+ * mergeConfigs({ foo: 'bar', args: [1, 2, 3] },
27
+ * { baz: 'blah', args: [4, 5, 6] })
28
+ * => { foo: 'bar', baz: 'blah', args: [1, 2, 3, 4, 5, 6] }
29
+ *
30
+ * @param {Object} first
31
+ * @param {Object} second
32
+ * @return {Object}
33
+ */
34
+ function mergeConfigs(first, second) {
35
+ return _.mergeWith(
36
+ first,
37
+ second,
38
+ (firstValue, secondValue) => {
39
+ // Merge arrays by concatenation.
40
+ if (Array.isArray(firstValue)) {
41
+ return firstValue.concat(secondValue);
42
+ }
43
+ // Use lodash's default merge behavior for everything else.
44
+ return undefined;
45
+ });
46
+ }
47
+
20
48
  /**
21
49
  * @param {Object} config
22
50
  */
@@ -78,7 +106,7 @@ module.exports = (config) => {
78
106
  }
79
107
 
80
108
  // Add standard WebDriver configs.
81
- Object.assign(launcher, {
109
+ mergeConfigs(launcher, {
82
110
  base: 'WebDriver',
83
111
  config: {hostname: gridHostname, port: gridPort},
84
112
  pseudoActivityInterval: 20000,
@@ -87,8 +115,10 @@ module.exports = (config) => {
87
115
  version: metadata.version,
88
116
  });
89
117
 
90
- if (metadata.extra_config) {
91
- Object.assign(launcher, metadata.extra_config);
118
+ if (metadata.extra_configs) {
119
+ for (const config of metadata.extra_configs) {
120
+ mergeConfigs(launcher, config);
121
+ }
92
122
  }
93
123
  }
94
124
 
@@ -603,15 +633,27 @@ function WebDriverScreenshotMiddlewareFactory(launcher) {
603
633
  }
604
634
 
605
635
  /**
636
+ * @param {karma.Launcher.Browser.spec} spec
606
637
  * @param {wd.remote} webDriverClient A WebDriver client, an object from the
607
638
  * "wd" package, created by "wd.remote()".
608
639
  * @return {!Promise.<!Buffer>} A Buffer containing a PNG screenshot
609
640
  */
610
- function getScreenshot(webDriverClient) {
641
+ function getScreenshot(spec, webDriverClient) {
611
642
  return new Promise((resolve, reject) => {
612
643
  webDriverClient.takeScreenshot((error, pngBase64) => {
613
644
  if (error) {
614
645
  reject(error);
646
+ } else if (pngBase64.error) {
647
+ // In some failure cases, pngBase64 is an object with "error",
648
+ // "message", and "stacktrace" fields. This happens, for example,
649
+ // with a timeout from the screenshot command. This is not an
650
+ // expected situation, so log it. The extra newlines keep this from
651
+ // being overwritten on the terminal when running tests against many
652
+ // browsers at once.
653
+ console.log('\n\nUnexpected screenshot failure:\n' +
654
+ ` Error: ${JSON.stringify(pngBase64)}\n` +
655
+ ` WebDriver spec: ${JSON.stringify(spec)}\n\n\n`);
656
+ reject(pngBase64);
615
657
  } else {
616
658
  // Convert the screenshot to a binary buffer.
617
659
  resolve(Buffer.from(pngBase64, 'base64'));
@@ -635,7 +677,8 @@ function WebDriverScreenshotMiddlewareFactory(launcher) {
635
677
  }
636
678
 
637
679
  /** @type {!Buffer} */
638
- const fullPageScreenshotData = await getScreenshot(webDriverClient);
680
+ const fullPageScreenshotData =
681
+ await getScreenshot(browser.spec, webDriverClient);
639
682
 
640
683
  // Crop the screenshot to the dimensions specified in the test.
641
684
  // Jimp is picky about types, so convert these strings to numbers.
@@ -754,7 +797,7 @@ function WebDriverScreenshotMiddlewareFactory(launcher) {
754
797
  // The result is cached for the sake of performance.
755
798
  if (webDriverClient.canTakeScreenshot === undefined) {
756
799
  try {
757
- await getScreenshot(webDriverClient);
800
+ await getScreenshot(browser.spec, webDriverClient);
758
801
  webDriverClient.canTakeScreenshot = true;
759
802
  } catch (error) {
760
803
  webDriverClient.canTakeScreenshot = false;
@@ -48,6 +48,9 @@ shaka.abr.SimpleAbrManager = class {
48
48
  /** @private {shaka.abr.EwmaBandwidthEstimator} */
49
49
  this.bandwidthEstimator_ = new shaka.abr.EwmaBandwidthEstimator();
50
50
 
51
+ /** @private {?function():void} */
52
+ this.onNetworkInformationChange_ = null;
53
+
51
54
  // Some browsers implement the Network Information API, which allows
52
55
  // retrieving information about a user's network connection. We listen
53
56
  // to the change event to be able to make quick changes in case the type
@@ -98,9 +101,6 @@ shaka.abr.SimpleAbrManager = class {
98
101
  /** @private {ResizeObserver} */
99
102
  this.resizeObserver_ = null;
100
103
 
101
- /** @private {?function():void} */
102
- this.onNetworkInformationChange_ = null;
103
-
104
104
  /** @private {shaka.util.Timer} */
105
105
  this.resizeObserverTimer_ = new shaka.util.Timer(() => {
106
106
  if (this.config_.restrictToElementSize) {
@@ -175,8 +175,8 @@ shaka.abr.SimpleAbrManager = class {
175
175
  if (this.resizeObserver_ && this.config_.restrictToElementSize) {
176
176
  const devicePixelRatio =
177
177
  this.config_.ignoreDevicePixelRatio ? 1 : window.devicePixelRatio;
178
- maxHeight = this.mediaElement_.clientWidth * devicePixelRatio;
179
- maxWidth = this.mediaElement_.clientHeight * devicePixelRatio;
178
+ maxHeight = this.mediaElement_.clientHeight * devicePixelRatio;
179
+ maxWidth = this.mediaElement_.clientWidth * devicePixelRatio;
180
180
  }
181
181
 
182
182
  // Get sorted Variants.
package/lib/player.js CHANGED
@@ -2069,10 +2069,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2069
2069
 
2070
2070
  this.playhead_.setStartTime(adjustedTime);
2071
2071
  }
2072
-
2073
- // Since the first streams just became active, send an adaptation event.
2074
- this.onAdaptation_(null,
2075
- shaka.util.StreamUtils.variantToTrack(initialVariant));
2076
2072
  }
2077
2073
 
2078
2074
  this.playhead_.ready();
@@ -6635,7 +6631,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
6635
6631
  * @define {string} A version number taken from git at compile time.
6636
6632
  * @export
6637
6633
  */
6638
- shaka.Player.version = 'v4.2.12-uncompiled';
6634
+ shaka.Player.version = 'v4.2.13-uncompiled';
6639
6635
 
6640
6636
  // Initialize the deprecation system using the version string we just set
6641
6637
  // on the player.
@@ -6,6 +6,7 @@
6
6
 
7
7
  goog.provide('shaka.polyfill.Orientation');
8
8
 
9
+ goog.require('shaka.log');
9
10
  goog.require('shaka.util.FakeEvent');
10
11
  goog.require('shaka.util.FakeEventTarget');
11
12
  goog.require('shaka.polyfill');
@@ -23,21 +24,47 @@ shaka.polyfill.Orientation = class {
23
24
  * @export
24
25
  */
25
26
  static install() {
26
- if (screen.orientation) {
27
+ if (screen.orientation && screen.orientation.unlock) {
27
28
  // Not needed.
29
+ shaka.log.info('Using native screen.orientation');
28
30
  return;
29
31
  }
30
32
 
31
- // There is no way to check to see if the 'orientationchange' event exists
32
- // on window, which could theoretically lead to this making a
33
- // screen.orientation object that doesn't actually work.
34
- // However, it looks like all platforms that support the deprecated
35
- // window.orientation feature also support that event.
36
- if (window.orientation != undefined) {
33
+ if (screen.orientation != undefined) {
34
+ // There are some platforms where screen.orientation is defined but
35
+ // incomplete (e.g. Safari).
36
+ // Install a very simple polyfill in that case.
37
+ shaka.polyfill.Orientation.installBasedOnScreenMethods_();
38
+ } else if (window.orientation != undefined) {
39
+ // There is no way to check to see if the 'orientationchange' event exists
40
+ // on window, which could theoretically lead to this making a
41
+ // screen.orientation object that doesn't actually work.
42
+ // However, it looks like all platforms that support the deprecated
43
+ // window.orientation feature also support that event.
37
44
  shaka.polyfill.Orientation.installBasedOnWindowMethods_();
38
45
  }
39
46
  }
40
47
 
48
+ /**
49
+ * Modifies screen.orientation to add no-ops for missing methods.
50
+ * Meant for cases where screen.orientation is defined, but has missing
51
+ * methods that cannot be properly polyfilled.
52
+ * @private
53
+ */
54
+ static installBasedOnScreenMethods_() {
55
+ if (screen.orientation.lock === undefined) {
56
+ screen.orientation.lock = (orientation) => {
57
+ shaka.log.info('screen.orientation.lock is a no-op');
58
+ return Promise.resolve();
59
+ };
60
+ }
61
+ if (screen.orientation.unlock === undefined) {
62
+ screen.orientation.unlock = () => {
63
+ shaka.log.info('screen.orientation.unlock is a no-op');
64
+ };
65
+ }
66
+ }
67
+
41
68
  /**
42
69
  * Makes a polyfill for orientation, based on window methods.
43
70
  * Note that some of the features this is based on are deprecated, so this
@@ -674,6 +674,7 @@ shaka.text.VttTextParser = class {
674
674
  cue.fontWeight = refCue.fontWeight;
675
675
  cue.fontStyle = refCue.fontStyle;
676
676
  cue.opacity = refCue.opacity;
677
+ cue.textShadow = refCue.textShadow;
677
678
  cue.wrapLine = refCue.wrapLine;
678
679
  }
679
680
 
@@ -180,8 +180,10 @@ shaka.util.ManifestParserUtils.VIDEO_CODEC_REGEXPS_ = [
180
180
  */
181
181
  shaka.util.ManifestParserUtils.AUDIO_CODEC_REGEXPS_ = [
182
182
  /^vorbis$/,
183
- /^opus$/,
184
- /^flac$/,
183
+ /^Opus$/, // correct codec string according to RFC 6381 section 3.3
184
+ /^opus$/, // some manifests wrongfully use this
185
+ /^fLaC$/, // correct codec string according to RFC 6381 section 3.3
186
+ /^flac$/, // some manifests wrongfully use this
185
187
  /^mp4a/,
186
188
  /^[ae]c-3$/,
187
189
  /^ac-4$/,
@@ -346,6 +346,20 @@ shaka.util.Platform = class {
346
346
  return shaka.util.Platform.isApple() && navigator.maxTouchPoints > 1;
347
347
  }
348
348
 
349
+ /**
350
+ * Return true if the platform is a Mac, regardless of the browser.
351
+ *
352
+ * @return {boolean}
353
+ */
354
+ static isMac() {
355
+ // Try the newer standard first.
356
+ if (navigator.userAgentData && navigator.userAgentData.platform) {
357
+ return navigator.userAgentData.platform.toLowerCase() == 'macos';
358
+ }
359
+ // Fall back to the old API, with less strict matching.
360
+ return navigator.platform.toLowerCase().includes('mac');
361
+ }
362
+
349
363
  /**
350
364
  * Check if the user agent contains a key. This is the best way we know of
351
365
  * right now to detect platforms. If there is a better way, please send a
@@ -436,47 +436,61 @@ shaka.util.StreamUtils = class {
436
436
  manifest.variants = manifest.variants.filter((variant) => {
437
437
  // See: https://github.com/shaka-project/shaka-player/issues/3860
438
438
  const video = variant.video;
439
+
439
440
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
441
+ const ManifestParserUtils = shaka.util.ManifestParserUtils;
442
+ const MimeUtils = shaka.util.MimeUtils;
443
+ const StreamUtils = shaka.util.StreamUtils;
444
+
440
445
  if (video) {
441
- let videoCodecs =
442
- shaka.util.StreamUtils.getCorrectVideoCodecs_(video.codecs);
446
+ let videoCodecs = StreamUtils.getCorrectVideoCodecs_(video.codecs);
447
+
443
448
  // For multiplexed streams. Here we must check the audio of the
444
449
  // stream to see if it is compatible.
445
450
  if (video.codecs.includes(',')) {
446
451
  const allCodecs = video.codecs.split(',');
447
- videoCodecs = shaka.util.ManifestParserUtils.guessCodecs(
452
+
453
+ videoCodecs = ManifestParserUtils.guessCodecs(
448
454
  ContentType.VIDEO, allCodecs);
449
- videoCodecs =
450
- shaka.util.StreamUtils.getCorrectVideoCodecs_(videoCodecs);
451
- let audioCodecs = shaka.util.ManifestParserUtils.guessCodecs(
455
+ videoCodecs = StreamUtils.getCorrectVideoCodecs_(videoCodecs);
456
+
457
+ let audioCodecs = ManifestParserUtils.guessCodecs(
452
458
  ContentType.AUDIO, allCodecs);
453
- audioCodecs =
454
- shaka.util.StreamUtils.getCorrectAudioCodecs_(audioCodecs);
455
- const audioFullType = shaka.util.MimeUtils.getFullOrConvertedType(
459
+ audioCodecs = StreamUtils.getCorrectAudioCodecs_(audioCodecs);
460
+
461
+ const audioFullType = MimeUtils.getFullOrConvertedType(
456
462
  video.mimeType, audioCodecs, ContentType.AUDIO);
463
+
457
464
  if (!MediaSource.isTypeSupported(audioFullType)) {
458
465
  return false;
459
466
  }
467
+
460
468
  // Update the codec string with the (possibly) converted codecs.
461
469
  videoCodecs = [videoCodecs, audioCodecs].join(',');
462
470
  }
463
- const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
471
+
472
+ const fullType = MimeUtils.getFullOrConvertedType(
464
473
  video.mimeType, videoCodecs, ContentType.VIDEO);
474
+
465
475
  if (!MediaSource.isTypeSupported(fullType)) {
466
476
  return false;
467
477
  }
478
+
468
479
  // Update the codec string with the (possibly) converted codecs.
469
480
  video.codecs = videoCodecs;
470
481
  }
482
+
471
483
  const audio = variant.audio;
484
+
472
485
  if (audio) {
473
- const codecs =
474
- shaka.util.StreamUtils.getCorrectAudioCodecs_(audio.codecs);
475
- const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
486
+ const codecs = StreamUtils.getCorrectAudioCodecs_(audio.codecs);
487
+ const fullType = MimeUtils.getFullOrConvertedType(
476
488
  audio.mimeType, codecs, ContentType.AUDIO);
489
+
477
490
  if (!MediaSource.isTypeSupported(fullType)) {
478
491
  return false;
479
492
  }
493
+
480
494
  // Update the codec string with the (possibly) converted codecs.
481
495
  audio.codecs = codecs;
482
496
  }
@@ -488,7 +502,7 @@ shaka.util.StreamUtils = class {
488
502
  (video.codecs.includes('avc1.') ||
489
503
  video.codecs.includes('avc3.'))) {
490
504
  shaka.log.debug('Dropping variant - not compatible with platform',
491
- shaka.util.StreamUtils.getVariantSummaryString_(variant));
505
+ StreamUtils.getVariantSummaryString_(variant));
492
506
  return false;
493
507
  }
494
508
 
@@ -498,7 +512,7 @@ shaka.util.StreamUtils = class {
498
512
  // Filter out all unsupported variants.
499
513
  if (!supported) {
500
514
  shaka.log.debug('Dropping variant - not compatible with platform',
501
- shaka.util.StreamUtils.getVariantSummaryString_(variant));
515
+ StreamUtils.getVariantSummaryString_(variant));
502
516
  }
503
517
  return supported;
504
518
  });
@@ -562,7 +576,11 @@ shaka.util.StreamUtils = class {
562
576
  static getDecodingConfigs_(variant, usePersistentLicenses, srcEquals) {
563
577
  const audio = variant.audio;
564
578
  const video = variant.video;
579
+
565
580
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
581
+ const ManifestParserUtils = shaka.util.ManifestParserUtils;
582
+ const MimeUtils = shaka.util.MimeUtils;
583
+ const StreamUtils = shaka.util.StreamUtils;
566
584
 
567
585
  /** @type {!MediaDecodingConfiguration} */
568
586
  const mediaDecodingConfig = {
@@ -571,19 +589,23 @@ shaka.util.StreamUtils = class {
571
589
 
572
590
  if (video) {
573
591
  let videoCodecs = video.codecs;
592
+
574
593
  // For multiplexed streams with audio+video codecs, the config should have
575
594
  // AudioConfiguration and VideoConfiguration.
576
595
  if (video.codecs.includes(',')) {
577
596
  const allCodecs = video.codecs.split(',');
578
- videoCodecs = shaka.util.ManifestParserUtils.guessCodecs(
597
+
598
+ videoCodecs = ManifestParserUtils.guessCodecs(
579
599
  ContentType.VIDEO, allCodecs);
580
- videoCodecs =
581
- shaka.util.StreamUtils.getCorrectVideoCodecs_(videoCodecs);
582
- const audioCodecs = shaka.util.ManifestParserUtils.guessCodecs(
600
+ videoCodecs = StreamUtils.getCorrectVideoCodecs_(videoCodecs);
601
+
602
+ let audioCodecs = ManifestParserUtils.guessCodecs(
583
603
  ContentType.AUDIO, allCodecs);
604
+ audioCodecs = StreamUtils.getCorrectAudioCodecs_(audioCodecs);
584
605
 
585
- const audioFullType = shaka.util.MimeUtils.getFullOrConvertedType(
606
+ const audioFullType = MimeUtils.getFullOrConvertedType(
586
607
  video.mimeType, audioCodecs, ContentType.AUDIO);
608
+
587
609
  mediaDecodingConfig.audio = {
588
610
  contentType: audioFullType,
589
611
  channels: 2,
@@ -592,9 +614,11 @@ shaka.util.StreamUtils = class {
592
614
  spatialRendering: false,
593
615
  };
594
616
  }
595
- videoCodecs = shaka.util.StreamUtils.getCorrectVideoCodecs_(videoCodecs);
596
- const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
617
+
618
+ videoCodecs = StreamUtils.getCorrectVideoCodecs_(videoCodecs);
619
+ const fullType = MimeUtils.getFullOrConvertedType(
597
620
  video.mimeType, videoCodecs, ContentType.VIDEO);
621
+
598
622
  // VideoConfiguration
599
623
  mediaDecodingConfig.video = {
600
624
  contentType: fullType,
@@ -627,9 +651,8 @@ shaka.util.StreamUtils = class {
627
651
  }
628
652
  }
629
653
  if (audio) {
630
- const codecs =
631
- shaka.util.StreamUtils.getCorrectAudioCodecs_(audio.codecs);
632
- const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
654
+ const codecs = StreamUtils.getCorrectAudioCodecs_(audio.codecs);
655
+ const fullType = MimeUtils.getFullOrConvertedType(
633
656
  audio.mimeType, codecs, ContentType.AUDIO);
634
657
 
635
658
  // AudioConfiguration
@@ -760,6 +783,20 @@ shaka.util.StreamUtils = class {
760
783
  * @private
761
784
  */
762
785
  static getCorrectAudioCodecs_(codecs) {
786
+ // According to RFC 6381 section 3.3, 'fLaC' is actually the correct
787
+ // codec string. We still need to map it to 'flac', as some browsers
788
+ // currently don't support 'fLaC', while 'flac' is supported by most
789
+ // major browsers.
790
+ // See https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
791
+ if (codecs === 'fLaC') {
792
+ return 'flac';
793
+ }
794
+
795
+ // The same is true for 'Opus'.
796
+ if (codecs === 'Opus') {
797
+ return 'opus';
798
+ }
799
+
763
800
  // Some Tizen devices seem to misreport AC-3 support, but correctly
764
801
  // report EC-3 support. So query EC-3 as a fallback for AC-3.
765
802
  // See https://github.com/shaka-project/shaka-player/issues/2989 for
@@ -1238,6 +1275,9 @@ shaka.util.StreamUtils = class {
1238
1275
  if (textTrack.kind == 'captions') {
1239
1276
  track.mimeType = CLOSED_CAPTION_MIMETYPE;
1240
1277
  }
1278
+ if (textTrack.kind == 'subtitles') {
1279
+ track.mimeType = 'text/vtt';
1280
+ }
1241
1281
  if (textTrack.kind) {
1242
1282
  track.roles = [textTrack.kind];
1243
1283
  }
@@ -1285,13 +1325,15 @@ shaka.util.StreamUtils = class {
1285
1325
  * @private
1286
1326
  */
1287
1327
  static html5TrackToGenericShakaTrack_(html5Track) {
1328
+ const language = html5Track.language;
1329
+
1288
1330
  /** @type {shaka.extern.Track} */
1289
1331
  const track = {
1290
1332
  id: shaka.util.StreamUtils.html5TrackId(html5Track),
1291
1333
  active: false,
1292
1334
  type: '',
1293
1335
  bandwidth: 0,
1294
- language: shaka.util.LanguageUtils.normalize(html5Track.language),
1336
+ language: shaka.util.LanguageUtils.normalize(language || 'und'),
1295
1337
  label: html5Track.label,
1296
1338
  kind: html5Track.kind,
1297
1339
  width: null,
@@ -1321,6 +1363,7 @@ shaka.util.StreamUtils = class {
1321
1363
  originalAudioId: null,
1322
1364
  originalTextId: null,
1323
1365
  originalImageId: null,
1366
+ originalLanguage: language,
1324
1367
  };
1325
1368
 
1326
1369
  return track;
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": "4.2.12",
4
+ "version": "4.2.13",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -42,7 +42,7 @@
42
42
  "karma-coverage": "^2.2.0",
43
43
  "karma-jasmine": "^4.0.1",
44
44
  "karma-jasmine-ajax": "^0.1.13",
45
- "karma-local-wd-launcher": "^1.6.2",
45
+ "karma-local-wd-launcher": "^1.6.4",
46
46
  "karma-opera-launcher": "^1.0.0",
47
47
  "karma-sourcemap-loader": "^0.3.8",
48
48
  "karma-spec-reporter": "^0.0.34",
@@ -171,7 +171,10 @@ describe('CastUtils', () => {
171
171
  }
172
172
  });
173
173
 
174
- describe('TimeRanges', () => {
174
+ // Disable because these tests are flakey on ChromeLinux, and this whole
175
+ // module will be removed in
176
+ // https://github.com/shaka-project/shaka-player/issues/4214
177
+ xdescribe('TimeRanges', () => {
175
178
  /** @type {!HTMLVideoElement} */
176
179
  let video;
177
180
  /** @type {!shaka.util.EventManager} */