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.
- package/README.md +47 -0
- package/dist/deps.js +8 -8
- package/dist/locales.js +35 -35
- package/dist/shaka-player.compiled.d.ts +36 -13
- package/dist/shaka-player.compiled.debug.d.ts +36 -13
- package/dist/shaka-player.compiled.debug.externs.js +46 -11
- package/dist/shaka-player.compiled.debug.js +543 -517
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +46 -11
- package/dist/shaka-player.compiled.js +1348 -1331
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +37 -14
- package/dist/shaka-player.ui.debug.d.ts +37 -14
- package/dist/shaka-player.ui.debug.externs.js +46 -11
- package/dist/shaka-player.ui.debug.js +629 -598
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +46 -11
- package/dist/shaka-player.ui.js +1624 -1603
- package/dist/shaka-player.ui.map +4 -4
- package/externs/shaka/ads.js +9 -0
- package/externs/shaka/manifest.js +26 -1
- package/externs/shaka/offline.js +8 -2
- package/externs/shaka/player.js +80 -28
- package/externs/shaka/text.js +9 -0
- package/lib/ads/ad_manager.js +6 -0
- package/lib/ads/ad_utils.js +1 -0
- package/lib/ads/client_side_ad.js +8 -0
- package/lib/ads/interstitial_ad.js +25 -4
- package/lib/ads/interstitial_ad_manager.js +67 -8
- package/lib/ads/media_tailor_ad.js +8 -0
- package/lib/ads/server_side_ad.js +8 -0
- package/lib/dash/content_protection.js +31 -0
- package/lib/dash/dash_parser.js +22 -12
- package/lib/hls/hls_parser.js +63 -49
- package/lib/media/adaptation_set.js +11 -17
- package/lib/media/adaptation_set_criteria.js +4 -9
- package/lib/media/drm_engine.js +3 -1
- package/lib/media/manifest_filterer.js +2 -1
- package/lib/media/media_source_engine.js +286 -20
- package/lib/media/playhead.js +3 -1
- package/lib/media/preload_manager.js +10 -7
- package/lib/media/segment_prefetch.js +32 -13
- package/lib/media/segment_reference.js +3 -3
- package/lib/media/streaming_engine.js +87 -261
- package/lib/mss/mss_parser.js +1 -0
- package/lib/offline/download_info.js +5 -1
- package/lib/offline/indexeddb/storage_mechanism.js +4 -3
- package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
- package/lib/offline/manifest_converter.js +4 -0
- package/lib/offline/storage.js +277 -5
- package/lib/player.js +224 -78
- package/lib/text/simple_text_displayer.js +7 -0
- package/lib/text/stub_text_displayer.js +7 -0
- package/lib/text/ui_text_displayer.js +12 -0
- package/lib/util/dom_utils.js +14 -0
- package/lib/util/error.js +5 -0
- package/lib/util/periods.js +2 -0
- package/lib/util/platform.js +15 -0
- package/lib/util/player_configuration.js +11 -4
- package/lib/util/stream_utils.js +20 -1
- package/package.json +1 -1
- package/ui/ad_statistics_button.js +12 -0
- package/ui/controls.js +31 -7
- package/ui/externs/ui.js +8 -1
- package/ui/fullscreen_button.js +9 -0
- package/ui/locales/be.json +49 -0
- package/ui/mute_button.js +42 -11
- package/ui/skip_ad_button.js +16 -11
- package/ui/statistics_button.js +12 -0
- 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',
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
1601
|
-
const
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
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
|
-
|
|
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
|
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
-
|
|
1785
|
-
|
|
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
|
-
|
|
2039
|
-
|
|
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
|
|
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,
|
|
2386
|
-
/*
|
|
2387
|
-
|
|
2388
|
-
/*
|
|
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.
|
|
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
|
|
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
|
|
54
|
-
if (this.canInclude(variant, compareCodecs
|
|
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
|
|
70
|
+
canInclude(variant, compareCodecs = true) {
|
|
75
71
|
return shaka.media.AdaptationSet
|
|
76
|
-
.areAdaptable(this.root_, variant, compareCodecs
|
|
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
|
|
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 &&
|
|
108
|
-
a.audio, b.audio, compareCodecs
|
|
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
|
|
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 (
|
|
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
|
|
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,
|
|
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
|
|
220
|
+
!supportsSmoothCodecTransitions);
|
|
226
221
|
}
|
|
227
222
|
|
|
228
223
|
/**
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -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(
|
|
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);
|