shaka-player 3.2.6 → 3.2.9

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 +0 -1
  2. package/.github/workflows/release-please.yaml +4 -3
  3. package/.github/workflows/selenium-lab-tests.yaml +0 -1
  4. package/AUTHORS +1 -1
  5. package/CHANGELOG.md +39 -0
  6. package/CONTRIBUTORS +2 -1
  7. package/README.md +4 -4
  8. package/build/README.md +2 -2
  9. package/build/generateTsDefs.py +0 -2
  10. package/build/test.py +8 -2
  11. package/demo/common/assets.js +1 -1
  12. package/demo/demo.less +0 -1
  13. package/demo/main.js +3 -3
  14. package/dist/controls.css +2 -2
  15. package/dist/controls.css.map +1 -1
  16. package/dist/demo.compiled.debug.js +3 -3
  17. package/dist/demo.compiled.debug.map +2 -2
  18. package/dist/demo.compiled.js +3 -3
  19. package/dist/demo.compiled.map +2 -2
  20. package/dist/demo.css +1 -1
  21. package/dist/demo.css.map +1 -1
  22. package/dist/deps.js +1 -1
  23. package/dist/locales.js +28 -28
  24. package/dist/receiver.compiled.debug.js +1 -1
  25. package/dist/receiver.compiled.debug.map +1 -1
  26. package/dist/receiver.compiled.js +1 -1
  27. package/dist/receiver.compiled.map +1 -1
  28. package/dist/shaka-player.compiled.d.ts +1 -2
  29. package/dist/shaka-player.compiled.debug.d.ts +1 -2
  30. package/dist/shaka-player.compiled.debug.externs.js +1 -0
  31. package/dist/shaka-player.compiled.debug.js +213 -207
  32. package/dist/shaka-player.compiled.debug.map +4 -4
  33. package/dist/shaka-player.compiled.externs.js +1 -0
  34. package/dist/shaka-player.compiled.js +775 -769
  35. package/dist/shaka-player.compiled.map +4 -4
  36. package/dist/shaka-player.ui.d.ts +1 -2
  37. package/dist/shaka-player.ui.debug.d.ts +1 -2
  38. package/dist/shaka-player.ui.debug.externs.js +1 -0
  39. package/dist/shaka-player.ui.debug.js +241 -236
  40. package/dist/shaka-player.ui.debug.map +4 -4
  41. package/dist/shaka-player.ui.externs.js +1 -0
  42. package/dist/shaka-player.ui.js +898 -891
  43. package/dist/shaka-player.ui.map +4 -4
  44. package/karma.conf.js +4 -0
  45. package/lib/abr/simple_abr_manager.js +2 -1
  46. package/lib/dash/dash_parser.js +2 -3
  47. package/lib/hls/hls_parser.js +45 -18
  48. package/lib/media/drm_engine.js +3 -0
  49. package/lib/media/media_source_engine.js +7 -1
  50. package/lib/offline/indexeddb/storage_mechanism.js +4 -2
  51. package/lib/player.js +165 -107
  52. package/lib/util/config_utils.js +25 -0
  53. package/lib/util/error.js +7 -0
  54. package/lib/util/manifest_parser_utils.js +1 -1
  55. package/lib/util/mime_utils.js +62 -6
  56. package/lib/util/periods.js +5 -4
  57. package/lib/util/player_configuration.js +9 -14
  58. package/lib/util/stream_utils.js +5 -2
  59. package/package.json +6 -3
  60. package/test/cast/cast_utils_unit.js +1 -0
  61. package/test/dash/dash_parser_manifest_unit.js +0 -24
  62. package/test/hls/hls_live_unit.js +86 -7
  63. package/test/hls/manifest_text_parser_unit.js +19 -0
  64. package/test/media/media_source_engine_integration.js +1 -0
  65. package/test/media/media_source_engine_unit.js +4 -4
  66. package/test/media/streaming_engine_integration.js +2 -0
  67. package/test/offline/indexeddb_storage_unit.js +1 -1
  68. package/test/offline/storage_compatibility_unit.js +1 -1
  69. package/test/player_external.js +7 -1
  70. package/test/player_integration.js +6 -10
  71. package/test/player_src_equals_integration.js +81 -83
  72. package/test/player_unit.js +98 -1
  73. package/test/test/boot.js +9 -0
  74. package/test/test/externs/filters.js +4 -0
  75. package/test/test/util/simple_fakes.js +31 -2
  76. package/test/util/mime_utils_unit.js +54 -0
  77. package/test/util/periods_unit.js +79 -0
  78. package/ui/less/containers.less +1 -1
  79. package/ui/less/general.less +1 -1
  80. package/ui/less/range_elements.less +1 -0
  81. package/.github/pull_request_template.md +0 -38
  82. package/docs/tutorials/gsoc-ideas-list.md +0 -3
package/karma.conf.js CHANGED
@@ -363,6 +363,8 @@ module.exports = (config) => {
363
363
  // If testing custom assets, we don't serve other unit or integration tests.
364
364
  // External asset tests are the basis for custom asset testing, so this file
365
365
  // is automatically included.
366
+ clientArgs.testFiles.push('demo/common/asset.js');
367
+ clientArgs.testFiles.push('demo/common/assets.js');
366
368
  clientArgs.testFiles.push('test/player_external.js');
367
369
  } else {
368
370
  // In a normal test run, we serve unit tests.
@@ -374,6 +376,8 @@ module.exports = (config) => {
374
376
  }
375
377
  if (settings.external) {
376
378
  // If --external is present, we serve external asset tests.
379
+ clientArgs.testFiles.push('demo/common/asset.js');
380
+ clientArgs.testFiles.push('demo/common/assets.js');
377
381
  clientArgs.testFiles.push('test/**/*_external.js');
378
382
  }
379
383
  }
@@ -216,8 +216,9 @@ shaka.abr.SimpleAbrManager = class {
216
216
  * @export
217
217
  */
218
218
  getBandwidthEstimate() {
219
+ const defaultBandwidthEstimate = this.getDefaultBandwidth_();
219
220
  return this.bandwidthEstimator_.getBandwidthEstimate(
220
- this.config_.defaultBandwidthEstimate);
221
+ defaultBandwidthEstimate);
221
222
  }
222
223
 
223
224
 
@@ -755,8 +755,8 @@ shaka.dash.DashParser = class {
755
755
  // currently support that. Just choose one.
756
756
  // TODO: https://github.com/shaka-project/shaka-player/issues/1528
757
757
  stream.trickModeVideo = trickModeSet.streams.find((trickStream) =>
758
- shaka.util.MimeUtils.getCodecBase(stream.codecs) ==
759
- shaka.util.MimeUtils.getCodecBase(trickStream.codecs));
758
+ shaka.util.MimeUtils.getNormalizedCodec(stream.codecs) ==
759
+ shaka.util.MimeUtils.getNormalizedCodec(trickStream.codecs));
760
760
  }
761
761
  }
762
762
  }
@@ -1218,7 +1218,6 @@ shaka.dash.DashParser = class {
1218
1218
  });
1219
1219
  let spatialAudio = false;
1220
1220
  if (hasJoc) {
1221
- context.representation.mimeType = 'audio/eac3-joc';
1222
1221
  spatialAudio = true;
1223
1222
  }
1224
1223
 
@@ -1736,8 +1736,8 @@ shaka.hls.HlsParser = class {
1736
1736
  * @param {number} timestampOffset
1737
1737
  * @param {!Map.<string, string>} variables
1738
1738
  * @param {string} absoluteMediaPlaylistUri
1739
- * @return {!shaka.media.SegmentReference}
1740
1739
  * @param {string} type
1740
+ * @return {shaka.media.SegmentReference}
1741
1741
  * @private
1742
1742
  */
1743
1743
  createSegmentReference_(
@@ -1753,17 +1753,42 @@ shaka.hls.HlsParser = class {
1753
1753
  let startByte = 0;
1754
1754
  let endByte = null;
1755
1755
 
1756
+ if (!extinfTag) {
1757
+ if (hlsSegment.partialSegments.length == 0) {
1758
+ // EXTINF tag must be available if the segment has no partial segments.
1759
+ throw new shaka.util.Error(
1760
+ shaka.util.Error.Severity.CRITICAL,
1761
+ shaka.util.Error.Category.MANIFEST,
1762
+ shaka.util.Error.Code.HLS_REQUIRED_TAG_MISSING, 'EXTINF');
1763
+ } else if (!this.lowLatencyMode_) {
1764
+ // Without EXTINF and without low-latency mode, partial segments get
1765
+ // ignored.
1766
+ return null;
1767
+ }
1768
+ }
1769
+
1756
1770
  // Create SegmentReferences for the partial segments.
1757
1771
  const partialSegmentRefs = [];
1758
- if (this.lowLatencyMode_ && hlsSegment.partialSegments.length) {
1772
+ if (this.lowLatencyMode_) {
1759
1773
  for (let i = 0; i < hlsSegment.partialSegments.length; i++) {
1760
1774
  const item = hlsSegment.partialSegments[i];
1761
1775
  const pPreviousReference = i == 0 ?
1762
1776
  previousReference : partialSegmentRefs[partialSegmentRefs.length - 1];
1763
1777
  const pStartTime = (i == 0) ? startTime : pPreviousReference.endTime;
1764
- const pDuration = Number(item.getAttributeValue('DURATION'));
1765
- // A preload hinted partial segment doesn't have duration information,
1766
- // so its startTime and endTime are the same.
1778
+
1779
+ // If DURATION is missing from this partial segment, use the target
1780
+ // partial duration from the top of the playlist, which is a required
1781
+ // attribute for content with partial segments.
1782
+ const pDuration = Number(item.getAttributeValue('DURATION')) ||
1783
+ this.partialTargetDuration_;
1784
+
1785
+ // If for some reason we have neither an explicit duration, nor a target
1786
+ // partial duration, we should SKIP this partial segment to avoid
1787
+ // duplicating content in the presentation timeline.
1788
+ if (!pDuration) {
1789
+ continue;
1790
+ }
1791
+
1767
1792
  const pEndTime = pStartTime + pDuration;
1768
1793
 
1769
1794
  let pStartByte = 0;
@@ -1796,14 +1821,6 @@ shaka.hls.HlsParser = class {
1796
1821
  /* appendWindowEnd= */ Infinity);
1797
1822
  partialSegmentRefs.push(partial);
1798
1823
  } // for-loop of hlsSegment.partialSegments
1799
- } else {
1800
- // EXTINF tag must be available if the segment has no partial segments.
1801
- if (!extinfTag) {
1802
- throw new shaka.util.Error(
1803
- shaka.util.Error.Severity.CRITICAL,
1804
- shaka.util.Error.Category.MANIFEST,
1805
- shaka.util.Error.Code.HLS_REQUIRED_TAG_MISSING, 'EXTINF');
1806
- }
1807
1824
  }
1808
1825
 
1809
1826
  // If the segment has EXTINF tag, set the segment's end time, start byte
@@ -1822,6 +1839,7 @@ shaka.hls.HlsParser = class {
1822
1839
  } else {
1823
1840
  endTime = partialSegmentRefs[partialSegmentRefs.length - 1].endTime;
1824
1841
  }
1842
+
1825
1843
  // If the segment has EXT-X-BYTERANGE tag, set the start byte and end byte
1826
1844
  // base on the byterange information. If segment has no EXT-X-BYTERANGE tag
1827
1845
  // and has partial segments, set the start byte and end byte base on the
@@ -2047,7 +2065,9 @@ shaka.hls.HlsParser = class {
2047
2065
  playlist.absoluteUri,
2048
2066
  type);
2049
2067
 
2050
- references.push(reference);
2068
+ if (reference) {
2069
+ references.push(reference);
2070
+ }
2051
2071
  } else if (!this.lowLatencyMode_) {
2052
2072
  // If a segment has no extinfTag, it must contain partial segments.
2053
2073
  shaka.log.alwaysWarn('Low-latency HLS live stream detected, but ' +
@@ -2191,6 +2211,9 @@ shaka.hls.HlsParser = class {
2191
2211
  variables,
2192
2212
  /* absoluteMediaPlaylistUri= */ '',
2193
2213
  type);
2214
+ goog.asserts.assert(
2215
+ segmentRef != null, 'Segment reference should not be null!');
2216
+
2194
2217
  // If we are updating the manifest, we can usually skip fetching the segment
2195
2218
  // by examining the references we already have. This won't be possible if
2196
2219
  // there was some kind of lag or delay updating the manifest on the server,
@@ -2539,12 +2562,16 @@ shaka.hls.HlsParser = class {
2539
2562
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
2540
2563
  const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
2541
2564
 
2565
+ // If you wait long enough, requesting the first segment can fail
2566
+ // because it has fallen off the left edge of DVR, so to be safer,
2567
+ // let's request the middle segment.
2542
2568
  goog.asserts.assert(playlist.segments.length,
2543
2569
  'Playlist should have segments!');
2544
- const firstSegmentUri = this.variableSubstitution_(
2545
- playlist.segments[0].absoluteUri, variables);
2570
+ const middleSegmentIdx = Math.trunc((playlist.segments.length - 1) / 2);
2571
+ const middleSegmentUri = this.variableSubstitution_(
2572
+ playlist.segments[middleSegmentIdx].absoluteUri, variables);
2546
2573
 
2547
- const parsedUri = new goog.Uri(firstSegmentUri);
2574
+ const parsedUri = new goog.Uri(middleSegmentUri);
2548
2575
  const extension = parsedUri.getPath().split('.').pop();
2549
2576
  const map = HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_[contentType];
2550
2577
 
@@ -2575,7 +2602,7 @@ shaka.hls.HlsParser = class {
2575
2602
  // If unable to guess mime type, request a segment and try getting it
2576
2603
  // from the response.
2577
2604
  const headRequest = shaka.net.NetworkingEngine.makeRequest(
2578
- [firstSegmentUri], this.config_.retryParameters);
2605
+ [middleSegmentUri], this.config_.retryParameters);
2579
2606
  headRequest.method = 'HEAD';
2580
2607
 
2581
2608
  const response = await this.makeNetworkRequest_(
@@ -1372,6 +1372,9 @@ shaka.media.DrmEngine = class {
1372
1372
  }
1373
1373
  return;
1374
1374
  }
1375
+ if (this.destroyer_.destroyed()) {
1376
+ return;
1377
+ }
1375
1378
 
1376
1379
  const updateEvent = new shaka.util.FakeEvent('drmsessionupdate');
1377
1380
  this.playerInterface_.onEvent(updateEvent);
@@ -63,6 +63,11 @@ shaka.media.MediaSourceEngine = class {
63
63
  string>} */
64
64
  this.sourceBufferTypes_ = {};
65
65
 
66
+
67
+ /** @private {!Object.<shaka.util.ManifestParserUtils.ContentType,
68
+ boolean>} */
69
+ this.expectedEncryption_ = {};
70
+
66
71
  /** @private {shaka.text.TextEngine} */
67
72
  this.textEngine_ = null;
68
73
 
@@ -345,6 +350,7 @@ shaka.media.MediaSourceEngine = class {
345
350
  this.sourceBuffers_[contentType] = sourceBuffer;
346
351
  this.sourceBufferTypes_[contentType] = mimeType;
347
352
  this.queues_[contentType] = [];
353
+ this.expectedEncryption_[contentType] = !!stream.drmInfos.length;
348
354
  }
349
355
  }
350
356
  }
@@ -1091,7 +1097,7 @@ shaka.media.MediaSourceEngine = class {
1091
1097
  */
1092
1098
  workAroundBrokenPlatforms_(segment, startTime, contentType) {
1093
1099
  const isInitSegment = startTime == null;
1094
- const encryptionExpected = this.video_.mediaKeys;
1100
+ const encryptionExpected = this.expectedEncryption_[contentType];
1095
1101
 
1096
1102
  // If:
1097
1103
  // 1. this is an init segment,
@@ -368,8 +368,10 @@ shaka.offline.indexeddb.StorageMechanism.SESSION_ID_STORE = 'session-ids';
368
368
  shaka.offline.StorageMuxer.register(
369
369
  'idb',
370
370
  () => {
371
- // Offline storage is not supported on the Chromecast platform.
372
- if (shaka.util.Platform.isChromecast()) {
371
+ // Offline storage is not supported on the Chromecast or Xbox One
372
+ // platforms.
373
+ if (shaka.util.Platform.isChromecast() ||
374
+ shaka.util.Platform.isXboxOne()) {
373
375
  return null;
374
376
  }
375
377
  // Offline storage requires the IndexedDB API.