Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
mangui committed Mar 8, 2016
2 parents 0008862 + b669f83 commit 87c4a49
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 3 deletions.
17 changes: 17 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,23 @@ if set to 10, the player will seek back to ```liveSyncDurationCount``` whenever
If set, this value must be stricly superior to ```liveSyncDurationCount```
a value too close from ```liveSyncDurationCount``` is likely to cause playback stalls.
#### ```liveSyncDuration```
(default undefined)
Alternative parameter to ```liveSyncDurationCount```, expressed in seconds vs number of segments.
If defined in the configuration object, ```liveSyncDuration``` will take precedence over the default```liveSyncDurationCount```.
You can't define this parameter and either ```liveSyncDurationCount``` or ```liveMaxLatencyDurationCount``` in your configuration object at the same time.
A value too low (inferior to ~3 segment durations) is likely to cause playback stalls.
#### ```liveMaxLatencyDuration```
(default undefined)
Alternative parameter to ```liveMaxLatencyDurationCount```, expressed in seconds vs number of segments.
If defined in the configuration object, ```liveMaxLatencyDuration``` will take precedence over the default```liveMaxLatencyDurationCount```.
If set, this value must be stricly superior to ```liveSyncDuration``` which must be defined as well.
You can't define this parameter and either ```liveSyncDurationCount``` or ```liveMaxLatencyDurationCount``` in your configuration object at the same time.
A value too close from ```liveSyncDuration``` is likely to cause playback stalls.
#### ```enableWorker```
(default true)
Expand Down
10 changes: 7 additions & 3 deletions src/controller/stream-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,11 @@ class StreamController extends EventHandler {
if (levelDetails.live) {
// check if requested position is within seekable boundaries :
//logger.log(`start/pos/bufEnd/seeking:${start.toFixed(3)}/${pos.toFixed(3)}/${bufferEnd.toFixed(3)}/${this.media.seeking}`);
if (bufferEnd < Math.max(start,end-config.liveMaxLatencyDurationCount*levelDetails.targetduration)) {
this.seekAfterBuffered = start + Math.max(0, levelDetails.totalduration - config.liveSyncDurationCount * levelDetails.targetduration);
let maxLatency = config.liveMaxLatencyDuration !== undefined ? config.liveMaxLatencyDuration : config.liveMaxLatencyDurationCount*levelDetails.targetduration;

if (bufferEnd < Math.max(start, end - maxLatency)) {
let targetLatency = config.liveSyncDuration !== undefined ? config.liveSyncDuration : config.liveSyncDurationCount * levelDetails.targetduration;
this.seekAfterBuffered = start + Math.max(0, levelDetails.totalduration - targetLatency);
logger.log(`buffer end: ${bufferEnd} is located too far from the end of live sliding playlist, media position will be reseted to: ${this.seekAfterBuffered.toFixed(3)}`);
bufferEnd = this.seekAfterBuffered;
}
Expand Down Expand Up @@ -773,7 +776,8 @@ class StreamController extends EventHandler {
if (this.startFragRequested === false) {
// if live playlist, set start position to be fragment N-this.config.liveSyncDurationCount (usually 3)
if (newDetails.live) {
this.startPosition = Math.max(0, sliding + duration - this.config.liveSyncDurationCount * newDetails.targetduration);
let targetLatency = this.config.liveSyncDuration !== undefined ? this.config.liveSyncDuration : this.config.liveSyncDurationCount * newDetails.targetduration;
this.startPosition = Math.max(0, sliding + duration - targetLatency);
}
this.nextLoadPosition = this.startPosition;
}
Expand Down
11 changes: 11 additions & 0 deletions src/hls.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class Hls {
maxSeekHole: 2,
liveSyncDurationCount:3,
liveMaxLatencyDurationCount: Infinity,
liveSyncDuration: undefined,
liveMaxLatencyDuration: undefined,
maxMaxBufferLength: 600,
enableWorker: true,
enableSoftwareAES: true,
Expand Down Expand Up @@ -84,6 +86,11 @@ class Hls {

constructor(config = {}) {
var defaultConfig = Hls.DefaultConfig;

if ((config.liveSyncDurationCount || config.liveMaxLatencyDurationCount) && (config.liveSyncDuration || config.liveMaxLatencyDuration)) {
throw new Error('Illegal hls.js config: don\'t mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration');
}

for (var prop in defaultConfig) {
if (prop in config) { continue; }
config[prop] = defaultConfig[prop];
Expand All @@ -93,6 +100,10 @@ class Hls {
throw new Error('Illegal hls.js config: "liveMaxLatencyDurationCount" must be gt "liveSyncDurationCount"');
}

if (config.liveMaxLatencyDuration !== undefined && (config.liveMaxLatencyDuration <= config.liveSyncDuration || config.liveSyncDuration === undefined)) {
throw new Error('Illegal hls.js config: "liveMaxLatencyDuration" must be gt "liveSyncDuration"');
}

enableLogs(config.debug);
this.config = config;
// observer setup
Expand Down
52 changes: 52 additions & 0 deletions tests/unit/demux/tsdemuxer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const assert = require('assert');
const bufferIsEqual = require('arraybuffer-equal');

import TSDemuxer from '../../../src/demux/tsdemuxer';
import Hls from '../../../src/hls';


class FakeRemuxer {
constructor() {
this.switchLevel__count = 0;
this.insertDiscontinuity__count = 0;
}
switchLevel() { this.switchLevel__count++; }
insertDiscontinuity() { this.insertDiscontinuity__count++; }
remux() {}
}


describe('TS Demuxer', () => {

var demuxer = new TSDemuxer(new Hls(), FakeRemuxer);

it('can probe for valid and invalid TS fragments', () => {
assert.equal(TSDemuxer.probe(validTSFragment), true);
assert.equal(TSDemuxer.probe(new Uint8Array([])), false);
});
// demuxer.push(data,audioCodec,videoCodec,timeOffset,cc,level,sn,duration);

it('detects a discontinuity', () => {
var cc;

// Initial feeds of data should not attempt to insert a discontinuity
cc = 0;
demuxer.push([], 'a', 'v', 0, cc, 0, 0, 0)
assert.equal(demuxer.remuxer.insertDiscontinuity__count, 0);
demuxer.push([], 'a', 'v', 0, cc, 0, 0, 0)
assert.equal(demuxer.remuxer.insertDiscontinuity__count, 0);

// Noticing a change to the continuity counter should trigger a remuxer discontinuity insertion
cc = 1;
demuxer.push([], 'a', 'v', 0, cc, 0, 0, 0)
assert.equal(demuxer.remuxer.insertDiscontinuity__count, 1);
});

});



// Grabbed the first 3*188 bytes from the sample at
// http://www.streambox.fr/playlists/x36xhzz/x36xhzz.m3u8
const validTSFragment = new Uint8Array([71,64,17,16,0,66,240,42,0,1,193,0,0,0,1,255,0,1,252,128,25,72,23,1,10,108,117,109,98,101,114,106,97,99,107,10,108,117,109,98,101,114,106,97,99,107,181,55,220,162,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,71,64,0,16,0,0,176,13,0,1,193,0,0,0,1,225,0,232,249,94,125,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,71,65,0,16,0,2,176,23,0,1,193,0,0,225,2,240,0,15,225,1,240,0,27,225,2,240,0,36,225,253,208,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]);

25 changes: 25 additions & 0 deletions tests/unit/loader/playlist-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,5 +321,30 @@ lo008ts`;
assert.strictEqual(result.fragments[9].byteRangeEndOffset,817988);
});

it('parses discontinuity and maintains continuity counter', () => {
var level = `#EXTM3U
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10,
0001.ts
#EXTINF:10,
0002.ts
#EXTINF:5,
0003.ts
#EXT-X-DISCONTINUITY
#EXTINF:10,
0005.ts
#EXTINF:10,
0006.ts
#EXT-X-ENDLIST
`;
var result = new PlaylistLoader({on : function() { }}).parseLevelPlaylist(level, 'http://video.example.com/disc.m3u8',0);
assert.strictEqual(result.fragments.length, 5);
assert.strictEqual(result.totalduration, 45);
assert.strictEqual(result.fragments[2].cc, 0);
assert.strictEqual(result.fragments[3].cc, 1); //continuity counter should increase around discontinuity
});

});

0 comments on commit 87c4a49

Please sign in to comment.