shaka-player 3.2.20 → 3.2.21

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 (48) hide show
  1. package/.github/workflows/selenium-lab-tests.yaml +23 -1
  2. package/AUTHORS +2 -1
  3. package/CHANGELOG.md +18 -0
  4. package/CONTRIBUTORS +4 -1
  5. package/dist/controls.css +1 -1
  6. package/dist/locales.js +28 -28
  7. package/dist/shaka-player.compiled.d.ts +6 -2
  8. package/dist/shaka-player.compiled.debug.d.ts +6 -2
  9. package/dist/shaka-player.compiled.debug.js +148 -146
  10. package/dist/shaka-player.compiled.debug.map +3 -3
  11. package/dist/shaka-player.compiled.js +264 -263
  12. package/dist/shaka-player.compiled.map +3 -3
  13. package/dist/shaka-player.ui.d.ts +6 -2
  14. package/dist/shaka-player.ui.debug.d.ts +6 -2
  15. package/dist/shaka-player.ui.debug.js +87 -85
  16. package/dist/shaka-player.ui.debug.map +3 -3
  17. package/dist/shaka-player.ui.js +296 -295
  18. package/dist/shaka-player.ui.map +3 -3
  19. package/docs/tutorials/fairplay.md +2 -2
  20. package/externs/shaka/net.js +1 -0
  21. package/externs/shaka/player.js +13 -7
  22. package/lib/ads/client_side_ad_manager.js +2 -2
  23. package/lib/media/media_source_engine.js +9 -4
  24. package/lib/media/streaming_engine.js +8 -3
  25. package/lib/net/http_fetch_plugin.js +10 -0
  26. package/lib/net/networking_engine.js +1 -0
  27. package/lib/player.js +17 -2
  28. package/lib/polyfill/media_capabilities.js +13 -0
  29. package/lib/text/mp4_vtt_parser.js +4 -0
  30. package/lib/text/text_engine.js +1 -0
  31. package/lib/util/manifest_parser_utils.js +1 -2
  32. package/lib/util/mime_utils.js +11 -0
  33. package/lib/util/stream_utils.js +2 -2
  34. package/maintained-branches.md +3 -4
  35. package/package.json +1 -1
  36. package/test/media/content_workarounds_unit.js +43 -0
  37. package/test/media/drm_engine_integration.js +4 -17
  38. package/test/media/streaming_engine_unit.js +6 -1
  39. package/test/net/networking_engine_unit.js +6 -1
  40. package/test/player_integration.js +39 -0
  41. package/test/player_unit.js +54 -0
  42. package/test/polyfill/media_capabilities_unit.js +0 -1
  43. package/test/test/assets/text-clip-alt.vtt +63 -0
  44. package/test/test/util/fake_drm_engine.js +3 -0
  45. package/test/test/util/simple_fakes.js +3 -0
  46. package/test/test/util/test_scheme.js +9 -14
  47. package/test/text/mp4_vtt_parser_unit.js +8 -0
  48. package/test/util/mime_utils_unit.js +10 -0
@@ -25,14 +25,14 @@ is used by the browser to generate the license request. If you don't use the
25
25
  default content ID derivation, you need to specify a custom init data transform:
26
26
 
27
27
  ```js
28
- player.configure('drm.initDataTransform', (initData, initDataType) => {
28
+ player.configure('drm.initDataTransform', (initData, initDataType, drmInfo) => {
29
29
  if (initDataType != 'skd')
30
30
  return initData;
31
31
 
32
32
  // 'initData' is a buffer containing an 'skd://' URL as a UTF-8 string.
33
33
  const skdUri = shaka.util.StringUtils.fromBytesAutoDetect(initData);
34
34
  const contentId = getMyContentId(skdUri);
35
- const cert = player.drmInfo().serverCertificate;
35
+ const cert = drmInfo.serverCertificate;
36
36
  return shaka.util.FairPlayUtils.initDataTransform(initData, contentId, cert);
37
37
  });
38
38
  ```
@@ -100,6 +100,7 @@ shaka.extern.Request;
100
100
  /**
101
101
  * @typedef {{
102
102
  * uri: string,
103
+ * originalUri: string,
103
104
  * data: BufferSource,
104
105
  * headers: !Object.<string, string>,
105
106
  * timeMs: (number|undefined),
@@ -571,9 +571,7 @@ shaka.extern.AdvancedDrmConfiguration;
571
571
  * clearKeys: !Object.<string, string>,
572
572
  * delayLicenseRequestUntilPlayed: boolean,
573
573
  * advanced: Object.<string, shaka.extern.AdvancedDrmConfiguration>,
574
- * initDataTransform:
575
- * ((function(!Uint8Array, string, ?shaka.extern.DrmInfo):!Uint8Array)|
576
- * undefined),
574
+ * initDataTransform:(shaka.extern.InitDataTransform|undefined),
577
575
  * logLicenseExchange: boolean,
578
576
  * updateExpirationTime: number,
579
577
  * preferredKeySystems: !Array.<string>
@@ -597,10 +595,7 @@ shaka.extern.AdvancedDrmConfiguration;
597
595
  * <i>Optional.</i> <br>
598
596
  * A dictionary which maps key system IDs to advanced DRM configuration for
599
597
  * those key systems.
600
- * @property
601
- * {((function(!Uint8Array, string, ?shaka.extern.DrmInfo):!Uint8Array)|
602
- * undefined)}
603
- * initDataTransform
598
+ * @property {shaka.extern.InitDataTransform|undefined} initDataTransform
604
599
  * <i>Optional.</i><br>
605
600
  * If given, this function is called with the init data from the
606
601
  * manifest/media and should return the (possibly transformed) init data to
@@ -622,6 +617,17 @@ shaka.extern.AdvancedDrmConfiguration;
622
617
  */
623
618
  shaka.extern.DrmConfiguration;
624
619
 
620
+ /**
621
+ * @typedef {function(!Uint8Array, string, ?shaka.extern.DrmInfo):!Uint8Array}
622
+ *
623
+ * @description
624
+ * A callback function to handle custom content ID signaling for FairPlay
625
+ * content.
626
+ *
627
+ * @exportDoc
628
+ */
629
+ shaka.extern.InitDataTransform;
630
+
625
631
 
626
632
  /**
627
633
  * @typedef {{
@@ -212,9 +212,9 @@ shaka.ads.ClientSideAdManager = class {
212
212
  // seen the ads actually play until requestAds() is called.
213
213
  // Note: We listen for a play event to avoid autoplay issues that might
214
214
  // crash IMA.
215
- this.video_.addEventListener('play', () => {
215
+ this.eventManager_.listenOnce(this.video_, 'play', () => {
216
216
  this.imaAdsManager_.start();
217
- }, {once: true});
217
+ });
218
218
  } catch (adError) {
219
219
  // If there was a problem with the VAST response,
220
220
  // we we won't be getting an ad. Hide ad UI if we showed it already
@@ -182,6 +182,9 @@ shaka.media.MediaSourceEngine = class {
182
182
  'audio/mp4; codecs="ec-3"',
183
183
  'audio/mp4; codecs="opus"',
184
184
  'audio/mp4; codecs="flac"',
185
+ 'audio/mp4; codecs="dtsc"', // DTS Digital Surround
186
+ 'audio/mp4; codecs="dtse"', // DTS Express
187
+ 'audio/mp4; codecs="dtsx"', // DTS:X
185
188
  // WebM types
186
189
  'video/webm; codecs="vp8"',
187
190
  'video/webm; codecs="vp9"',
@@ -515,7 +518,7 @@ shaka.media.MediaSourceEngine = class {
515
518
  // For HLS CEA-608/708 CLOSED-CAPTIONS, text data is embedded in
516
519
  // the video stream, so textEngine may not have been initialized.
517
520
  if (!this.textEngine_) {
518
- this.reinitText('text/vtt');
521
+ this.reinitText(shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE);
519
522
  }
520
523
 
521
524
  if (transmuxedData.metadata) {
@@ -542,7 +545,7 @@ shaka.media.MediaSourceEngine = class {
542
545
  contentType, () => this.append_(contentType, transmuxedSegment));
543
546
  } else if (hasClosedCaptions) {
544
547
  if (!this.textEngine_) {
545
- this.reinitText('text/vtt');
548
+ this.reinitText(shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE);
546
549
  }
547
550
  // If it is the init segment for closed captions, initialize the closed
548
551
  // caption parser.
@@ -711,8 +714,10 @@ shaka.media.MediaSourceEngine = class {
711
714
  async endOfStream(reason) {
712
715
  await this.enqueueBlockingOperation_(() => {
713
716
  // If endOfStream() has already been called on the media source,
714
- // don't call it again.
715
- if (this.ended()) {
717
+ // don't call it again. Also do not call if readyState is
718
+ // 'closed' (not attached to video element) since it is not a
719
+ // valid operation.
720
+ if (this.ended() || this.mediaSource_.readyState === 'closed') {
716
721
  return;
717
722
  }
718
723
  // Tizen won't let us pass undefined, but it will let us omit the
@@ -77,6 +77,9 @@ shaka.media.StreamingEngine = class {
77
77
  /** @private {?shaka.extern.Stream} */
78
78
  this.currentTextStream_ = null;
79
79
 
80
+ /** @private {number} */
81
+ this.textStreamSequenceId_ = 0;
82
+
80
83
  /**
81
84
  * Maps a content type, e.g., 'audio', 'video', or 'text', to a MediaState.
82
85
  *
@@ -220,6 +223,8 @@ shaka.media.StreamingEngine = class {
220
223
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
221
224
  goog.asserts.assert(!this.mediaStates_.has(ContentType.TEXT),
222
225
  'Should not call loadNewTextStream_ while streaming text!');
226
+ this.textStreamSequenceId_++;
227
+ const currentSequenceId = this.textStreamSequenceId_;
223
228
 
224
229
  try {
225
230
  // Clear MediaSource's buffered text, so that the new text stream will
@@ -241,7 +246,7 @@ shaka.media.StreamingEngine = class {
241
246
  const streamText =
242
247
  textDisplayer.isTextVisible() || this.config_.alwaysStreamText;
243
248
 
244
- if (streamText) {
249
+ if (streamText && (this.textStreamSequenceId_ == currentSequenceId)) {
245
250
  const state = this.createMediaState_(stream);
246
251
  this.mediaStates_.set(ContentType.TEXT, state);
247
252
  this.scheduleUpdate_(state, 0);
@@ -1477,10 +1482,10 @@ shaka.media.StreamingEngine = class {
1477
1482
  'waiting for another stream to recover...');
1478
1483
  }
1479
1484
 
1480
- // QuotaExceededError gets thrown if evication didn't help to make room
1485
+ // QuotaExceededError gets thrown if eviction didn't help to make room
1481
1486
  // for a segment. We want to wait for a while (4 seconds is just an
1482
1487
  // arbitrary number) before updating to give the playhead a chance to
1483
- // advance, so we don't immidiately throw again.
1488
+ // advance, so we don't immediately throw again.
1484
1489
  this.scheduleUpdate_(mediaState, 4);
1485
1490
  }
1486
1491
 
@@ -227,6 +227,16 @@ shaka.net.HttpFetchPlugin = class {
227
227
  } else {
228
228
  return false;
229
229
  }
230
+ // Old fetch implementations hasn't body and ReadableStream implementation
231
+ // See: https://github.com/shaka-project/shaka-player/issues/5088
232
+ if (window.Response) {
233
+ const response = new Response('');
234
+ if (!response.body) {
235
+ return false;
236
+ }
237
+ } else {
238
+ return false;
239
+ }
230
240
  return !!(window.fetch && window.AbortController);
231
241
  }
232
242
  };
@@ -299,6 +299,7 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
299
299
  if (!responseAndGotProgress.gotProgress &&
300
300
  this.onProgressUpdated_ &&
301
301
  !response.fromCache &&
302
+ request.method != 'HEAD' &&
302
303
  type == shaka.net.NetworkingEngine.RequestType.SEGMENT) {
303
304
  this.onProgressUpdated_(response.timeMs, response.data.byteLength);
304
305
  }
package/lib/player.js CHANGED
@@ -1148,6 +1148,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1148
1148
  */
1149
1149
  shouldUseSrcEquals_(payload) {
1150
1150
  const Platform = shaka.util.Platform;
1151
+ const MimeUtils = shaka.util.MimeUtils;
1151
1152
 
1152
1153
  // If we are using a platform that does not support media source, we will
1153
1154
  // fall back to src= to handle all playback.
@@ -1202,7 +1203,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1202
1203
  // version there.
1203
1204
 
1204
1205
  // Native HLS can be preferred on any platform via this flag:
1205
- if (this.config_.streaming.preferNativeHls) {
1206
+ if (MimeUtils.isHlsType(mimeType) &&
1207
+ this.config_.streaming.preferNativeHls) {
1206
1208
  return true;
1207
1209
  }
1208
1210
 
@@ -3898,6 +3900,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
3898
3900
  firstVariantWithLabel.language, '', 0, label);
3899
3901
 
3900
3902
  this.chooseVariantAndSwitch_();
3903
+ } else if (this.video_ && this.video_.audioTracks) {
3904
+ const audioTracks = Array.from(this.video_.audioTracks);
3905
+
3906
+ let trackMatch = null;
3907
+
3908
+ for (const audioTrack of audioTracks) {
3909
+ if (audioTrack.label == label) {
3910
+ trackMatch = audioTrack;
3911
+ }
3912
+ }
3913
+ if (trackMatch) {
3914
+ this.switchHtml5Track_(trackMatch);
3915
+ }
3901
3916
  }
3902
3917
  }
3903
3918
 
@@ -6461,7 +6476,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
6461
6476
  * @define {string} A version number taken from git at compile time.
6462
6477
  * @export
6463
6478
  */
6464
- shaka.Player.version = 'v3.2.20-uncompiled';
6479
+ shaka.Player.version = 'v3.2.21-uncompiled';
6465
6480
 
6466
6481
  // Initialize the deprecation system using the version string we just set
6467
6482
  // on the player.
@@ -101,6 +101,19 @@ shaka.polyfill.MediaCapabilities = class {
101
101
  if (shaka.util.Platform.isChromecast()) {
102
102
  isSupported =
103
103
  shaka.polyfill.MediaCapabilities.canCastDisplayType_(videoConfig);
104
+ } else if (shaka.util.Platform.isTizen()) {
105
+ let extendedType = videoConfig.contentType;
106
+ if (videoConfig.width && videoConfig.height) {
107
+ extendedType += `; width=${videoConfig.width}`;
108
+ extendedType += `; height=${videoConfig.height}`;
109
+ }
110
+ if (videoConfig.framerate) {
111
+ extendedType += `; framerate=${videoConfig.framerate}`;
112
+ }
113
+ if (videoConfig.bitrate) {
114
+ extendedType += `; bitrate=${videoConfig.bitrate}`;
115
+ }
116
+ isSupported = MediaSource.isTypeSupported(extendedType);
104
117
  } else {
105
118
  isSupported = MediaSource.isTypeSupported(videoConfig.contentType);
106
119
  }
@@ -89,6 +89,10 @@ shaka.text.Mp4VttParser = class {
89
89
  * @export
90
90
  */
91
91
  parseMedia(data, time) {
92
+ if (!data.length) {
93
+ return [];
94
+ }
95
+
92
96
  if (!this.timescale_) {
93
97
  // Missing timescale for VTT content. We should have seen the init
94
98
  // segment.
@@ -134,6 +134,7 @@ shaka.text.TextEngine = class {
134
134
  // into TextEngine and TextDisplayer.
135
135
  if (mimeType == shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE ||
136
136
  mimeType == shaka.util.MimeUtils.CEA708_CLOSED_CAPTION_MIMETYPE) {
137
+ this.parser_ = null;
137
138
  return;
138
139
  }
139
140
 
@@ -185,8 +185,7 @@ shaka.util.ManifestParserUtils.AUDIO_CODEC_REGEXPS_ = [
185
185
  /^mp4a/,
186
186
  /^[ae]c-3$/,
187
187
  /^ac-4$/,
188
- /^dts[cx]$/, // DTS Surround Sound
189
- /^[du]dts$/, // DTS Surround Sound
188
+ /^dts[cex]$/, // DTS Digital Surround (dtsc), DTS Express (dtse), DTS:X (dtsx)
190
189
  ];
191
190
 
192
191
 
@@ -194,6 +194,17 @@ shaka.util.MimeUtils = class {
194
194
  return value;
195
195
  }
196
196
 
197
+ /**
198
+ * Checks if the given MIME type is HLS MIME type.
199
+ *
200
+ * @param {string} mimeType
201
+ * @return {boolean}
202
+ */
203
+ static isHlsType(mimeType) {
204
+ return mimeType === 'application/x-mpegurl' ||
205
+ mimeType === 'application/vnd.apple.mpegurl';
206
+ }
207
+
197
208
  /**
198
209
  * Get the base and profile of a codec string. Where [0] will be the codec
199
210
  * base and [1] will be the profile.
@@ -821,7 +821,7 @@ shaka.util.StreamUtils = class {
821
821
  const video = variant.video;
822
822
  if (audio && currentVariant && currentVariant.audio) {
823
823
  if (!StreamUtils.areStreamsCompatible_(audio, currentVariant.audio)) {
824
- shaka.log.debug('Droping variant - not compatible with active audio',
824
+ shaka.log.debug('Dropping variant - not compatible with active audio',
825
825
  'active audio',
826
826
  StreamUtils.getStreamSummaryString_(currentVariant.audio),
827
827
  'variant.audio',
@@ -832,7 +832,7 @@ shaka.util.StreamUtils = class {
832
832
 
833
833
  if (video && currentVariant && currentVariant.video) {
834
834
  if (!StreamUtils.areStreamsCompatible_(video, currentVariant.video)) {
835
- shaka.log.debug('Droping variant - not compatible with active video',
835
+ shaka.log.debug('Dropping variant - not compatible with active video',
836
836
  'active video',
837
837
  StreamUtils.getStreamSummaryString_(currentVariant.video),
838
838
  'variant.video',
@@ -2,10 +2,9 @@
2
2
 
3
3
  We are currently maintaining the following branches of Shaka Player:
4
4
 
5
- - v4.1 (latest)
6
- - v4.0 (previous)
7
- - v3.3 (LTS until April 30, 2023)
8
- - v3.2 (in use by the Cast Application Framework)
5
+ - v4.3 (latest, also in use by the Cast Application Framework)
6
+ - v4.2 (previous)
7
+ - No active LTS branches at this time
9
8
 
10
9
  Other branches are no longer receiving bug fixes, and we recommend you upgrade
11
10
  to a maintained branch. For details on upgrading, please see our
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shaka-player",
3
3
  "description": "DASH/EME video player library",
4
- "version": "3.2.20",
4
+ "version": "3.2.21",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -0,0 +1,43 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ describe('ContentWorkarounds', () => {
8
+ const encryptionBoxes = {
9
+ 'encv': ['hev1', 'hvc1', 'avc1', 'avc3'],
10
+ 'enca': ['ac-3', 'ec-3', 'mp4a'],
11
+ };
12
+ for (const encryptionBox of Object.keys(encryptionBoxes)) {
13
+ for (const box of encryptionBoxes[encryptionBox]) {
14
+ it(`adds ${encryptionBox} box for ${box}`, () => {
15
+ const boxType = [];
16
+ for (const char of box) {
17
+ boxType.push(char.charCodeAt(0));
18
+ }
19
+ const unencrypted = new Uint8Array([
20
+ 0x00, 0x00, 0x00, 0x20, // size
21
+ 0x73, 0x74, 0x73, 0x64, // stsd
22
+ 0x01, // version
23
+ 0x12, 0x34, 0x56, // flags
24
+ 0x00, 0x00, 0x00, 0x01, // count
25
+ 0x00, 0x00, 0x00, 0x10, // size
26
+ ...boxType, // box type
27
+ 0x01, // version
28
+ 0x12, 0x34, 0x56, // flags
29
+ 0x00, 0x11, 0x22, 0x33, // payload
30
+ ]);
31
+
32
+ const faked =
33
+ shaka.media.ContentWorkarounds.fakeEncryption(unencrypted);
34
+ const spy = jasmine.createSpy('boxCallback');
35
+ new shaka.util.Mp4Parser()
36
+ .fullBox('stsd', shaka.util.Mp4Parser.sampleDescription)
37
+ .box(encryptionBox, /** @type {!Function} */ (spy))
38
+ .parse(faked);
39
+ expect(spy).toHaveBeenCalled();
40
+ });
41
+ }
42
+ }
43
+ });
@@ -74,19 +74,6 @@ describe('DrmEngine', () => {
74
74
  onEventSpy = jasmine.createSpy('onEvent');
75
75
 
76
76
  networkingEngine = new shaka.net.NetworkingEngine();
77
- networkingEngine.registerRequestFilter((type, request) => {
78
- if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
79
- return;
80
- }
81
-
82
- request.headers['X-AxDRM-Message'] = [
83
- 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lk',
84
- 'IjoiNjllNTQwODgtZTllMC00NTMwLThjMWEtMWViNmRjZDBkMTRlIiwibWVzc2FnZSI6e',
85
- 'yJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiNmU1YTFkMj',
86
- 'YtMjc1Ny00N2Q3LTgwNDYtZWFhNWQxZDM0YjVhIn1dfX0.yF7PflOPv9qHnu3ZWJNZ12j',
87
- 'gkqTabmwXbDWk_47tLNE',
88
- ].join('');
89
- });
90
77
 
91
78
  const playerInterface = {
92
79
  netEngine: networkingEngine,
@@ -99,22 +86,22 @@ describe('DrmEngine', () => {
99
86
  drmEngine = new shaka.media.DrmEngine(playerInterface);
100
87
  const config = shaka.util.PlayerConfiguration.createDefault().drm;
101
88
  config.servers['com.widevine.alpha'] =
102
- 'https://drm-widevine-licensing.axtest.net/AcquireLicense';
89
+ 'https://cwip-shaka-proxy.appspot.com/specific_key?blodJidXR9eARuql0dNLWg=GX8m9XLIZNIzizrl0RTqnA';
103
90
  config.servers['com.microsoft.playready'] =
104
- 'https://drm-playready-licensing.axtest.net/AcquireLicense';
91
+ 'https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(kid:6e5a1d26-2757-47d7-8046-eaa5d1d34b5a,contentkey:GX8m9XLIZNIzizrl0RTqnA==,sl:150)';
105
92
  drmEngine.configure(config);
106
93
 
107
94
  manifest = shaka.test.ManifestGenerator.generate((manifest) => {
108
95
  manifest.addVariant(0, (variant) => {
109
96
  variant.addVideo(1, (stream) => {
110
97
  stream.encrypted = true;
111
- stream.addDrmInfo('com.widevine.alpha');
112
98
  stream.addDrmInfo('com.microsoft.playready');
99
+ stream.addDrmInfo('com.widevine.alpha');
113
100
  });
114
101
  variant.addAudio(2, (stream) => {
115
102
  stream.encrypted = true;
116
- stream.addDrmInfo('com.widevine.alpha');
117
103
  stream.addDrmInfo('com.microsoft.playready');
104
+ stream.addDrmInfo('com.widevine.alpha');
118
105
  });
119
106
  });
120
107
  });
@@ -3275,7 +3275,12 @@ describe('StreamingEngine', () => {
3275
3275
  netEngine.request.and.callFake((requestType, request) => {
3276
3276
  const buffer = new ArrayBuffer(0);
3277
3277
  /** @type {shaka.extern.Response} */
3278
- const response = {uri: request.uris[0], data: buffer, headers: {}};
3278
+ const response = {
3279
+ uri: request.uris[0],
3280
+ originalUri: request.uris[0],
3281
+ data: buffer,
3282
+ headers: {},
3283
+ };
3279
3284
  return shaka.util.AbortableOperation.completed(response);
3280
3285
  });
3281
3286
 
@@ -1226,6 +1226,11 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ () => {
1226
1226
 
1227
1227
  /** @return {shaka.extern.Response} */
1228
1228
  function createResponse() {
1229
- return {uri: '', data: new ArrayBuffer(5), headers: {}};
1229
+ return {
1230
+ uri: '',
1231
+ originalUri: '',
1232
+ data: new ArrayBuffer(5),
1233
+ headers: {},
1234
+ };
1230
1235
  }
1231
1236
  }); // describe('NetworkingEngine')
@@ -336,6 +336,45 @@ describe('Player', () => {
336
336
  player.setTextTrackVisibility(true);
337
337
  expect(getTracksActive()).toEqual([false, true]);
338
338
  });
339
+
340
+ // https://github.com/shaka-project/shaka-player/issues/4821
341
+ it('loads a single text stream', async () => {
342
+ player.configure({preferredTextLanguage: 'en'});
343
+ await player.load('test:sintel_no_text_compiled');
344
+
345
+ // Add preferred language text track.
346
+ const locationUri = new goog.Uri(location.href);
347
+ const partialUri = new goog.Uri('/base/test/test/assets/text-clip.vtt');
348
+ const absoluteUri = locationUri.resolve(partialUri);
349
+ await player.addTextTrackAsync(
350
+ absoluteUri.toString(), 'en', 'subtitles', 'text/vtt');
351
+
352
+ // Add alternate language text track.
353
+ // Two text tracks with same timings but different text
354
+ // are necessary for test.
355
+ const partialUri2 =
356
+ new goog.Uri('/base/test/test/assets/text-clip-alt.vtt');
357
+ const absoluteUri2 = locationUri.resolve(partialUri2);
358
+ await player.addTextTrackAsync(
359
+ absoluteUri2.toString(), 'fr', 'subtitles', 'text/vtt');
360
+
361
+ const textTracks = player.getTextTracks();
362
+ expect(textTracks.length).toBe(2);
363
+ expect(textTracks[0].language).toBe('en');
364
+ expect(textTracks[1].language).toBe('fr');
365
+
366
+ // Enable text visibilty and immediately change language.
367
+ // Only one set of cues should be active.
368
+ // Cues should be of the selected language track.
369
+ player.setTextTrackVisibility(true);
370
+ player.selectTextLanguage('fr');
371
+ video.currentTime = 5;
372
+ video.play();
373
+ await waiter.waitForMovementOrFailOnTimeout(video, 10);
374
+
375
+ expect(video.textTracks[0].activeCues.length).toBe(1);
376
+ expect(player.getTextTracks()[1].active).toBe(true);
377
+ });
339
378
  }); // describe('setTextTrackVisibility')
340
379
 
341
380
  describe('plays', () => {
@@ -370,6 +370,60 @@ describe('Player', () => {
370
370
  expect(streamingEngine.unloadTextStream).not.toHaveBeenCalled();
371
371
  });
372
372
  });
373
+
374
+ describe('when config.streaming.preferNativeHls is set to true', () => {
375
+ beforeEach(() => {
376
+ shaka.media.ManifestParser.registerParserByMime(
377
+ 'application/x-mpegurl',
378
+ () => new shaka.test.FakeManifestParser(manifest));
379
+ });
380
+
381
+ afterEach(() => {
382
+ shaka.media.ManifestParser.unregisterParserByMime(
383
+ 'application/x-mpegurl');
384
+ video.canPlayType.calls.reset();
385
+ });
386
+
387
+ it('only applies to HLS streams', async () => {
388
+ video.canPlayType.and.returnValue('maybe');
389
+ spyOn(shaka.util.Platform, 'anyMediaElement').and.returnValue(video);
390
+ spyOn(shaka.util.Platform, 'supportsMediaSource').and.returnValue(true);
391
+ spyOn(shaka.util.Platform, 'isApple').and.returnValue(false);
392
+ // Make sure player.load() resolves for src=
393
+ spyOn(shaka.util.MediaReadyState, 'waitForReadyState').and.callFake(
394
+ (mediaElement, readyState, eventManager, callback) => {
395
+ callback();
396
+ });
397
+
398
+ player.configure({
399
+ streaming: {
400
+ preferNativeHls: true,
401
+ useNativeHlsOnSafari: false,
402
+ },
403
+ });
404
+
405
+ await player.load(fakeManifestUri, undefined, 'application/x-mpegurl');
406
+
407
+ expect(player.getLoadMode()).toBe(shaka.Player.LoadMode.SRC_EQUALS);
408
+ });
409
+
410
+ it('does not apply to non-HLS streams', async () => {
411
+ video.canPlayType.and.returnValue('maybe');
412
+ spyOn(shaka.util.Platform, 'supportsMediaSource').and.returnValue(true);
413
+ spyOn(shaka.util.Platform, 'isApple').and.returnValue(false);
414
+
415
+ player.configure({
416
+ streaming: {
417
+ preferNativeHls: true,
418
+ useNativeHlsOnSafari: false,
419
+ },
420
+ });
421
+
422
+ await player.load(fakeManifestUri, 0, fakeMimeType);
423
+
424
+ expect(player.getLoadMode()).toBe(shaka.Player.LoadMode.MEDIA_SOURCE);
425
+ });
426
+ });
373
427
  }); // describe('load/unload')
374
428
 
375
429
  describe('getConfiguration', () => {
@@ -67,7 +67,6 @@ describe('MediaCapabilities', () => {
67
67
  width: 512,
68
68
  },
69
69
  };
70
- shaka.polyfill.MediaCapabilities.memoizedMediaKeySystemAccessRequests_ = {};
71
70
 
72
71
  mockCanDisplayType = jasmine.createSpy('canDisplayType');
73
72
  mockCanDisplayType.and.returnValue(false);
@@ -0,0 +1,63 @@
1
+ WEBVTT
2
+
3
+ 00:04.000 --> 00:07.300
4
+ Journal de bord du capitaine.
5
+ Date stellaire 41636.9.
6
+
7
+ 00:07.500 --> 00:11.800
8
+ Comme nous le craignions, l'épave
9
+ du cargo Odin de la Fédération,
10
+
11
+ 00:12.100 --> 00:16.400
12
+ percuté par un astéroïde,
13
+ ne révèle aucun signe de vie.
14
+
15
+ 00:16.700 --> 00:19.000
16
+ Mais trois nacelles
17
+ de sauvetage manquaient,
18
+
19
+ 00:19.300 --> 00:21.900
20
+ laissant supposer
21
+ qu'il y aurait des survivants.
22
+
23
+ 00:22.700 --> 00:27.700
24
+ - Mise sur orbite Angel One, paré.
25
+ - Quel genre d'endroit, Data ?
26
+
27
+ 00:28.200 --> 00:31.600
28
+ Planète de Classe-M.
29
+ Faune et flore à base de carbone.
30
+
31
+ 00:31.900 --> 00:34.300
32
+ Population éparse
33
+ et forme de vie intelligente.
34
+
35
+ 00:34.600 --> 00:38.400
36
+ Développement technique équivalent
37
+ au milieu du 20ème siècle terrien.
38
+
39
+ 00:38.800 --> 00:41.000
40
+ C'est presque un retour aux sources.
41
+
42
+ 00:41.300 --> 00:43.600
43
+ Si jamais des survivants
44
+ ont pu aller si loin,
45
+
46
+ 00:43.800 --> 00:49.000
47
+ c'était la planète la plus proche.
48
+ La distance qui nous a pris 2 jours
49
+
50
+ 00:49.500 --> 00:52.400
51
+ aurait pris 5 mois aux nacelles
52
+ de sauvetage du Odin.
53
+
54
+ 00:52.600 --> 00:54.700
55
+ Cinq mois, six jours, onze heures,
56
+ deux min...
57
+
58
+ 00:54.900 --> 00:58.400
59
+ - Merci, Data.
60
+ - ..et 57 secondes.
61
+
62
+ 00:58.600 --> 01:01.300
63
+ Signal audio provenant d'Angel One.
@@ -74,6 +74,9 @@ shaka.test.FakeDrmEngine = class {
74
74
  /** @type {!jasmine.Spy} */
75
75
  this.supportsVariant = jasmine.createSpy('supportsVariant');
76
76
  this.supportsVariant.and.returnValue(true);
77
+
78
+ /** @type {!jasmine.Spy} */
79
+ this.setSrcEquals = jasmine.createSpy('setSrcEquals');
77
80
  }
78
81
 
79
82
  /**