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: '',