shaka-player 3.3.17 → 3.3.19

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 (82) hide show
  1. package/.github/workflows/build-and-test.yaml +4 -4
  2. package/.github/workflows/demo-version-index.yaml +6 -0
  3. package/.github/workflows/selenium-lab-tests.yaml +78 -17
  4. package/.github/workflows/update-screenshots.yaml +142 -0
  5. package/AUTHORS +2 -1
  6. package/CHANGELOG.md +44 -0
  7. package/CONTRIBUTORS +4 -1
  8. package/demo/common/asset.js +15 -0
  9. package/demo/common/assets.js +4 -2
  10. package/demo/common/message_ids.js +1 -0
  11. package/demo/custom.js +19 -0
  12. package/demo/locales/en.json +1 -0
  13. package/demo/locales/source.json +4 -0
  14. package/demo/main.js +14 -0
  15. package/dist/controls.css +1 -1
  16. package/dist/demo.compiled.debug.js +146 -144
  17. package/dist/demo.compiled.debug.map +3 -3
  18. package/dist/demo.compiled.js +146 -144
  19. package/dist/demo.compiled.map +3 -3
  20. package/dist/deps.js +1 -1
  21. package/dist/locales.js +31 -31
  22. package/dist/receiver.compiled.debug.js +15 -15
  23. package/dist/receiver.compiled.debug.map +2 -2
  24. package/dist/receiver.compiled.js +15 -15
  25. package/dist/receiver.compiled.map +2 -2
  26. package/dist/shaka-player.compiled.d.ts +13 -2
  27. package/dist/shaka-player.compiled.debug.d.ts +13 -2
  28. package/dist/shaka-player.compiled.debug.js +160 -158
  29. package/dist/shaka-player.compiled.debug.map +3 -3
  30. package/dist/shaka-player.compiled.js +338 -335
  31. package/dist/shaka-player.compiled.map +3 -3
  32. package/dist/shaka-player.ui.d.ts +13 -2
  33. package/dist/shaka-player.ui.debug.d.ts +13 -2
  34. package/dist/shaka-player.ui.debug.js +224 -222
  35. package/dist/shaka-player.ui.debug.map +3 -3
  36. package/dist/shaka-player.ui.js +501 -498
  37. package/dist/shaka-player.ui.map +3 -3
  38. package/docs/tutorials/errors.md +94 -0
  39. package/docs/tutorials/fairplay.md +2 -2
  40. package/docs/tutorials/index.json +2 -0
  41. package/docs/tutorials/widevine-service-certs.md +45 -0
  42. package/externs/ima.js +9 -0
  43. package/externs/shaka/net.js +1 -0
  44. package/externs/shaka/player.js +13 -7
  45. package/lib/ads/client_side_ad_manager.js +11 -5
  46. package/lib/dash/dash_parser.js +49 -48
  47. package/lib/hls/hls_parser.js +2 -0
  48. package/lib/media/media_source_engine.js +9 -4
  49. package/lib/media/streaming_engine.js +8 -3
  50. package/lib/media/transmuxer.js +13 -7
  51. package/lib/media/video_wrapper.js +3 -3
  52. package/lib/net/http_fetch_plugin.js +79 -57
  53. package/lib/net/networking_engine.js +1 -0
  54. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  55. package/lib/player.js +19 -2
  56. package/lib/polyfill/media_capabilities.js +15 -8
  57. package/lib/polyfill/mediasource.js +7 -2
  58. package/lib/text/mp4_vtt_parser.js +4 -0
  59. package/lib/text/text_engine.js +1 -0
  60. package/lib/text/ui_text_displayer.js +1 -0
  61. package/lib/text/vtt_text_parser.js +4 -5
  62. package/lib/util/manifest_parser_utils.js +1 -2
  63. package/lib/util/mime_utils.js +12 -1
  64. package/lib/util/periods.js +5 -5
  65. package/lib/util/stream_utils.js +28 -16
  66. package/maintained-branches.md +3 -4
  67. package/package.json +1 -1
  68. package/test/media/content_workarounds_unit.js +43 -0
  69. package/test/media/drm_engine_integration.js +4 -17
  70. package/test/media/streaming_engine_unit.js +6 -1
  71. package/test/net/networking_engine_unit.js +6 -1
  72. package/test/player_integration.js +39 -0
  73. package/test/player_unit.js +54 -0
  74. package/test/polyfill/media_capabilities_unit.js +20 -23
  75. package/test/test/assets/text-clip-alt.vtt +63 -0
  76. package/test/test/util/fake_drm_engine.js +3 -0
  77. package/test/test/util/simple_fakes.js +3 -0
  78. package/test/test/util/test_scheme.js +9 -14
  79. package/test/text/mp4_vtt_parser_unit.js +8 -0
  80. package/test/text/vtt_text_parser_unit.js +26 -2
  81. package/test/text/web_vtt_layout_integration.js +0 -3
  82. package/test/util/mime_utils_unit.js +10 -0
@@ -120,65 +120,77 @@ shaka.net.HttpFetchPlugin = class {
120
120
  // not the body yet.
121
121
  headersReceived(shaka.net.HttpFetchPlugin.headersToGenericObject_(
122
122
  response.headers));
123
- // Getting the reader in this way allows us to observe the process of
124
- // downloading the body, instead of just waiting for an opaque promise to
125
- // resolve.
126
- // We first clone the response because calling getReader locks the body
127
- // stream; if we didn't clone it here, we would be unable to get the
128
- // response's arrayBuffer later.
129
- const reader = response.clone().body.getReader();
130
-
131
- const contentLengthRaw = response.headers.get('Content-Length');
132
- const contentLength =
133
- contentLengthRaw ? parseInt(contentLengthRaw, 10) : 0;
134
-
135
- const start = (controller) => {
136
- const push = async () => {
137
- let readObj;
138
- try {
139
- readObj = await reader.read();
140
- } catch (e) {
141
- // If we abort the request, we'll get an error here. Just ignore it
142
- // since real errors will be reported when we read the buffer below.
143
- shaka.log.v1('error reading from stream', e.message);
144
- return;
145
- }
146
-
147
- if (!readObj.done) {
148
- loaded += readObj.value.byteLength;
149
- if (streamDataCallback) {
150
- await streamDataCallback(readObj.value);
123
+
124
+ // In new versions of Chromium, HEAD requests now have a response body
125
+ // that is null.
126
+ // So just don't try to download the body at all, if it's a HEAD request,
127
+ // to avoid null reference errors.
128
+ // See: https://crbug.com/1297060
129
+ if (init.method != 'HEAD') {
130
+ goog.asserts.assert(response.body,
131
+ 'non-HEAD responses should have a body');
132
+
133
+ // Getting the reader in this way allows us to observe the process of
134
+ // downloading the body, instead of just waiting for an opaque promise
135
+ // to resolve.
136
+ // We first clone the response because calling getReader locks the body
137
+ // stream; if we didn't clone it here, we would be unable to get the
138
+ // response's arrayBuffer later.
139
+ const reader = response.clone().body.getReader();
140
+
141
+ const contentLengthRaw = response.headers.get('Content-Length');
142
+ const contentLength =
143
+ contentLengthRaw ? parseInt(contentLengthRaw, 10) : 0;
144
+
145
+ const start = (controller) => {
146
+ const push = async () => {
147
+ let readObj;
148
+ try {
149
+ readObj = await reader.read();
150
+ } catch (e) {
151
+ // If we abort the request, we'll get an error here. Just ignore
152
+ // it since real errors will be reported when we read the buffer
153
+ // below.
154
+ shaka.log.v1('error reading from stream', e.message);
155
+ return;
156
+ }
157
+
158
+ if (!readObj.done) {
159
+ loaded += readObj.value.byteLength;
160
+ if (streamDataCallback) {
161
+ await streamDataCallback(readObj.value);
162
+ }
163
+ }
164
+
165
+ const currentTime = Date.now();
166
+ // If the time between last time and this time we got progress event
167
+ // is long enough, or if a whole segment is downloaded, call
168
+ // progressUpdated().
169
+ if (currentTime - lastTime > 100 || readObj.done) {
170
+ progressUpdated(currentTime - lastTime, loaded - lastLoaded,
171
+ contentLength - loaded);
172
+ lastLoaded = loaded;
173
+ lastTime = currentTime;
174
+ }
175
+
176
+ if (readObj.done) {
177
+ goog.asserts.assert(!readObj.value,
178
+ 'readObj should be unset when "done" is true.');
179
+ controller.close();
180
+ } else {
181
+ controller.enqueue(readObj.value);
182
+ push();
151
183
  }
152
- }
153
-
154
- const currentTime = Date.now();
155
- // If the time between last time and this time we got progress event
156
- // is long enough, or if a whole segment is downloaded, call
157
- // progressUpdated().
158
- if (currentTime - lastTime > 100 || readObj.done) {
159
- progressUpdated(currentTime - lastTime, loaded - lastLoaded,
160
- contentLength - loaded);
161
- lastLoaded = loaded;
162
- lastTime = currentTime;
163
- }
164
-
165
- if (readObj.done) {
166
- goog.asserts.assert(!readObj.value,
167
- 'readObj should be unset when "done" is true.');
168
- controller.close();
169
- } else {
170
- controller.enqueue(readObj.value);
171
- push();
172
- }
184
+ };
185
+ push();
173
186
  };
174
- push();
175
- };
176
- // Create a ReadableStream to use the reader. We don't need to use the
177
- // actual stream for anything, though, as we are using the response's
178
- // arrayBuffer method to get the body, so we don't store the
179
- // ReadableStream.
180
- new ReadableStream({start}); // eslint-disable-line no-new
181
- arrayBuffer = await response.arrayBuffer();
187
+ // Create a ReadableStream to use the reader. We don't need to use the
188
+ // actual stream for anything, though, as we are using the response's
189
+ // arrayBuffer method to get the body, so we don't store the
190
+ // ReadableStream.
191
+ new ReadableStream({start}); // eslint-disable-line no-new
192
+ arrayBuffer = await response.arrayBuffer();
193
+ }
182
194
  } catch (error) {
183
195
  if (abortStatus.canceled) {
184
196
  throw new shaka.util.Error(
@@ -243,6 +255,16 @@ shaka.net.HttpFetchPlugin = class {
243
255
  } else {
244
256
  return false;
245
257
  }
258
+ // Old fetch implementations hasn't body and ReadableStream implementation
259
+ // See: https://github.com/shaka-project/shaka-player/issues/5088
260
+ if (window.Response) {
261
+ const response = new Response('');
262
+ if (!response.body) {
263
+ return false;
264
+ }
265
+ } else {
266
+ return false;
267
+ }
246
268
  return !!(window.fetch && window.AbortController);
247
269
  }
248
270
  };
@@ -309,6 +309,7 @@ shaka.net.NetworkingEngine = class extends shaka.util.FakeEventTarget {
309
309
  if (!responseAndGotProgress.gotProgress &&
310
310
  this.onProgressUpdated_ &&
311
311
  !response.fromCache &&
312
+ request.method != 'HEAD' &&
312
313
  type == shaka.net.NetworkingEngine.RequestType.SEGMENT) {
313
314
  this.onProgressUpdated_(response.timeMs, response.data.byteLength);
314
315
  }
@@ -67,7 +67,7 @@ shaka.offline.indexeddb.StorageMechanism = class {
67
67
  shaka.util.Error.Category.STORAGE,
68
68
  shaka.util.Error.Code.INDEXED_DB_INIT_TIMED_OUT));
69
69
  });
70
- timeOutTimer.tickAfter(2);
70
+ timeOutTimer.tickAfter(5);
71
71
 
72
72
  const open = window.indexedDB.open(name, version);
73
73
  open.onsuccess = (event) => {
package/lib/player.js CHANGED
@@ -1225,6 +1225,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1225
1225
  */
1226
1226
  shouldUseSrcEquals_(payload) {
1227
1227
  const Platform = shaka.util.Platform;
1228
+ const MimeUtils = shaka.util.MimeUtils;
1228
1229
 
1229
1230
  // If we are using a platform that does not support media source, we will
1230
1231
  // fall back to src= to handle all playback.
@@ -1279,7 +1280,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
1279
1280
  // version there.
1280
1281
 
1281
1282
  // Native HLS can be preferred on any platform via this flag:
1282
- if (this.config_.streaming.preferNativeHls) {
1283
+ if (MimeUtils.isHlsType(mimeType) &&
1284
+ this.config_.streaming.preferNativeHls) {
1283
1285
  return true;
1284
1286
  }
1285
1287
 
@@ -2408,6 +2410,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2408
2410
  // goes wrong.
2409
2411
  new shaka.util.Timer(resolve).tickAfter(1);
2410
2412
  });
2413
+ } else if (textTracks.length > 0) {
2414
+ this.isTextVisible_ = true;
2411
2415
  }
2412
2416
 
2413
2417
  // If we have moved on to another piece of content while waiting for
@@ -4060,6 +4064,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4060
4064
  firstVariantWithLabel.language, '', 0, label);
4061
4065
 
4062
4066
  this.chooseVariantAndSwitch_();
4067
+ } else if (this.video_ && this.video_.audioTracks) {
4068
+ const audioTracks = Array.from(this.video_.audioTracks);
4069
+
4070
+ let trackMatch = null;
4071
+
4072
+ for (const audioTrack of audioTracks) {
4073
+ if (audioTrack.label == label) {
4074
+ trackMatch = audioTrack;
4075
+ }
4076
+ }
4077
+ if (trackMatch) {
4078
+ this.switchHtml5Track_(trackMatch);
4079
+ }
4063
4080
  }
4064
4081
  }
4065
4082
 
@@ -6663,7 +6680,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
6663
6680
  * @define {string} A version number taken from git at compile time.
6664
6681
  * @export
6665
6682
  */
6666
- shaka.Player.version = 'v3.3.17-uncompiled';
6683
+ shaka.Player.version = 'v3.3.19-uncompiled';
6667
6684
 
6668
6685
  // Initialize the deprecation system using the version string we just set
6669
6686
  // on the player.
@@ -8,7 +8,6 @@ goog.provide('shaka.polyfill.MediaCapabilities');
8
8
 
9
9
  goog.require('shaka.log');
10
10
  goog.require('shaka.polyfill');
11
- goog.require('shaka.util.Error');
12
11
  goog.require('shaka.util.Platform');
13
12
 
14
13
 
@@ -102,6 +101,19 @@ shaka.polyfill.MediaCapabilities = class {
102
101
  if (shaka.util.Platform.isChromecast()) {
103
102
  isSupported =
104
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);
105
117
  } else {
106
118
  isSupported = MediaSource.isTypeSupported(videoConfig.contentType);
107
119
  }
@@ -212,13 +224,8 @@ shaka.polyfill.MediaCapabilities = class {
212
224
  * @private
213
225
  */
214
226
  static canCastDisplayType_(videoConfig) {
215
- if (!(window.cast)) {
216
- shaka.log.error('Expected cast namespace to be available!');
217
- throw new shaka.util.Error(
218
- shaka.util.Error.Severity.CRITICAL,
219
- shaka.util.Error.Category.CAST,
220
- shaka.util.Error.Code.CAST_API_UNAVAILABLE);
221
- } else if (!(cast.__platform__ && cast.__platform__.canDisplayType)) {
227
+ if (!(window.cast &&
228
+ cast.__platform__ && cast.__platform__.canDisplayType)) {
222
229
  shaka.log.warning('Expected cast APIs to be available! Falling back to ' +
223
230
  'MediaSource.isTypeSupported() for type support.');
224
231
  return MediaSource.isTypeSupported(videoConfig.contentType);
@@ -58,14 +58,19 @@ shaka.polyfill.MediaSource = class {
58
58
  // Offsetting the end of the removal range seems to help.
59
59
  // Bug filed: https://bugs.webkit.org/show_bug.cgi?id=177884
60
60
  shaka.polyfill.MediaSource.patchRemovalRange_();
61
- } else {
62
- shaka.log.info('Patching Safari 13 MSE bugs.');
61
+ } else if (safariVersion <= 15) {
62
+ shaka.log.info('Patching Safari 13 & 14 & 15 MSE bugs.');
63
63
  // Safari 13 does not correctly implement abort() on SourceBuffer.
64
64
  // Calling abort() before appending a segment causes that segment to be
65
65
  // incomplete in the buffer.
66
66
  // Bug filed: https://bugs.webkit.org/show_bug.cgi?id=165342
67
67
  shaka.polyfill.MediaSource.stubAbort_();
68
68
  }
69
+ } else if (shaka.util.Platform.isEdge()) {
70
+ shaka.log.info('Rejecting TS container.');
71
+ // TS content is broken on Edge in general.
72
+ // See https://github.com/shaka-project/shaka-player/issues/4955
73
+ shaka.polyfill.MediaSource.rejectTsContent_();
69
74
  } else if (shaka.util.Platform.isTizen2() ||
70
75
  shaka.util.Platform.isTizen3() ||
71
76
  shaka.util.Platform.isTizen4()) {
@@ -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
 
@@ -480,6 +480,7 @@ shaka.text.UITextDisplayer = class {
480
480
  wrapper = shaka.util.Dom.createHTMLElement('span');
481
481
  wrapper.classList.add('shaka-text-wrapper');
482
482
  wrapper.style.backgroundColor = cue.backgroundColor;
483
+ wrapper.style.lineHeight = 'normal';
483
484
  cueElement.appendChild(wrapper);
484
485
  }
485
486
 
@@ -369,8 +369,7 @@ shaka.text.VttTextParser = class {
369
369
  end += timeOffset;
370
370
 
371
371
  // Get the payload.
372
- const payload = VttTextParser.htmlUnescape_(
373
- text.slice(1).join('\n').trim());
372
+ const payload = text.slice(1).join('\n').trim();
374
373
 
375
374
  let cue = null;
376
375
  if (styles.has('global')) {
@@ -427,7 +426,7 @@ shaka.text.VttTextParser = class {
427
426
  const childNode = childNodes[0];
428
427
  if (childNode.nodeType == Node.TEXT_NODE ||
429
428
  childNode.nodeType == Node.CDATA_SECTION_NODE) {
430
- rootCue.payload = payload;
429
+ rootCue.payload = VttTextParser.htmlUnescape_(payload);
431
430
  return;
432
431
  }
433
432
  }
@@ -438,7 +437,7 @@ shaka.text.VttTextParser = class {
438
437
  rootCue.nestedCues = cues;
439
438
  } else {
440
439
  shaka.log.warning('The cue\'s markup could not be parsed: ', payload);
441
- rootCue.payload = payload;
440
+ rootCue.payload = VttTextParser.htmlUnescape_(payload);
442
441
  }
443
442
  }
444
443
 
@@ -682,7 +681,7 @@ shaka.text.VttTextParser = class {
682
681
  }
683
682
  if (text.length > 0) {
684
683
  const textCue = nestedCue.clone();
685
- textCue.payload = text;
684
+ textCue.payload = VttTextParser.htmlUnescape_(text);
686
685
  cues.push(textCue);
687
686
  }
688
687
  isFirst = false;
@@ -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
 
@@ -50,7 +50,7 @@ shaka.util.MimeUtils = class {
50
50
  return shaka.media.Transmuxer.convertTsCodecs(
51
51
  contentType, fullMimeType);
52
52
  }
53
- } else if (contentType == ContentType.AUDIO) {
53
+ } else if (mimeType != 'video/mp2t' && contentType == ContentType.AUDIO) {
54
54
  // video/mp2t is the correct mime type for TS audio, so only replace the
55
55
  // word "video" with "audio" for non-TS audio content.
56
56
  return fullMimeType.replace('video', 'audio');
@@ -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.
@@ -671,11 +671,11 @@ shaka.util.PeriodCombiner = class {
671
671
  // Also checks if the segmentIndex is still valid after the async
672
672
  // operations, to make sure we stop if the active stream has changed.
673
673
  if (outputStream.segmentIndex instanceof shaka.media.MetaSegmentIndex) {
674
- for (let i = 0; i < streams.length; i++) {
674
+ for (let i = firstNewPeriodIndex; i < streams.length; i++) {
675
675
  const match = streams[i];
676
- if (match.segmentIndex && i >= firstNewPeriodIndex) {
677
- goog.asserts.assert(match.segmentIndex,
678
- 'stream should have a segmentIndex.');
676
+ goog.asserts.assert(match.segmentIndex,
677
+ 'stream should have a segmentIndex.');
678
+ if (match.segmentIndex) {
679
679
  outputStream.segmentIndex.appendSegmentIndex(match.segmentIndex);
680
680
  }
681
681
  }
@@ -728,7 +728,7 @@ shaka.util.PeriodCombiner = class {
728
728
  // in advance. concat() will add them to the output's MetaSegmentIndex.
729
729
  }
730
730
 
731
- if (!outputStream.matchedStreams) {
731
+ if (!outputStream.matchedStreams || !outputStream.matchedStreams.length) {
732
732
  // This is not a stream we can build output from, but it may become part
733
733
  // of another output based on another period's stream.
734
734
  return null;
@@ -703,26 +703,38 @@ shaka.util.StreamUtils = class {
703
703
  }
704
704
 
705
705
  if (audio) {
706
- if (!keySystemConfig.audio) {
706
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
707
+ if (info.audioRobustness != '') {
708
+ if (!keySystemConfig.audio) {
709
+ // KeySystemTrackConfiguration
710
+ keySystemConfig.audio = {
711
+ robustness: info.audioRobustness,
712
+ };
713
+ } else {
714
+ keySystemConfig.audio.robustness =
715
+ keySystemConfig.audio.robustness || info.audioRobustness;
716
+ }
717
+ } else if (!keySystemConfig.audio) {
707
718
  // KeySystemTrackConfiguration
708
- keySystemConfig.audio = {
709
- robustness: info.audioRobustness,
710
- };
711
- } else {
712
- keySystemConfig.audio.robustness =
713
- keySystemConfig.audio.robustness || info.audioRobustness;
719
+ keySystemConfig.audio = {};
714
720
  }
715
721
  }
716
722
 
717
723
  if (video) {
718
- if (!keySystemConfig.video) {
724
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
725
+ if (info.videoRobustness != '') {
726
+ if (!keySystemConfig.video) {
727
+ // KeySystemTrackConfiguration
728
+ keySystemConfig.video = {
729
+ robustness: info.videoRobustness,
730
+ };
731
+ } else {
732
+ keySystemConfig.video.robustness =
733
+ keySystemConfig.video.robustness || info.videoRobustness;
734
+ }
735
+ } else if (!keySystemConfig.video) {
719
736
  // KeySystemTrackConfiguration
720
- keySystemConfig.video = {
721
- robustness: info.videoRobustness,
722
- };
723
- } else {
724
- keySystemConfig.video.robustness =
725
- keySystemConfig.video.robustness || info.videoRobustness;
737
+ keySystemConfig.video = {};
726
738
  }
727
739
  }
728
740
  }
@@ -809,7 +821,7 @@ shaka.util.StreamUtils = class {
809
821
  const video = variant.video;
810
822
  if (audio && currentVariant && currentVariant.audio) {
811
823
  if (!StreamUtils.areStreamsCompatible_(audio, currentVariant.audio)) {
812
- shaka.log.debug('Droping variant - not compatible with active audio',
824
+ shaka.log.debug('Dropping variant - not compatible with active audio',
813
825
  'active audio',
814
826
  StreamUtils.getStreamSummaryString_(currentVariant.audio),
815
827
  'variant.audio',
@@ -820,7 +832,7 @@ shaka.util.StreamUtils = class {
820
832
 
821
833
  if (video && currentVariant && currentVariant.video) {
822
834
  if (!StreamUtils.areStreamsCompatible_(video, currentVariant.video)) {
823
- shaka.log.debug('Droping variant - not compatible with active video',
835
+ shaka.log.debug('Dropping variant - not compatible with active video',
824
836
  'active video',
825
837
  StreamUtils.getStreamSummaryString_(currentVariant.video),
826
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.2 (latest)
6
- - v4.1 (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.3.17",
4
+ "version": "3.3.19",
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
  });
@@ -3277,7 +3277,12 @@ describe('StreamingEngine', () => {
3277
3277
  netEngine.request.and.callFake((requestType, request) => {
3278
3278
  const buffer = new ArrayBuffer(0);
3279
3279
  /** @type {shaka.extern.Response} */
3280
- const response = {uri: request.uris[0], data: buffer, headers: {}};
3280
+ const response = {
3281
+ uri: request.uris[0],
3282
+ originalUri: request.uris[0],
3283
+ data: buffer,
3284
+ headers: {},
3285
+ };
3281
3286
  return shaka.util.AbortableOperation.completed(response);
3282
3287
  });
3283
3288
 
@@ -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')