Skip to content

Commit

Permalink
Move availabilityWindowOverride to manifest parsers
Browse files Browse the repository at this point in the history
This reverts the implementation to an earlier draft state.  During
review of the first version, I recommended moving the implementation
to Player so that it would be independent of the manifest parsers.
That was bad advice on my part, because this overlooked updates made
by the parsers when live manifests are updated later.

Closes #1177
Closes #1307

Change-Id: I4611e00824dead83c6467da04a2a11afa892ace7
  • Loading branch information
joeyparrish committed Jul 20, 2018
1 parent 3dbe49b commit ecd27fb
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 51 deletions.
4 changes: 3 additions & 1 deletion externs/shaka/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,9 @@ shaka.extern.DashManifestConfiguration;
* 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.
* manifest, or NaN if the default value should be used. This is enforced by
* the manifest parser, so custom manifest parsers should take care to honor
* this parameter.
* @property {shaka.extern.DashManifestConfiguration} dash
* Advanced parameters used by the DASH manifest parser.
*
Expand Down
21 changes: 16 additions & 5 deletions lib/dash/dash_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -550,10 +550,23 @@ shaka.dash.DashParser.prototype.processManifest_ =
// Ignore duration calculated from Period lengths if this is dynamic.
presentationTimeline.setDuration(duration || Infinity);
}

let isLive = presentationTimeline.isLive();

// If it's live, we check for an override.
if (isLive && !isNaN(this.config_.availabilityWindowOverride)) {
segmentAvailabilityDuration = this.config_.availabilityWindowOverride;
}

// If it's null, that means segments are always available. This is always the
// case for VOD, and sometimes the case for live.
if (segmentAvailabilityDuration == null) {
segmentAvailabilityDuration = Infinity;
}

presentationTimeline.setSegmentAvailabilityDuration(
segmentAvailabilityDuration != null ?
segmentAvailabilityDuration :
Infinity);
segmentAvailabilityDuration);

// Use @maxSegmentDuration to override smaller, derived values.
presentationTimeline.notifyMaxSegmentDuration(maxSegmentDuration || 1);
if (goog.DEBUG) presentationTimeline.assertIsValid();
Expand All @@ -567,8 +580,6 @@ shaka.dash.DashParser.prototype.processManifest_ =
// the clock offset.
let timingElements = XmlUtils.findChildren(mpd, 'UTCTiming');

let isLive = presentationTimeline.isLive();

return this.parseUtcTiming_(
baseUris, timingElements, isLive).then(function(offset) {
// Detect calls to stop().
Expand Down
7 changes: 6 additions & 1 deletion lib/hls/hls_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,14 @@ shaka.hls.HlsParser.prototype.parseManifest_ = function(data, uri) {
// will be able to buffer ahead three segments, but the seek window will
// be zero-sized.
const PresentationType = shaka.hls.HlsParser.PresentationType_;

if (this.presentationType_ == PresentationType.LIVE) {
let segmentAvailabilityDuration = threeSegmentDurations;
if (!isNaN(this.config_.availabilityWindowOverride)) {
segmentAvailabilityDuration = this.config_.availabilityWindowOverride;
}
this.presentationTimeline_.setSegmentAvailabilityDuration(
threeSegmentDurations);
segmentAvailabilityDuration);
}

let rolloverSeconds =
Expand Down
5 changes: 0 additions & 5 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -733,11 +733,6 @@ 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();
Expand Down
49 changes: 49 additions & 0 deletions test/dash/dash_parser_live_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,55 @@ describe('DashParser Live', function() {
PromiseMock.flush();
});

describe('availabilityWindowOverride', function() {
it('overrides @timeShiftBufferDepth', function(done) {
let manifest = [
'<MPD type="dynamic" suggestedPresentationDelay="PT60S"',
' minimumUpdatePeriod="PT5S"',
' timeShiftBufferDepth="PT2M"',
' maxSegmentDuration="PT10S"',
' availabilityStartTime="1970-01-01T00:05:00Z">',
' <Period id="1">',
' <AdaptationSet mimeType="video/mp4">',
' <Representation id="3" bandwidth="500">',
' <BaseURL>http://example.com</BaseURL>',
' <SegmentTemplate media="s$Number$.mp4" duration="2" />',
' </Representation>',
' </AdaptationSet>',
' </Period>',
'</MPD>',
].join('\n');
fakeNetEngine.setResponseMapAsText({'dummy://foo': manifest});

parser.configure({
retryParameters: shaka.net.NetworkingEngine.defaultRetryParameters(),
availabilityWindowOverride: 4 * 60,
dash: {
clockSyncUri: '',
customScheme: function(node) { return null; },
ignoreDrmInfo: false,
xlinkFailGracefully: false,
defaultPresentationDelay: 10,
},
});

Date.now = function() { return 600000; /* 10 minutes */ };
parser.start('dummy://foo', playerInterface)
.then(function(manifest) {
expect(manifest).toBeTruthy();
let timeline = manifest.presentationTimeline;
expect(timeline).toBeTruthy();

// The parser was configured to have a manifest availability window
// of 4 minutes.
let end = timeline.getSegmentAvailabilityEnd();
let start = timeline.getSegmentAvailabilityStart();
expect(end - start).toEqual(4 * 60);
}).catch(fail).then(done);
PromiseMock.flush();
});
});

describe('maxSegmentDuration', function() {
it('uses @maxSegmentDuration', function(done) {
let manifest = [
Expand Down
53 changes: 53 additions & 0 deletions test/hls/hls_live_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,17 @@ describe('HlsParser live', function() {
'test:/main2.mp4\n',
].join('');

let mediaWithManySegments = [
'#EXTM3U\n',
'#EXT-X-TARGETDURATION:5\n',
'#EXT-X-MAP:URI="test:/init.mp4",BYTERANGE="616@0"\n',
'#EXT-X-MEDIA-SEQUENCE:0\n',
].join('');
for (let i = 0; i < 1000; ++i) {
mediaWithManySegments += '#EXTINF:2,\n';
mediaWithManySegments += 'test:/main.mp4\n';
}

it('starts presentation as VOD when ENDLIST is present', function(done) {
fakeNetEngine.setResponseMap({
'test:/master': toUTF8(master),
Expand All @@ -455,6 +466,48 @@ describe('HlsParser live', function() {
parser.start('test:/master', playerInterface).catch(fail).then(done);
});

describe('availabilityWindowOverride', function() {
async function testWindowOverride(expectedWindow) {
fakeNetEngine.setResponseMap({
'test:/master': toUTF8(master),
'test:/video': toUTF8(mediaWithManySegments),
'test:/init.mp4': initSegmentData,
'test:/main.mp4': segmentData,
});

let manifest = await parser.start('test:/master', playerInterface);
expect(manifest).toBeTruthy();
let timeline = manifest.presentationTimeline;
expect(timeline).toBeTruthy();

const start = timeline.getSegmentAvailabilityStart();
const end = timeline.getSegmentAvailabilityEnd();
expect(end - start).toEqual(expectedWindow);
}

it('does not affect seek range if unset', async () => {
// 15 seconds is three segment durations.
await testWindowOverride(15);
});

it('overrides default seek range if set', async () => {
parser.configure({
retryParameters: shaka.net.NetworkingEngine.defaultRetryParameters(),
availabilityWindowOverride: 240,
dash: {
customScheme: function(node) { return null; },
clockSyncUri: '',
ignoreDrmInfo: false,
xlinkFailGracefully: false,
defaultPresentationDelay: 10,
},
});

// 240 is the availabilityWindowOverride setting.
await testWindowOverride(240);
});
});

it('offsets VTT text with rolled over TS timestamps', function(done) {
const masterWithVtt = [
'#EXTM3U\n',
Expand Down
39 changes: 0 additions & 39 deletions test/player_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -3135,45 +3135,6 @@ 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() {
Expand Down

0 comments on commit ecd27fb

Please sign in to comment.