shaka-player 4.11.13 → 4.12.1

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 (71) hide show
  1. package/README.md +47 -0
  2. package/dist/deps.js +8 -8
  3. package/dist/locales.js +35 -35
  4. package/dist/shaka-player.compiled.d.ts +36 -13
  5. package/dist/shaka-player.compiled.debug.d.ts +36 -13
  6. package/dist/shaka-player.compiled.debug.externs.js +46 -11
  7. package/dist/shaka-player.compiled.debug.js +543 -517
  8. package/dist/shaka-player.compiled.debug.map +4 -4
  9. package/dist/shaka-player.compiled.externs.js +46 -11
  10. package/dist/shaka-player.compiled.js +1348 -1331
  11. package/dist/shaka-player.compiled.map +4 -4
  12. package/dist/shaka-player.ui.d.ts +37 -14
  13. package/dist/shaka-player.ui.debug.d.ts +37 -14
  14. package/dist/shaka-player.ui.debug.externs.js +46 -11
  15. package/dist/shaka-player.ui.debug.js +629 -598
  16. package/dist/shaka-player.ui.debug.map +4 -4
  17. package/dist/shaka-player.ui.externs.js +46 -11
  18. package/dist/shaka-player.ui.js +1624 -1603
  19. package/dist/shaka-player.ui.map +4 -4
  20. package/externs/shaka/ads.js +9 -0
  21. package/externs/shaka/manifest.js +26 -1
  22. package/externs/shaka/offline.js +8 -2
  23. package/externs/shaka/player.js +80 -28
  24. package/externs/shaka/text.js +9 -0
  25. package/lib/ads/ad_manager.js +6 -0
  26. package/lib/ads/ad_utils.js +1 -0
  27. package/lib/ads/client_side_ad.js +8 -0
  28. package/lib/ads/interstitial_ad.js +25 -4
  29. package/lib/ads/interstitial_ad_manager.js +67 -8
  30. package/lib/ads/media_tailor_ad.js +8 -0
  31. package/lib/ads/server_side_ad.js +8 -0
  32. package/lib/dash/content_protection.js +31 -0
  33. package/lib/dash/dash_parser.js +22 -12
  34. package/lib/hls/hls_parser.js +63 -49
  35. package/lib/media/adaptation_set.js +11 -17
  36. package/lib/media/adaptation_set_criteria.js +4 -9
  37. package/lib/media/drm_engine.js +3 -1
  38. package/lib/media/manifest_filterer.js +2 -1
  39. package/lib/media/media_source_engine.js +286 -20
  40. package/lib/media/playhead.js +3 -1
  41. package/lib/media/preload_manager.js +10 -7
  42. package/lib/media/segment_prefetch.js +32 -13
  43. package/lib/media/segment_reference.js +3 -3
  44. package/lib/media/streaming_engine.js +87 -261
  45. package/lib/mss/mss_parser.js +1 -0
  46. package/lib/offline/download_info.js +5 -1
  47. package/lib/offline/indexeddb/storage_mechanism.js +4 -3
  48. package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
  49. package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
  50. package/lib/offline/manifest_converter.js +4 -0
  51. package/lib/offline/storage.js +277 -5
  52. package/lib/player.js +224 -78
  53. package/lib/text/simple_text_displayer.js +7 -0
  54. package/lib/text/stub_text_displayer.js +7 -0
  55. package/lib/text/ui_text_displayer.js +12 -0
  56. package/lib/util/dom_utils.js +14 -0
  57. package/lib/util/error.js +5 -0
  58. package/lib/util/periods.js +2 -0
  59. package/lib/util/platform.js +15 -0
  60. package/lib/util/player_configuration.js +11 -4
  61. package/lib/util/stream_utils.js +20 -1
  62. package/package.json +1 -1
  63. package/ui/ad_statistics_button.js +12 -0
  64. package/ui/controls.js +31 -7
  65. package/ui/externs/ui.js +8 -1
  66. package/ui/fullscreen_button.js +9 -0
  67. package/ui/locales/be.json +49 -0
  68. package/ui/mute_button.js +42 -11
  69. package/ui/skip_ad_button.js +16 -11
  70. package/ui/statistics_button.js +12 -0
  71. package/ui/ui.js +10 -5
@@ -11,6 +11,7 @@ goog.require('shaka.log');
11
11
  goog.require('shaka.util.BufferUtils');
12
12
  goog.require('shaka.util.Error');
13
13
  goog.require('shaka.util.ManifestParserUtils');
14
+ goog.require('shaka.util.Platform');
14
15
  goog.require('shaka.util.Pssh');
15
16
  goog.require('shaka.util.StringUtils');
16
17
  goog.require('shaka.util.TXml');
@@ -194,6 +195,34 @@ shaka.dash.ContentProtection = class {
194
195
  return repContext.defaultKeyId || context.defaultKeyId;
195
196
  }
196
197
 
198
+ /**
199
+ * Gets a FairPlay license URL from a content protection element
200
+ * containing a 'dashif:Laurl' element
201
+ *
202
+ * @param {shaka.dash.ContentProtection.Element} element
203
+ * @return {string}
204
+ */
205
+ static getFairPlayLicenseUrl(element) {
206
+ if (shaka.util.Platform.isMediaKeysPolyfilled()) {
207
+ throw new shaka.util.Error(
208
+ shaka.util.Error.Severity.CRITICAL,
209
+ shaka.util.Error.Category.MANIFEST,
210
+ shaka.util.Error.Code
211
+ .DASH_MSE_ENCRYPTED_LEGACY_APPLE_MEDIA_KEYS_NOT_SUPPORTED);
212
+ }
213
+ const dashIfLaurlNode = shaka.util.TXml.findChildNS(
214
+ element.node, shaka.dash.ContentProtection.DashIfNamespaceUri_,
215
+ 'Laurl',
216
+ );
217
+ if (dashIfLaurlNode) {
218
+ const textContents = shaka.util.TXml.getTextContents(dashIfLaurlNode);
219
+ if (textContents) {
220
+ return textContents;
221
+ }
222
+ }
223
+ return '';
224
+ }
225
+
197
226
  /**
198
227
  * Gets a Widevine license URL from a content protection element
199
228
  * containing a custom `ms:laurl` or 'dashif:Laurl' elements
@@ -793,6 +822,8 @@ shaka.dash.ContentProtection.Element;
793
822
  * @private
794
823
  */
795
824
  shaka.dash.ContentProtection.licenseUrlParsers_ = new Map()
825
+ .set('com.apple.fps',
826
+ shaka.dash.ContentProtection.getFairPlayLicenseUrl)
796
827
  .set('com.widevine.alpha',
797
828
  shaka.dash.ContentProtection.getWidevineLicenseUrl)
798
829
  .set('com.microsoft.playready',
@@ -681,7 +681,6 @@ shaka.dash.DashParser = class {
681
681
  }
682
682
 
683
683
  this.manifestPatchContext_.type = mpdType;
684
- this.cleanStreamMap_();
685
684
  /** @type {!shaka.media.PresentationTimeline} */
686
685
  let presentationTimeline;
687
686
  if (this.manifest_) {
@@ -858,6 +857,8 @@ shaka.dash.DashParser = class {
858
857
  // after period combining, while we still have a direct reference, so that
859
858
  // any new streams will appear in the period combiner.
860
859
  this.playerInterface_.makeTextStreamsForClosedCaptions(this.manifest_);
860
+
861
+ this.cleanStreamMap_();
861
862
  }
862
863
 
863
864
  /**
@@ -1501,13 +1502,21 @@ shaka.dash.DashParser = class {
1501
1502
  return !this.lastManifestUpdatePeriodIds_.includes(pId);
1502
1503
  });
1503
1504
  for (const pId of diffPeriodsIDs) {
1505
+ let shouldDeleteIndex = true;
1504
1506
  for (const contextId of this.indexStreamMap_[pId]) {
1507
+ const stream = this.streamMap_[contextId];
1508
+ if (stream.segmentIndex && !stream.segmentIndex.isEmpty()) {
1509
+ shouldDeleteIndex = false;
1510
+ continue;
1511
+ }
1505
1512
  if (this.periodCombiner_) {
1506
1513
  this.periodCombiner_.deleteStream(this.streamMap_[contextId], pId);
1507
1514
  }
1508
1515
  delete this.streamMap_[contextId];
1509
1516
  }
1510
- delete this.indexStreamMap_[pId];
1517
+ if (shouldDeleteIndex) {
1518
+ delete this.indexStreamMap_[pId];
1519
+ }
1511
1520
  }
1512
1521
  }
1513
1522
 
@@ -1597,13 +1606,15 @@ shaka.dash.DashParser = class {
1597
1606
  .filter((as) => { return as.trickModeFor; });
1598
1607
 
1599
1608
  // Attach trick mode tracks to normal tracks.
1600
- for (const trickModeSet of trickModeAdaptationSets) {
1601
- const targetIds = trickModeSet.trickModeFor.split(' ');
1602
- for (const normalSet of normalAdaptationSets) {
1603
- if (targetIds.includes(normalSet.id)) {
1604
- for (const stream of normalSet.streams) {
1605
- shaka.util.StreamUtils.setBetterIFrameStream(
1606
- stream, trickModeSet.streams);
1609
+ if (!this.config_.disableIFrames) {
1610
+ for (const trickModeSet of trickModeAdaptationSets) {
1611
+ const targetIds = trickModeSet.trickModeFor.split(' ');
1612
+ for (const normalSet of normalAdaptationSets) {
1613
+ if (targetIds.includes(normalSet.id)) {
1614
+ for (const stream of normalSet.streams) {
1615
+ shaka.util.StreamUtils.setBetterIFrameStream(
1616
+ stream, trickModeSet.streams);
1617
+ }
1607
1618
  }
1608
1619
  }
1609
1620
  }
@@ -2023,9 +2034,7 @@ shaka.dash.DashParser = class {
2023
2034
  new Set([...drmInfo.keyIds, ...stream.keyIds]) :
2024
2035
  drmInfo.keyIds || stream.keyIds;
2025
2036
  }
2026
- if (this.config_.dash.enableAudioGroups) {
2027
- stream.groupId = adaptationId;
2028
- }
2037
+ stream.groupId = adaptationId;
2029
2038
  }
2030
2039
 
2031
2040
  const repIds = representations
@@ -2384,6 +2393,7 @@ shaka.dash.DashParser = class {
2384
2393
  fastSwitching: false,
2385
2394
  fullMimeTypes: new Set([shaka.util.MimeUtils.getFullType(
2386
2395
  context.representation.mimeType, context.representation.codecs)]),
2396
+ isAudioMuxedInVideo: false,
2387
2397
  };
2388
2398
  }
2389
2399
 
@@ -293,6 +293,9 @@ shaka.hls.HlsParser = class {
293
293
  * @exportInterface
294
294
  */
295
295
  configure(config, isPreloadFn) {
296
+ const needFireUpdate = this.playerInterface_ &&
297
+ config.hls.updatePeriod != this.config_.hls.updatePeriod &&
298
+ config.hls.updatePeriod >= 0;
296
299
  this.config_ = config;
297
300
  if (isPreloadFn) {
298
301
  this.isPreloadFn_ = isPreloadFn;
@@ -301,6 +304,11 @@ shaka.hls.HlsParser = class {
301
304
  if (this.contentSteeringManager_) {
302
305
  this.contentSteeringManager_.configure(this.config_);
303
306
  }
307
+
308
+ if (needFireUpdate && this.manifest_ &&
309
+ this.manifest_.presentationTimeline.isLive()) {
310
+ this.updatePlaylistTimer_.tickNow();
311
+ }
304
312
  }
305
313
 
306
314
  /**
@@ -420,7 +428,8 @@ shaka.hls.HlsParser = class {
420
428
  // problem in the live encoder for example), and disable the stream if
421
429
  // necessary.
422
430
  for (const streamInfo of activeStreamInfos) {
423
- if (streamInfo.stream.segmentIndex &&
431
+ if (!streamInfo.stream.isAudioMuxedInVideo &&
432
+ streamInfo.stream.segmentIndex &&
424
433
  !streamInfo.stream.segmentIndex.earliestReference()) {
425
434
  this.playerInterface_.disableStream(streamInfo.stream);
426
435
  }
@@ -448,6 +457,9 @@ shaka.hls.HlsParser = class {
448
457
  * @private
449
458
  */
450
459
  async updateStream_(streamInfo) {
460
+ if (streamInfo.stream.isAudioMuxedInVideo) {
461
+ return;
462
+ }
451
463
  const manifestUris = [];
452
464
  for (const uri of streamInfo.getUris()) {
453
465
  const uriObj = new goog.Uri(uri);
@@ -1491,11 +1503,11 @@ shaka.hls.HlsParser = class {
1491
1503
  * @private
1492
1504
  */
1493
1505
  createStreamInfosFromMediaTags_(mediaTags, groupIdPathwayIdMapping) {
1494
- // Filter out subtitles and media tags without uri.
1506
+ // Filter out subtitles and media tags without uri (except audio).
1495
1507
  mediaTags = mediaTags.filter((tag) => {
1496
1508
  const uri = tag.getAttributeValue('URI') || '';
1497
1509
  const type = tag.getAttributeValue('TYPE');
1498
- return type != 'SUBTITLES' && uri != '';
1510
+ return type != 'SUBTITLES' && (uri != '' || type == 'AUDIO');
1499
1511
  });
1500
1512
 
1501
1513
  const groupedTags = {};
@@ -1511,7 +1523,7 @@ shaka.hls.HlsParser = class {
1511
1523
  for (const key in groupedTags) {
1512
1524
  // Create stream info for each audio / video media grouped tag.
1513
1525
  this.createStreamInfoFromMediaTags_(
1514
- groupedTags[key], groupIdPathwayIdMapping);
1526
+ groupedTags[key], groupIdPathwayIdMapping, /* requireUri= */ false);
1515
1527
  }
1516
1528
  }
1517
1529
 
@@ -1781,32 +1793,8 @@ shaka.hls.HlsParser = class {
1781
1793
  }
1782
1794
 
1783
1795
  if (!ignoreStream) {
1784
- let language = null;
1785
- let name = null;
1786
- let channelsCount = null;
1787
- let spatialAudio = false;
1788
- let characteristics = null;
1789
- let sampleRate = null;
1790
- if (!streamInfos.length) {
1791
- const mediaTag = mediaTags.find((tag) => {
1792
- const uri = tag.getAttributeValue('URI') || '';
1793
- const type = tag.getAttributeValue('TYPE');
1794
- const groupId = tag.getRequiredAttrValue('GROUP-ID');
1795
- return type != 'SUBTITLES' && uri == '' &&
1796
- globalGroupIds.includes(groupId);
1797
- });
1798
- if (mediaTag) {
1799
- language = mediaTag.getAttributeValue('LANGUAGE');
1800
- name = mediaTag.getAttributeValue('NAME');
1801
- channelsCount = this.getChannelsCount_(mediaTag);
1802
- spatialAudio = this.isSpatialAudio_(mediaTag);
1803
- characteristics = mediaTag.getAttributeValue('CHARACTERISTICS');
1804
- sampleRate = this.getSampleRate_(mediaTag);
1805
- }
1806
- }
1807
- const streamInfo = this.createStreamInfoFromVariantTags_(
1808
- tags, allCodecs, type, language, name, channelsCount,
1809
- characteristics, sampleRate, spatialAudio);
1796
+ const streamInfo =
1797
+ this.createStreamInfoFromVariantTags_(tags, allCodecs, type);
1810
1798
  if (globalGroupId) {
1811
1799
  streamInfo.stream.groupId = globalGroupId;
1812
1800
  }
@@ -2035,8 +2023,10 @@ shaka.hls.HlsParser = class {
2035
2023
  if (videoStream) {
2036
2024
  videoStream.drmInfos = drmInfos;
2037
2025
  videoStream.keyIds = keyIds;
2038
- shaka.util.StreamUtils.setBetterIFrameStream(
2039
- videoStream, iFrameStreams);
2026
+ if (!this.config_.disableIFrames) {
2027
+ shaka.util.StreamUtils.setBetterIFrameStream(
2028
+ videoStream, iFrameStreams);
2029
+ }
2040
2030
  }
2041
2031
  if (videoStream && !audioStream) {
2042
2032
  videoStream.bandwidth = bandwidth;
@@ -2140,17 +2130,20 @@ shaka.hls.HlsParser = class {
2140
2130
  *
2141
2131
  * @param {!Array.<!shaka.hls.Tag>} tags
2142
2132
  * @param {!Map.<string, string>} groupIdPathwayIdMapping
2133
+ * @param {boolean=} requireUri
2143
2134
  * @return {!shaka.hls.HlsParser.StreamInfo}
2144
2135
  * @private
2145
2136
  */
2146
- createStreamInfoFromMediaTags_(tags, groupIdPathwayIdMapping) {
2137
+ createStreamInfoFromMediaTags_(tags, groupIdPathwayIdMapping,
2138
+ requireUri = true) {
2147
2139
  const verbatimMediaPlaylistUris = [];
2148
2140
  const globalGroupIds = [];
2149
2141
  const groupIdUriMappping = new Map();
2150
2142
  for (const tag of tags) {
2151
2143
  goog.asserts.assert(tag.name == 'EXT-X-MEDIA',
2152
2144
  'Should only be called on media tags!');
2153
- const uri = tag.getRequiredAttrValue('URI');
2145
+ const uri = requireUri ? tag.getRequiredAttrValue('URI') :
2146
+ (tag.getAttributeValue('URI') || shaka.hls.HlsParser.FAKE_MUXED_URL_);
2154
2147
  const groupId = tag.getRequiredAttrValue('GROUP-ID');
2155
2148
  verbatimMediaPlaylistUris.push(uri);
2156
2149
  globalGroupIds.push(groupId);
@@ -2350,17 +2343,10 @@ shaka.hls.HlsParser = class {
2350
2343
  * @param {!Array.<!shaka.hls.Tag>} tags
2351
2344
  * @param {!Array.<string>} allCodecs
2352
2345
  * @param {string} type
2353
- * @param {?string} language
2354
- * @param {?string} name
2355
- * @param {?number} channelsCount
2356
- * @param {?string} characteristics
2357
- * @param {?number} sampleRate
2358
- * @param {boolean} spatialAudio
2359
2346
  * @return {!shaka.hls.HlsParser.StreamInfo}
2360
2347
  * @private
2361
2348
  */
2362
- createStreamInfoFromVariantTags_(tags, allCodecs, type, language, name,
2363
- channelsCount, characteristics, sampleRate, spatialAudio) {
2349
+ createStreamInfoFromVariantTags_(tags, allCodecs, type) {
2364
2350
  const streamId = this.globalId_++;
2365
2351
  const verbatimMediaPlaylistUris = [];
2366
2352
  for (const tag of tags) {
@@ -2382,10 +2368,11 @@ shaka.hls.HlsParser = class {
2382
2368
  const closedCaptions = this.getClosedCaptions_(tags[0], type);
2383
2369
  const codecs = shaka.util.ManifestParserUtils.guessCodecs(type, allCodecs);
2384
2370
  const streamInfo = this.createStreamInfo_(
2385
- streamId, verbatimMediaPlaylistUris, codecs, type, language,
2386
- /* primary= */ false, name, channelsCount, closedCaptions,
2387
- characteristics, /* forced= */ false, sampleRate,
2388
- /* spatialAudio= */ false);
2371
+ streamId, verbatimMediaPlaylistUris,
2372
+ codecs, type, /* language= */ null, /* primary= */ false,
2373
+ /* name= */ null, /* channelcount= */ null, closedCaptions,
2374
+ /* characteristics= */ null, /* forced= */ false,
2375
+ /* sampleRate= */ null, /* spatialAudio= */ false);
2389
2376
 
2390
2377
  this.uriToStreamInfosMap_.set(key, streamInfo);
2391
2378
  return streamInfo;
@@ -2421,6 +2408,15 @@ shaka.hls.HlsParser = class {
2421
2408
  languageValue, primary, name, channelsCount, closedCaptions,
2422
2409
  characteristics, forced, sampleRate, spatialAudio);
2423
2410
 
2411
+ const FAKE_MUXED_URL_ = shaka.hls.HlsParser.FAKE_MUXED_URL_;
2412
+ if (verbatimMediaPlaylistUris.includes(FAKE_MUXED_URL_)) {
2413
+ stream.isAudioMuxedInVideo = true;
2414
+ // We assigned the TS mimetype because it is the only one that works
2415
+ // with this functionality. MP4 is not supported right now.
2416
+ stream.mimeType = 'video/mp2t';
2417
+ this.setFullTypeForStream_(stream);
2418
+ }
2419
+
2424
2420
  const redirectUris = [];
2425
2421
  const getUris = () => {
2426
2422
  if (this.contentSteeringManager_ &&
@@ -2664,6 +2660,12 @@ shaka.hls.HlsParser = class {
2664
2660
  return creationPromise;
2665
2661
  }
2666
2662
 
2663
+ if (stream.isAudioMuxedInVideo) {
2664
+ const segmentIndex = new shaka.media.SegmentIndex([]);
2665
+ stream.segmentIndex = segmentIndex;
2666
+ return Promise.resolve();
2667
+ }
2668
+
2667
2669
  // Create a new PendingRequest to be able to cancel this specific
2668
2670
  // download.
2669
2671
  pendingRequest = this.requestManifest_(streamInfo.getUris(),
@@ -2704,7 +2706,8 @@ shaka.hls.HlsParser = class {
2704
2706
  getMinDuration_() {
2705
2707
  let minDuration = Infinity;
2706
2708
  for (const streamInfo of this.uriToStreamInfosMap_.values()) {
2707
- if (streamInfo.stream.segmentIndex && streamInfo.stream.type != 'text') {
2709
+ if (streamInfo.stream.segmentIndex && streamInfo.stream.type != 'text' &&
2710
+ !streamInfo.stream.isAudioMuxedInVideo) {
2708
2711
  // Since everything is already offset to 0 (either by sync or by being
2709
2712
  // VOD), only maxTimestamp is necessary to compute the duration.
2710
2713
  minDuration = Math.min(minDuration, streamInfo.maxTimestamp);
@@ -2721,7 +2724,8 @@ shaka.hls.HlsParser = class {
2721
2724
  let maxTimestamp = Infinity;
2722
2725
  let minTimestamp = Infinity;
2723
2726
  for (const streamInfo of this.uriToStreamInfosMap_.values()) {
2724
- if (streamInfo.stream.segmentIndex && streamInfo.stream.type != 'text') {
2727
+ if (streamInfo.stream.segmentIndex && streamInfo.stream.type != 'text' &&
2728
+ !streamInfo.stream.isAudioMuxedInVideo) {
2725
2729
  maxTimestamp = Math.min(maxTimestamp, streamInfo.maxTimestamp);
2726
2730
  minTimestamp = Math.min(minTimestamp, streamInfo.minTimestamp);
2727
2731
  }
@@ -3117,6 +3121,7 @@ shaka.hls.HlsParser = class {
3117
3121
  external: false,
3118
3122
  fastSwitching: false,
3119
3123
  fullMimeTypes: new Set(),
3124
+ isAudioMuxedInVideo: false,
3120
3125
  };
3121
3126
  this.setFullTypeForStream_(stream);
3122
3127
  return stream;
@@ -4590,7 +4595,8 @@ shaka.hls.HlsParser = class {
4590
4595
  if (this.isLive_()) {
4591
4596
  const updateDuration = (endTime - startTime) / 1000.0;
4592
4597
  this.averageUpdateDuration_.sample(1, updateDuration);
4593
- const delay = this.getUpdatePlaylistDelay_();
4598
+ const delay = this.config_.hls.updatePeriod > 0 ?
4599
+ this.config_.hls.updatePeriod : this.getUpdatePlaylistDelay_();
4594
4600
  const finalDelay = Math.max(0,
4595
4601
  delay - this.averageUpdateDuration_.getEstimate());
4596
4602
  this.updatePlaylistTimer_.tickAfter(/* seconds= */ finalDelay);
@@ -5154,6 +5160,14 @@ shaka.hls.HlsParser.PresentationType_ = {
5154
5160
  LIVE: 'LIVE',
5155
5161
  };
5156
5162
 
5163
+
5164
+ /**
5165
+ * @const {string}
5166
+ * @private
5167
+ */
5168
+ shaka.hls.HlsParser.FAKE_MUXED_URL_ = 'shaka://hls-muxed';
5169
+
5170
+
5157
5171
  shaka.media.ManifestParser.registerParserByMime(
5158
5172
  'application/x-mpegurl', () => new shaka.hls.HlsParser());
5159
5173
  shaka.media.ManifestParser.registerParserByMime(
@@ -27,10 +27,8 @@ shaka.media.AdaptationSet = class {
27
27
  * compatible. If a candidate is not compatible, it will not end up in the
28
28
  * adaptation set.
29
29
  * @param {boolean=} compareCodecs
30
- * @param {boolean=} enableAudioGroups
31
30
  */
32
- constructor(root, candidates, compareCodecs = true,
33
- enableAudioGroups = false) {
31
+ constructor(root, candidates, compareCodecs = true) {
34
32
  /** @private {shaka.extern.Variant} */
35
33
  this.root_ = root;
36
34
  /** @private {!Set.<shaka.extern.Variant>} */
@@ -40,18 +38,17 @@ shaka.media.AdaptationSet = class {
40
38
  // are not compatible with the root, they will be rejected by |add|.
41
39
  candidates = candidates || [];
42
40
  for (const candidate of candidates) {
43
- this.add(candidate, compareCodecs, enableAudioGroups);
41
+ this.add(candidate, compareCodecs);
44
42
  }
45
43
  }
46
44
 
47
45
  /**
48
46
  * @param {shaka.extern.Variant} variant
49
47
  * @param {boolean} compareCodecs
50
- * @param {boolean} enableAudioGroups
51
48
  * @return {boolean}
52
49
  */
53
- add(variant, compareCodecs, enableAudioGroups) {
54
- if (this.canInclude(variant, compareCodecs, enableAudioGroups)) {
50
+ add(variant, compareCodecs) {
51
+ if (this.canInclude(variant, compareCodecs)) {
55
52
  this.variants_.add(variant);
56
53
  return true;
57
54
  }
@@ -68,22 +65,20 @@ shaka.media.AdaptationSet = class {
68
65
  *
69
66
  * @param {shaka.extern.Variant} variant
70
67
  * @param {boolean=} compareCodecs
71
- * @param {boolean=} enableAudioGroups
72
68
  * @return {boolean}
73
69
  */
74
- canInclude(variant, compareCodecs = true, enableAudioGroups = false) {
70
+ canInclude(variant, compareCodecs = true) {
75
71
  return shaka.media.AdaptationSet
76
- .areAdaptable(this.root_, variant, compareCodecs, enableAudioGroups);
72
+ .areAdaptable(this.root_, variant, compareCodecs);
77
73
  }
78
74
 
79
75
  /**
80
76
  * @param {shaka.extern.Variant} a
81
77
  * @param {shaka.extern.Variant} b
82
78
  * @param {boolean} compareCodecs
83
- * @param {boolean} enableAudioGroups
84
79
  * @return {boolean}
85
80
  */
86
- static areAdaptable(a, b, compareCodecs, enableAudioGroups) {
81
+ static areAdaptable(a, b, compareCodecs) {
87
82
  const AdaptationSet = shaka.media.AdaptationSet;
88
83
 
89
84
  // All variants should have audio or should all not have audio.
@@ -104,8 +99,8 @@ shaka.media.AdaptationSet = class {
104
99
  goog.asserts.assert(
105
100
  !!a.audio == !!b.audio,
106
101
  'Both should either have audio or not have audio.');
107
- if (a.audio && b.audio && !AdaptationSet.areAudiosCompatible_(
108
- a.audio, b.audio, compareCodecs, enableAudioGroups)) {
102
+ if (a.audio && b.audio &&
103
+ !AdaptationSet.areAudiosCompatible_(a.audio, b.audio, compareCodecs)) {
109
104
  return false;
110
105
  }
111
106
 
@@ -133,11 +128,10 @@ shaka.media.AdaptationSet = class {
133
128
  * @param {shaka.extern.Stream} a
134
129
  * @param {shaka.extern.Stream} b
135
130
  * @param {boolean} compareCodecs
136
- * @param {boolean} enableAudioGroups
137
131
  * @return {boolean}
138
132
  * @private
139
133
  */
140
- static areAudiosCompatible_(a, b, compareCodecs, enableAudioGroups) {
134
+ static areAudiosCompatible_(a, b, compareCodecs) {
141
135
  const AdaptationSet = shaka.media.AdaptationSet;
142
136
 
143
137
  // Don't adapt between channel counts, which could annoy the user
@@ -167,7 +161,7 @@ shaka.media.AdaptationSet = class {
167
161
  }
168
162
 
169
163
  // We can only adapt between the same groupId.
170
- if (enableAudioGroups && a.groupId !== b.groupId) {
164
+ if (a.groupId !== b.groupId) {
171
165
  return false;
172
166
  }
173
167
 
@@ -42,9 +42,8 @@ shaka.media.ExampleBasedCriteria = class {
42
42
  /**
43
43
  * @param {shaka.extern.Variant} example
44
44
  * @param {shaka.config.CodecSwitchingStrategy} codecSwitchingStrategy
45
- * @param {boolean} enableAudioGroups
46
45
  */
47
- constructor(example, codecSwitchingStrategy, enableAudioGroups) {
46
+ constructor(example, codecSwitchingStrategy) {
48
47
  // We can't know if role and label are really important, so we don't use
49
48
  // role and label for this.
50
49
  const role = '';
@@ -65,7 +64,7 @@ shaka.media.ExampleBasedCriteria = class {
65
64
  this.preferenceBasedCriteria_ = new shaka.media.PreferenceBasedCriteria(
66
65
  example.language, role, channelCount, hdrLevel, spatialAudio,
67
66
  videoLayout, audioLabel, videoLabel,
68
- codecSwitchingStrategy, enableAudioGroups, audioCodec);
67
+ codecSwitchingStrategy, audioCodec);
69
68
  }
70
69
 
71
70
  /** @override */
@@ -90,12 +89,10 @@ shaka.media.PreferenceBasedCriteria = class {
90
89
  * @param {string} audioLabel
91
90
  * @param {string} videoLabel
92
91
  * @param {shaka.config.CodecSwitchingStrategy} codecSwitchingStrategy
93
- * @param {boolean} enableAudioGroups
94
92
  * @param {string} audioCodec
95
93
  */
96
94
  constructor(language, role, channelCount, hdrLevel, spatialAudio,
97
- videoLayout, audioLabel, videoLabel, codecSwitchingStrategy,
98
- enableAudioGroups, audioCodec) {
95
+ videoLayout, audioLabel, videoLabel, codecSwitchingStrategy, audioCodec) {
99
96
  /** @private {string} */
100
97
  this.language_ = language;
101
98
  /** @private {string} */
@@ -114,8 +111,6 @@ shaka.media.PreferenceBasedCriteria = class {
114
111
  this.videoLabel_ = videoLabel;
115
112
  /** @private {shaka.config.CodecSwitchingStrategy} */
116
113
  this.codecSwitchingStrategy_ = codecSwitchingStrategy;
117
- /** @private {boolean} */
118
- this.enableAudioGroups_ = enableAudioGroups;
119
114
  /** @private {string} */
120
115
  this.audioCodec_ = audioCodec;
121
116
  }
@@ -222,7 +217,7 @@ shaka.media.PreferenceBasedCriteria = class {
222
217
  shaka.media.Capabilities.isChangeTypeSupported();
223
218
 
224
219
  return new shaka.media.AdaptationSet(current[0], current,
225
- !supportsSmoothCodecTransitions, this.enableAudioGroups_);
220
+ !supportsSmoothCodecTransitions);
226
221
  }
227
222
 
228
223
  /**
@@ -179,7 +179,9 @@ shaka.media.DrmEngine = class {
179
179
  // Webkit EME implementation requires the src to be defined to clear
180
180
  // the MediaKeys.
181
181
  if (!shaka.util.Platform.isMediaKeysPolyfilled('webkit')) {
182
- goog.asserts.assert(!this.video_.src,
182
+ goog.asserts.assert(
183
+ !this.video_.src &&
184
+ !this.video_.getElementsByTagName('source').length,
183
185
  'video src must be removed first!');
184
186
  }
185
187
 
@@ -56,7 +56,8 @@ shaka.media.ManifestFilterer = class {
56
56
  manifest,
57
57
  this.config_.preferredVideoCodecs,
58
58
  this.config_.preferredAudioCodecs,
59
- this.config_.preferredDecodingAttributes);
59
+ this.config_.preferredDecodingAttributes,
60
+ this.config_.preferredTextFormats);
60
61
  }
61
62
  this.checkPlayableVariants_(manifest);
62
63
  return this.filterManifestWithRestrictions(manifest);