shaka-player 4.7.13 → 4.7.14
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/AUTHORS +1 -0
- package/CONTRIBUTORS +1 -0
- package/dist/locales.js +34 -34
- package/dist/shaka-player.compiled.d.ts +1 -0
- package/dist/shaka-player.compiled.debug.d.ts +1 -0
- package/dist/shaka-player.compiled.debug.externs.js +4 -0
- package/dist/shaka-player.compiled.debug.js +183 -179
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +4 -0
- package/dist/shaka-player.compiled.js +1095 -1093
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +1 -0
- package/dist/shaka-player.ui.debug.d.ts +1 -0
- package/dist/shaka-player.ui.debug.externs.js +4 -0
- package/dist/shaka-player.ui.debug.js +183 -180
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +4 -0
- package/dist/shaka-player.ui.js +1229 -1227
- package/dist/shaka-player.ui.map +3 -3
- package/lib/ads/client_side_ad_manager.js +4 -2
- package/lib/dash/segment_template.js +24 -1
- package/lib/media/drm_engine.js +17 -3
- package/lib/media/media_source_engine.js +13 -3
- package/lib/media/playhead.js +3 -3
- package/lib/media/segment_index.js +10 -0
- package/lib/media/segment_reference.js +12 -0
- package/lib/media/streaming_engine.js +8 -14
- package/lib/player.js +42 -15
- package/lib/text/ui_text_displayer.js +10 -1
- package/lib/util/platform.js +31 -9
- package/lib/util/stream_utils.js +6 -2
- package/package.json +1 -1
- package/ui/resolution_selection.js +1 -0
|
@@ -533,7 +533,9 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
533
533
|
shaka.ads.AdManager.AD_STARTED, data));
|
|
534
534
|
if (this.ad_.isLinear()) {
|
|
535
535
|
this.adContainer_.setAttribute('ad-active', 'true');
|
|
536
|
-
this.
|
|
536
|
+
if (!this.config_.customPlayheadTracker) {
|
|
537
|
+
this.video_.pause();
|
|
538
|
+
}
|
|
537
539
|
if (this.video_.muted) {
|
|
538
540
|
this.ad_.setInitialMuted(this.video_.volume);
|
|
539
541
|
} else {
|
|
@@ -551,7 +553,7 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
551
553
|
(new Map()).set('originalEvent', e)));
|
|
552
554
|
if (this.ad_ && this.ad_.isLinear()) {
|
|
553
555
|
this.adContainer_.removeAttribute('ad-active');
|
|
554
|
-
if (!this.video_.ended) {
|
|
556
|
+
if (!this.config_.customPlayheadTracker && !this.video_.ended) {
|
|
555
557
|
this.video_.play();
|
|
556
558
|
}
|
|
557
559
|
}
|
|
@@ -394,6 +394,11 @@ shaka.dash.SegmentTemplate = class {
|
|
|
394
394
|
Math.ceil(availablePeriodTimes[1] / segmentDuration) - 1,
|
|
395
395
|
];
|
|
396
396
|
|
|
397
|
+
// For Low Latency we can request the partial current position.
|
|
398
|
+
if (context.representation.availabilityTimeOffset) {
|
|
399
|
+
availablePeriodPositions[1]++;
|
|
400
|
+
}
|
|
401
|
+
|
|
397
402
|
// In absolute positions.
|
|
398
403
|
const availablePresentationPositions =
|
|
399
404
|
availablePeriodPositions.map((x) => x + startNumber);
|
|
@@ -696,7 +701,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
696
701
|
*/
|
|
697
702
|
appendTemplateInfo(info, periodStart, periodEnd, shouldFit,
|
|
698
703
|
initSegmentReference) {
|
|
699
|
-
this.
|
|
704
|
+
this.updateInitSegmentReference(initSegmentReference);
|
|
700
705
|
if (!this.templateInfo_) {
|
|
701
706
|
this.templateInfo_ = info;
|
|
702
707
|
this.periodStart_ = periodStart;
|
|
@@ -727,6 +732,24 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
727
732
|
}
|
|
728
733
|
}
|
|
729
734
|
|
|
735
|
+
/**
|
|
736
|
+
* Updates the init segment reference and propagates the update to all
|
|
737
|
+
* references.
|
|
738
|
+
* @param {shaka.media.InitSegmentReference} initSegmentReference
|
|
739
|
+
*/
|
|
740
|
+
updateInitSegmentReference(initSegmentReference) {
|
|
741
|
+
if (this.initSegmentReference_ === initSegmentReference) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
this.initSegmentReference_ = initSegmentReference;
|
|
746
|
+
for (const reference of this.references) {
|
|
747
|
+
if (reference) {
|
|
748
|
+
reference.updateInitSegmentReference(initSegmentReference);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
730
753
|
/**
|
|
731
754
|
*
|
|
732
755
|
* @param {number} time
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -1551,6 +1551,9 @@ shaka.media.DrmEngine = class {
|
|
|
1551
1551
|
const req = this.playerInterface_.netEngine.request(requestType, request);
|
|
1552
1552
|
response = await req.promise;
|
|
1553
1553
|
} catch (error) {
|
|
1554
|
+
if (this.destroyer_.destroyed()) {
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1554
1557
|
// Request failed!
|
|
1555
1558
|
goog.asserts.assert(error instanceof shaka.util.Error,
|
|
1556
1559
|
'Wrong NetworkingEngine error type!');
|
|
@@ -1559,9 +1562,20 @@ shaka.media.DrmEngine = class {
|
|
|
1559
1562
|
shaka.util.Error.Category.DRM,
|
|
1560
1563
|
shaka.util.Error.Code.LICENSE_REQUEST_FAILED,
|
|
1561
1564
|
error);
|
|
1562
|
-
this.
|
|
1563
|
-
|
|
1564
|
-
metadata.updatePromise
|
|
1565
|
+
if (this.activeSessions_.size == 1) {
|
|
1566
|
+
this.onError_(shakaErr);
|
|
1567
|
+
if (metadata && metadata.updatePromise) {
|
|
1568
|
+
metadata.updatePromise.reject(shakaErr);
|
|
1569
|
+
}
|
|
1570
|
+
} else {
|
|
1571
|
+
if (metadata && metadata.updatePromise) {
|
|
1572
|
+
metadata.updatePromise.reject(shakaErr);
|
|
1573
|
+
}
|
|
1574
|
+
this.activeSessions_.delete(session);
|
|
1575
|
+
if (this.areAllSessionsLoaded_()) {
|
|
1576
|
+
this.allSessionsLoaded_.resolve();
|
|
1577
|
+
this.keyStatusTimer_.tickAfter(/* seconds= */ 0.1);
|
|
1578
|
+
}
|
|
1565
1579
|
}
|
|
1566
1580
|
return;
|
|
1567
1581
|
}
|
|
@@ -1839,12 +1839,17 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1839
1839
|
|
|
1840
1840
|
const totalOfBuffers = streamsByType.size;
|
|
1841
1841
|
let numberOfSourceBufferAdded = 0;
|
|
1842
|
-
|
|
1842
|
+
const onSourceBufferAdded = () => {
|
|
1843
1843
|
numberOfSourceBufferAdded++;
|
|
1844
1844
|
if (numberOfSourceBufferAdded === totalOfBuffers) {
|
|
1845
1845
|
sourceBufferAdded.resolve();
|
|
1846
|
+
this.eventManager_.unlisten(sourceBuffers, 'addsourcebuffer',
|
|
1847
|
+
onSourceBufferAdded);
|
|
1846
1848
|
}
|
|
1847
|
-
}
|
|
1849
|
+
};
|
|
1850
|
+
|
|
1851
|
+
this.eventManager_.listen(sourceBuffers, 'addsourcebuffer',
|
|
1852
|
+
onSourceBufferAdded);
|
|
1848
1853
|
|
|
1849
1854
|
for (const contentType of streamsByType.keys()) {
|
|
1850
1855
|
const stream = streamsByType.get(contentType);
|
|
@@ -1868,7 +1873,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1868
1873
|
this.destroyer_.ensureNotDestroyed();
|
|
1869
1874
|
|
|
1870
1875
|
this.eventManager_.listenOnce(this.video_, 'canplaythrough', () => {
|
|
1871
|
-
|
|
1876
|
+
// Don't use ensureNotDestroyed() from this event listener, because
|
|
1877
|
+
// that results in an uncaught exception. Instead, just check the
|
|
1878
|
+
// flag.
|
|
1879
|
+
if (this.destroyer_.destroyed()) {
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1872
1882
|
|
|
1873
1883
|
this.video_.autoplay = previousAutoPlayState;
|
|
1874
1884
|
if (!previousPausedState) {
|
package/lib/media/playhead.js
CHANGED
|
@@ -382,10 +382,10 @@ shaka.media.MediaSourcePlayhead = class {
|
|
|
382
382
|
seekStart = seekEnd - this.minSeekRange_;
|
|
383
383
|
}
|
|
384
384
|
|
|
385
|
-
if (currentTime < seekStart
|
|
386
|
-
//
|
|
385
|
+
if (currentTime < seekStart) {
|
|
386
|
+
// The seek range has moved past the playhead. Move ahead to catch up.
|
|
387
387
|
const targetTime = this.reposition_(currentTime);
|
|
388
|
-
shaka.log.info('Jumping
|
|
388
|
+
shaka.log.info('Jumping forward ' + (targetTime - currentTime) +
|
|
389
389
|
' seconds to catch up with the seek range.');
|
|
390
390
|
this.mediaElement_.currentTime = targetTime;
|
|
391
391
|
}
|
|
@@ -694,6 +694,16 @@ shaka.media.MetaSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
694
694
|
this.indexes_ = [];
|
|
695
695
|
}
|
|
696
696
|
|
|
697
|
+
/**
|
|
698
|
+
* @override
|
|
699
|
+
* @export
|
|
700
|
+
*/
|
|
701
|
+
forEachTopLevelReference(fn) {
|
|
702
|
+
for (const index of this.indexes_) {
|
|
703
|
+
index.forEachTopLevelReference(fn);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
697
707
|
/**
|
|
698
708
|
* @override
|
|
699
709
|
* @export
|
|
@@ -598,6 +598,18 @@ shaka.media.SegmentReference = class {
|
|
|
598
598
|
this.offset(offset);
|
|
599
599
|
}
|
|
600
600
|
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Updates the init segment reference and propagates the update to all partial
|
|
604
|
+
* references.
|
|
605
|
+
* @param {shaka.media.InitSegmentReference} initSegmentReference
|
|
606
|
+
*/
|
|
607
|
+
updateInitSegmentReference(initSegmentReference) {
|
|
608
|
+
this.initSegmentReference = initSegmentReference;
|
|
609
|
+
for (const partialReference of this.partialReferences) {
|
|
610
|
+
partialReference.updateInitSegmentReference(initSegmentReference);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
601
613
|
};
|
|
602
614
|
|
|
603
615
|
|
|
@@ -1733,9 +1733,16 @@ shaka.media.StreamingEngine = class {
|
|
|
1733
1733
|
otherState = this.mediaStates_.get(ContentType.VIDEO);
|
|
1734
1734
|
}
|
|
1735
1735
|
if (otherState) {
|
|
1736
|
+
// First, abort all operations in progress on the other stream.
|
|
1737
|
+
await this.abortOperations_(otherState).catch(() => {});
|
|
1738
|
+
// Then clear our cache of the last init segment, since MSE will be
|
|
1739
|
+
// reloaded and no init segment will be there post-reload.
|
|
1736
1740
|
otherState.lastInitSegmentReference = null;
|
|
1741
|
+
// Now force the existing buffer to be cleared. It is not necessary
|
|
1742
|
+
// to perform the MSE clear operation, but this has the side-effect
|
|
1743
|
+
// that our state for that stream will then match MSE's post-reload
|
|
1744
|
+
// state.
|
|
1737
1745
|
this.forceClearBuffer_(otherState);
|
|
1738
|
-
this.abortOperations_(otherState).catch(() => {});
|
|
1739
1746
|
}
|
|
1740
1747
|
}
|
|
1741
1748
|
|
|
@@ -1766,19 +1773,6 @@ shaka.media.StreamingEngine = class {
|
|
|
1766
1773
|
appendWindowEnd, ignoreTimestampOffset,
|
|
1767
1774
|
reference.mimeType || mediaState.stream.mimeType,
|
|
1768
1775
|
reference.codecs || mediaState.stream.codecs, streamsByType);
|
|
1769
|
-
if (isResetMediaSourceNecessary) {
|
|
1770
|
-
let otherState = null;
|
|
1771
|
-
if (mediaState.type === ContentType.VIDEO) {
|
|
1772
|
-
otherState = this.mediaStates_.get(ContentType.AUDIO);
|
|
1773
|
-
} else if (mediaState.type === ContentType.AUDIO) {
|
|
1774
|
-
otherState = this.mediaStates_.get(ContentType.VIDEO);
|
|
1775
|
-
}
|
|
1776
|
-
if (otherState) {
|
|
1777
|
-
otherState.waitingToClearBuffer = false;
|
|
1778
|
-
otherState.performingUpdate = false;
|
|
1779
|
-
this.forceClearBuffer_(otherState);
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
1776
|
} catch (error) {
|
|
1783
1777
|
mediaState.lastAppendWindowStart = null;
|
|
1784
1778
|
mediaState.lastAppendWindowEnd = null;
|
package/lib/player.js
CHANGED
|
@@ -1977,31 +1977,49 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1977
1977
|
this.config_.playRangeStart,
|
|
1978
1978
|
this.config_.playRangeEnd);
|
|
1979
1979
|
|
|
1980
|
-
this.playhead_ = this.createPlayhead(this.startTime_);
|
|
1981
|
-
this.playheadObservers_ =
|
|
1982
|
-
this.createPlayheadObserversForMSE_(startTimeOfLoad);
|
|
1983
1980
|
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1981
|
+
const setupPlayhead = (startTime) => {
|
|
1982
|
+
this.playhead_ = this.createPlayhead(startTime);
|
|
1983
|
+
this.playheadObservers_ =
|
|
1984
|
+
this.createPlayheadObserversForMSE_(startTimeOfLoad);
|
|
1985
|
+
|
|
1986
|
+
// We need to start the buffer management code near the end because it
|
|
1987
|
+
// will set the initial buffering state and that depends on other
|
|
1988
|
+
// components being initialized.
|
|
1989
|
+
const rebufferThreshold = Math.max(
|
|
1990
|
+
this.manifest_.minBufferTime,
|
|
1991
|
+
this.config_.streaming.rebufferingGoal);
|
|
1992
|
+
this.startBufferManagement_(mediaElement, rebufferThreshold);
|
|
1993
|
+
};
|
|
1994
|
+
|
|
1995
|
+
if (!this.config_.streaming.startAtSegmentBoundary) {
|
|
1996
|
+
setupPlayhead(this.startTime_);
|
|
1997
|
+
}
|
|
1990
1998
|
|
|
1991
1999
|
// Now we can switch to the initial variant.
|
|
1992
2000
|
if (!activeVariant) {
|
|
1993
2001
|
goog.asserts.assert(initialVariant,
|
|
1994
2002
|
'Must have choosen an initial variant!');
|
|
1995
2003
|
|
|
1996
|
-
this.switchVariant_(initialVariant, /* fromAdaptation= */ true,
|
|
1997
|
-
/* clearBuffer= */ false, /* safeMargin= */ 0);
|
|
1998
|
-
|
|
1999
2004
|
// Now that we have initial streams, we may adjust the start time to
|
|
2000
2005
|
// align to a segment boundary.
|
|
2001
2006
|
if (this.config_.streaming.startAtSegmentBoundary) {
|
|
2002
|
-
this.
|
|
2003
|
-
|
|
2007
|
+
const timeline = this.manifest_.presentationTimeline;
|
|
2008
|
+
let initialTime = this.startTime_ || this.video_.currentTime;
|
|
2009
|
+
const seekRangeStart = timeline.getSeekRangeStart();
|
|
2010
|
+
const seekRangeEnd = timeline.getSeekRangeEnd();
|
|
2011
|
+
if (initialTime < seekRangeStart) {
|
|
2012
|
+
initialTime = seekRangeStart;
|
|
2013
|
+
} else if (initialTime > seekRangeEnd) {
|
|
2014
|
+
initialTime = seekRangeEnd;
|
|
2015
|
+
}
|
|
2016
|
+
const startTime = await this.adjustStartTime_(
|
|
2017
|
+
initialVariant, initialTime);
|
|
2018
|
+
setupPlayhead(startTime);
|
|
2004
2019
|
}
|
|
2020
|
+
|
|
2021
|
+
this.switchVariant_(initialVariant, /* fromAdaptation= */ true,
|
|
2022
|
+
/* clearBuffer= */ false, /* safeMargin= */ 0);
|
|
2005
2023
|
}
|
|
2006
2024
|
|
|
2007
2025
|
this.playhead_.ready();
|
|
@@ -2316,6 +2334,15 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2316
2334
|
mediaElement.load();
|
|
2317
2335
|
}
|
|
2318
2336
|
|
|
2337
|
+
// In Safari using HLS won't load anything unless you call load()
|
|
2338
|
+
// explicitly, no matter the value of the preload attribute.
|
|
2339
|
+
// Note: this only happens when there are not autoplay.
|
|
2340
|
+
if (mediaElement.preload != 'none' && !mediaElement.autoplay &&
|
|
2341
|
+
shaka.util.MimeUtils.isHlsType(mimeType) &&
|
|
2342
|
+
shaka.util.Platform.safariVersion()) {
|
|
2343
|
+
mediaElement.load();
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2319
2346
|
// Set the load mode last so that we know that all our components are
|
|
2320
2347
|
// initialized.
|
|
2321
2348
|
this.loadMode_ = shaka.Player.LoadMode.SRC_EQUALS;
|
|
@@ -6960,7 +6987,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6960
6987
|
* @export
|
|
6961
6988
|
*/
|
|
6962
6989
|
// eslint-disable-next-line no-useless-concat
|
|
6963
|
-
shaka.Player.version = 'v4.7.
|
|
6990
|
+
shaka.Player.version = 'v4.7.14' + '-uncompiled'; // x-release-please-version
|
|
6964
6991
|
|
|
6965
6992
|
// Initialize the deprecation system using the version string we just set
|
|
6966
6993
|
// on the player.
|
|
@@ -72,7 +72,9 @@ shaka.text.UITextDisplayer = class {
|
|
|
72
72
|
|
|
73
73
|
/** @private {shaka.util.Timer} */
|
|
74
74
|
this.captionsTimer_ = new shaka.util.Timer(() => {
|
|
75
|
-
this.
|
|
75
|
+
if (!this.video_.paused) {
|
|
76
|
+
this.updateCaptions_();
|
|
77
|
+
}
|
|
76
78
|
}).tickEvery(updatePeriod);
|
|
77
79
|
|
|
78
80
|
/**
|
|
@@ -93,6 +95,10 @@ shaka.text.UITextDisplayer = class {
|
|
|
93
95
|
this.updateCaptions_(/* forceUpdate= */ true);
|
|
94
96
|
});
|
|
95
97
|
|
|
98
|
+
this.eventManager_.listen(this.video_, 'seeking', () => {
|
|
99
|
+
this.updateCaptions_(/* forceUpdate= */ true);
|
|
100
|
+
});
|
|
101
|
+
|
|
96
102
|
// From: https://html.spec.whatwg.org/multipage/media.html#dom-video-videowidth
|
|
97
103
|
// Whenever the natural width or natural height of the video changes
|
|
98
104
|
// (including, for example, because the selected video track was changed),
|
|
@@ -339,6 +345,9 @@ shaka.text.UITextDisplayer = class {
|
|
|
339
345
|
const cueRegistry = this.currentCuesMap_.get(cue);
|
|
340
346
|
goog.asserts.assert(cueRegistry, 'cueRegistry should exist.');
|
|
341
347
|
if (cueRegistry.regionElement) {
|
|
348
|
+
if (cueRegistry.regionElement.contains(container)) {
|
|
349
|
+
cueRegistry.regionElement.removeChild(container);
|
|
350
|
+
}
|
|
342
351
|
container.appendChild(cueRegistry.regionElement);
|
|
343
352
|
cueRegistry.regionElement.appendChild(cueRegistry.cueElement);
|
|
344
353
|
} else {
|
package/lib/util/platform.js
CHANGED
|
@@ -149,10 +149,9 @@ shaka.util.Platform = class {
|
|
|
149
149
|
* @return {boolean}
|
|
150
150
|
*/
|
|
151
151
|
static isWebOS3() {
|
|
152
|
-
// See:
|
|
153
|
-
return shaka.util.Platform.
|
|
154
|
-
shaka.util.Platform.
|
|
155
|
-
'Chrome/38.0.2125.122 Safari/537.36');
|
|
152
|
+
// See: https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine#useragent-string
|
|
153
|
+
return shaka.util.Platform.isWebOS() &&
|
|
154
|
+
shaka.util.Platform.chromeVersion() === 38;
|
|
156
155
|
}
|
|
157
156
|
|
|
158
157
|
/**
|
|
@@ -161,18 +160,20 @@ shaka.util.Platform = class {
|
|
|
161
160
|
* @return {boolean}
|
|
162
161
|
*/
|
|
163
162
|
static isWebOS4() {
|
|
164
|
-
// See:
|
|
165
|
-
return
|
|
163
|
+
// See: https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine#useragent-string
|
|
164
|
+
return shaka.util.Platform.isWebOS() &&
|
|
165
|
+
shaka.util.Platform.chromeVersion() === 53;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
/**
|
|
169
|
-
* Check if the current platform is a WebOS
|
|
169
|
+
* Check if the current platform is a WebOS 5.
|
|
170
170
|
*
|
|
171
171
|
* @return {boolean}
|
|
172
172
|
*/
|
|
173
173
|
static isWebOS5() {
|
|
174
|
-
// See:
|
|
175
|
-
return
|
|
174
|
+
// See: https://webostv.developer.lge.com/develop/specifications/web-api-and-web-engine#useragent-string
|
|
175
|
+
return shaka.util.Platform.isWebOS() &&
|
|
176
|
+
shaka.util.Platform.chromeVersion() === 68;
|
|
176
177
|
}
|
|
177
178
|
|
|
178
179
|
/**
|
|
@@ -184,6 +185,17 @@ shaka.util.Platform = class {
|
|
|
184
185
|
return shaka.util.Platform.userAgentContains_('CrKey');
|
|
185
186
|
}
|
|
186
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Check if the current platform is a Google Chromecast with Android
|
|
190
|
+
* (i.e. Chromecast with GoogleTV).
|
|
191
|
+
*
|
|
192
|
+
* @return {boolean}
|
|
193
|
+
*/
|
|
194
|
+
static isAndroidCastDevice() {
|
|
195
|
+
const Platform = shaka.util.Platform;
|
|
196
|
+
return Platform.isChromecast() && Platform.isAndroid();
|
|
197
|
+
}
|
|
198
|
+
|
|
187
199
|
/**
|
|
188
200
|
* Returns a major version number for Chrome, or Chromium-based browsers.
|
|
189
201
|
*
|
|
@@ -414,6 +426,9 @@ shaka.util.Platform = class {
|
|
|
414
426
|
return navigator.userAgentData.platform.toLowerCase() == 'macos';
|
|
415
427
|
}
|
|
416
428
|
// Fall back to the old API, with less strict matching.
|
|
429
|
+
if (!navigator.platform) {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
417
432
|
return navigator.platform.toLowerCase().includes('mac');
|
|
418
433
|
}
|
|
419
434
|
|
|
@@ -428,6 +443,9 @@ shaka.util.Platform = class {
|
|
|
428
443
|
return navigator.userAgentData.platform.toLowerCase() == 'windows';
|
|
429
444
|
}
|
|
430
445
|
// Fall back to the old API, with less strict matching.
|
|
446
|
+
if (!navigator.platform) {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
431
449
|
return navigator.platform.toLowerCase().includes('windows');
|
|
432
450
|
}
|
|
433
451
|
|
|
@@ -535,6 +553,10 @@ shaka.util.Platform = class {
|
|
|
535
553
|
Platform.isWebOS4() || Platform.isWebOS5()) {
|
|
536
554
|
return false;
|
|
537
555
|
}
|
|
556
|
+
// Older chromecasts without GoogleTV seem to not support SMOOTH properly.
|
|
557
|
+
if (Platform.isChromecast() && !Platform.isAndroidCastDevice()) {
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
538
560
|
// See: https://chromium-review.googlesource.com/c/chromium/src/+/4577759
|
|
539
561
|
if (Platform.isWindows() && Platform.isEdge()) {
|
|
540
562
|
return false;
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -973,8 +973,12 @@ shaka.util.StreamUtils = class {
|
|
|
973
973
|
// currently don't support 'fLaC', while 'flac' is supported by most
|
|
974
974
|
// major browsers.
|
|
975
975
|
// See https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
|
976
|
-
if (codecs
|
|
977
|
-
|
|
976
|
+
if (codecs.toLowerCase() == 'flac') {
|
|
977
|
+
if (!shaka.util.Platform.isSafari()) {
|
|
978
|
+
return 'flac';
|
|
979
|
+
} else {
|
|
980
|
+
return 'fLaC';
|
|
981
|
+
}
|
|
978
982
|
}
|
|
979
983
|
|
|
980
984
|
// The same is true for 'Opus'.
|
package/package.json
CHANGED
|
@@ -96,6 +96,7 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
|
|
|
96
96
|
} else {
|
|
97
97
|
otherIdx = tracks.findIndex((t) => {
|
|
98
98
|
return t.height == track.height &&
|
|
99
|
+
t.videoBandwidth == track.videoBandwidth &&
|
|
99
100
|
t.frameRate == track.frameRate &&
|
|
100
101
|
t.hdr == track.hdr &&
|
|
101
102
|
t.videoLayout == track.videoLayout;
|