diff --git a/demo/asset_section.js b/demo/asset_section.js
index 53c37a06b4..9aaad9e6a5 100644
--- a/demo/asset_section.js
+++ b/demo/asset_section.js
@@ -255,6 +255,16 @@ shakaDemo.preparePlayer_ = function(asset) {
if (!isNaN(preferredAudioChannelCount)) {
config.preferredAudioChannelCount = preferredAudioChannelCount;
}
+ let availabilityWindowOverrideRaw =
+ document.getElementById('availabilityWindowOverride').value;
+ let availabilityWindowOverride = Number(availabilityWindowOverrideRaw);
+ if (!isNaN(availabilityWindowOverride) &&
+ availabilityWindowOverrideRaw.length) {
+ // Don't configure if the field contains an empty string; this is because
+ // Number('') evaluates to 0, which is a valid (if fairly useless) override
+ // value, while we would rather it mean "don't override".
+ config.manifest.availabilityWindowOverride = availabilityWindowOverride;
+ }
config.abr.enabled =
document.getElementById('enableAdaptation').checked;
diff --git a/demo/configuration_section.js b/demo/configuration_section.js
index c7ae1fbd02..b4e1874cfb 100644
--- a/demo/configuration_section.js
+++ b/demo/configuration_section.js
@@ -53,6 +53,8 @@ shakaDemo.setupConfiguration_ = function() {
'input', shakaDemo.onDrmSettingsChange_);
document.getElementById('drmSettingsAudioRobustness').addEventListener(
'input', shakaDemo.onDrmSettingsChange_);
+ document.getElementById('availabilityWindowOverride').addEventListener(
+ 'input', shakaDemo.onAvailabilityWindowOverrideChange_);
let robustnessSuggestions = document.getElementById('robustnessSuggestions');
if (shakaDemo.support_.drm['com.widevine.alpha']) {
@@ -86,6 +88,16 @@ shakaDemo.onDrmSettingsChange_ = function(event) {
};
+/**
+ * @param {!Event} event
+ * @private
+ */
+shakaDemo.onAvailabilityWindowOverrideChange_ = function(event) {
+ // Change the hash, to mirror this.
+ shakaDemo.hashShouldChange_();
+};
+
+
/**
* @param {!Event} event
* @private
diff --git a/demo/index.html b/demo/index.html
index d040c9e1d0..af87ae09e1 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -221,6 +221,10 @@
Shaka Player
+
+
+
+
diff --git a/demo/main.js b/demo/main.js
index afe799c148..970efca577 100644
--- a/demo/main.js
+++ b/demo/main.js
@@ -288,6 +288,10 @@ shakaDemo.preBrowserCheckParams_ = function(params) {
if ('certificate' in params) {
document.getElementById('certificateInput').value = params['certificate'];
}
+ if ('availabilityWindowOverride' in params) {
+ document.getElementById('availabilityWindowOverride').value =
+ params['availabilityWindowOverride'];
+ }
if ('logtoscreen' in params) {
document.getElementById('logToScreen').checked = true;
// Call onLogChange_ manually, because setting checked
@@ -581,6 +585,11 @@ shakaDemo.hashShouldChange_ = function() {
if (document.getElementById('showNative').checked) {
params.push('nativecontrols');
}
+ let availabilityWindowOverride =
+ document.getElementById('availabilityWindowOverride').value;
+ if (availabilityWindowOverride) {
+ params.push('availabilityWindowOverride=' + availabilityWindowOverride);
+ }
if (shaka.log) {
let logLevelList = document.getElementById('logLevelList');
let logLevel = logLevelList[logLevelList.selectedIndex].value;
diff --git a/externs/shaka/player.js b/externs/shaka/player.js
index eb43b6045b..b5cfde0054 100644
--- a/externs/shaka/player.js
+++ b/externs/shaka/player.js
@@ -529,11 +529,15 @@ shaka.extern.DashManifestConfiguration;
/**
* @typedef {{
* retryParameters: shaka.extern.RetryParameters,
+ * availabilityWindowOverride: number,
* dash: shaka.extern.DashManifestConfiguration
* }}
*
* @property {shaka.extern.RetryParameters} retryParameters
* Retry parameters for manifest requests.
+ * @property (number) availabilityWindowOverride
+ * A number, in seconds, that overrides the availability window in the
+ * manifest, or NaN if the default value should be used.
* @property {shaka.extern.DashManifestConfiguration} dash
* Advanced parameters used by the DASH manifest parser.
*
diff --git a/lib/player.js b/lib/player.js
index 10a73fee5b..0045319d2e 100644
--- a/lib/player.js
+++ b/lib/player.js
@@ -729,6 +729,11 @@ shaka.Player.prototype.load = async function(
if (cancelValue) throw cancelValue;
+ if (!isNaN(this.config_.manifest.availabilityWindowOverride)) {
+ this.manifest_.presentationTimeline.setSegmentAvailabilityDuration(
+ this.config_.manifest.availabilityWindowOverride);
+ }
+
this.filterManifestForAVVariants_();
this.drmEngine_ = this.createDrmEngine();
@@ -2290,6 +2295,7 @@ shaka.Player.prototype.defaultConfig_ = function() {
},
manifest: {
retryParameters: shaka.net.NetworkingEngine.defaultRetryParameters(),
+ availabilityWindowOverride: NaN,
dash: {
customScheme: function(node) {
// Reference node to keep closure from removing it.
diff --git a/test/dash/dash_parser_content_protection_unit.js b/test/dash/dash_parser_content_protection_unit.js
index e4b0cad145..a567eac506 100644
--- a/test/dash/dash_parser_content_protection_unit.js
+++ b/test/dash/dash_parser_content_protection_unit.js
@@ -38,6 +38,7 @@ describe('DashParser ContentProtection', function() {
callback = callback || function(node) { return null; };
dashParser.configure({
retryParameters: retry,
+ availabilityWindowOverride: NaN,
dash: {
clockSyncUri: '',
customScheme: callback,
diff --git a/test/dash/dash_parser_live_unit.js b/test/dash/dash_parser_live_unit.js
index dfff7d9546..cf0271e41e 100644
--- a/test/dash/dash_parser_live_unit.js
+++ b/test/dash/dash_parser_live_unit.js
@@ -44,6 +44,7 @@ describe('DashParser Live', function() {
parser = new shaka.dash.DashParser();
parser.configure({
retryParameters: retry,
+ availabilityWindowOverride: NaN,
dash: {
clockSyncUri: '',
customScheme: function(node) { return null; },
diff --git a/test/hls/hls_live_unit.js b/test/hls/hls_live_unit.js
index b46501980b..c88251b5c3 100644
--- a/test/hls/hls_live_unit.js
+++ b/test/hls/hls_live_unit.js
@@ -120,6 +120,7 @@ describe('HlsParser live', function() {
let retry = shaka.net.NetworkingEngine.defaultRetryParameters();
config = {
retryParameters: retry,
+ availabilityWindowOverride: NaN,
dash: {
customScheme: function(node) { return null; },
clockSyncUri: '',
diff --git a/test/hls/hls_parser_unit.js b/test/hls/hls_parser_unit.js
index 85e1948521..d420ae608a 100644
--- a/test/hls/hls_parser_unit.js
+++ b/test/hls/hls_parser_unit.js
@@ -86,6 +86,7 @@ describe('HlsParser', function() {
let retry = shaka.net.NetworkingEngine.defaultRetryParameters();
config = {
retryParameters: retry,
+ availabilityWindowOverride: NaN,
dash: {
customScheme: function(node) { return null; },
clockSyncUri: '',
diff --git a/test/player_unit.js b/test/player_unit.js
index 95acebbf97..37da58feba 100644
--- a/test/player_unit.js
+++ b/test/player_unit.js
@@ -3135,6 +3135,45 @@ describe('Player', function() {
});
});
+ describe('live', function() {
+ function availabilityWindowTest(expectedAvailabilityWindow) {
+ // Create a live timeline and manifest.
+ let timeline = new shaka.media.PresentationTimeline(300, 0);
+ timeline.setStatic(false);
+ timeline.setSegmentAvailabilityDuration(100);
+
+ manifest = new shaka.test.ManifestGenerator()
+ .setTimeline(timeline)
+ .addPeriod(0)
+ .addVariant(0)
+ .addVideo(1)
+ .build();
+
+ let parser = new shaka.test.FakeManifestParser(manifest);
+ let parserFactory = function() { return parser; };
+
+ return player.load('', /* startTime */ 0, parserFactory).then(() => {
+ // Availability window can be determined by finding the time difference
+ // between the avalability end and start. Thus, we can compare the
+ // expected and actual window.
+ let end = timeline.getSegmentAvailabilityEnd();
+ expect(end - timeline.getSegmentAvailabilityStart())
+ .toBeCloseTo(expectedAvailabilityWindow, 1);
+ });
+ }
+
+ it('uses normal availability window when not overridden', async () => {
+ // The availability start should be what was in the timeline (100).
+ await availabilityWindowTest(100);
+ });
+
+ it('honors availabilityWindowOverride', async () => {
+ player.configure({manifest: {availabilityWindowOverride: 200}});
+ // The availability start should be what was configured (200).
+ await availabilityWindowTest(200);
+ });
+ });
+
describe('language methods', function() {
let videoOnlyManifest;
let parserFactory = function() {
diff --git a/test/test/util/dash_parser_util.js b/test/test/util/dash_parser_util.js
index 7de6e87108..6cd5850236 100644
--- a/test/test/util/dash_parser_util.js
+++ b/test/test/util/dash_parser_util.js
@@ -27,6 +27,7 @@ shaka.test.Dash.makeDashParser = function() {
let parser = new shaka.dash.DashParser();
parser.configure({
retryParameters: retry,
+ availabilityWindowOverride: NaN,
dash: {
customScheme: function(node) { return null; },
clockSyncUri: '',