Skip to content

Commit

Permalink
fix: program date time handling (#45)
Browse files Browse the repository at this point in the history
* update m3u8-parser to v4.2.0
* use segment program date time info
  • Loading branch information
mjneil committed Mar 2, 2018
1 parent a0cea44 commit 2609d01
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 17 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@
"dependencies": {
"aes-decrypter": "1.0.3",
"global": "^4.3.0",
"m3u8-parser": "2.1.0",
"mpd-parser": "0.4.0",
"m3u8-parser": "4.2.0",
"mux.js": "4.3.2",
"url-toolkit": "^2.1.3",
"video.js": "^6.2.0",
Expand Down
46 changes: 35 additions & 11 deletions src/sync-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,38 @@ export const syncPointStrategies = [
{
name: 'ProgramDateTime',
run: (syncController, playlist, duration, currentTimeline, currentTime) => {
if (syncController.datetimeToDisplayTime && playlist.dateTimeObject) {
let playlistTime = playlist.dateTimeObject.getTime() / 1000;
let playlistStart = playlistTime + syncController.datetimeToDisplayTime;
let syncPoint = {
time: playlistStart,
segmentIndex: 0
};
if (!syncController.datetimeToDisplayTime) {
return null;
}

return syncPoint;
let segments = playlist.segments || [];
let syncPoint = null;
let lastDistance = null;

currentTime = currentTime || 0;

for (let i = 0; i < segments.length; i++) {
let segment = segments[i];

if (segment.dateTimeObject) {
let segmentTime = segment.dateTimeObject.getTime() / 1000;
let segmentStart = segmentTime + syncController.datetimeToDisplayTime;
let distance = Math.abs(currentTime - segmentStart);

// Once the distance begins to increase, we have passed
// currentTime and can stop looking for better candidates
if (lastDistance !== null && lastDistance < distance) {
break;
}

lastDistance = distance;
syncPoint = {
time: segmentStart,
segmentIndex: i
};
}
}
return null;
return syncPoint;
}
},
// Stategy "Segment": We have a known time mapping for a timeline and a
Expand Down Expand Up @@ -336,8 +357,11 @@ export default class SyncController extends videojs.EventTarget {
* @param {Playlist} playlist - The currently active playlist
*/
setDateTimeMapping(playlist) {
if (!this.datetimeToDisplayTime && playlist.dateTimeObject) {
let playlistTimestamp = playlist.dateTimeObject.getTime() / 1000;
if (!this.datetimeToDisplayTime &&
playlist.segments &&
playlist.segments.length &&
playlist.segments[0].dateTimeObject) {
let playlistTimestamp = playlist.segments[0].dateTimeObject.getTime() / 1000;

this.datetimeToDisplayTime = -playlistTimestamp;
}
Expand Down
56 changes: 54 additions & 2 deletions test/sync-controller.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ QUnit.test('returns correct sync point for ProgramDateTime strategy', function(a

assert.equal(syncPoint, null, 'no syncpoint when datetimeToDisplayTime not set');

playlist.dateTimeObject = datetime;
playlist.segments[0].dateTimeObject = datetime;

this.syncController.setDateTimeMapping(playlist);

Expand All @@ -56,7 +56,7 @@ QUnit.test('returns correct sync point for ProgramDateTime strategy', function(a

assert.equal(syncPoint, null, 'no syncpoint when datetimeObject not set on playlist');

newPlaylist.dateTimeObject = new Date(2012, 11, 12, 12, 12, 22);
newPlaylist.segments[0].dateTimeObject = new Date(2012, 11, 12, 12, 12, 22);

syncPoint = strategy.run(this.syncController, newPlaylist, duration, timeline);

Expand All @@ -66,6 +66,58 @@ QUnit.test('returns correct sync point for ProgramDateTime strategy', function(a
}, 'syncpoint found for ProgramDateTime set');
});

QUnit.test('ProgramDateTime strategy finds nearest segment for sync', function(assert) {
let strategy = getStrategy('ProgramDateTime');
let playlist = playlistWithDuration(40);
let timeline = 0;
let duration = Infinity;
let syncPoint;

syncPoint = strategy.run(this.syncController, playlist, duration, timeline, 23);

assert.equal(syncPoint, null, 'no syncpoint when datetimeToDisplayTime not set');

playlist.segments.forEach((segment, index) => {
segment.dateTimeObject = new Date(2012, 11, 12, 12, 12, 12 + (index * 10));
});

this.syncController.setDateTimeMapping(playlist);

let newPlaylist = playlistWithDuration(40);

syncPoint = strategy.run(this.syncController, newPlaylist, duration, timeline);

assert.equal(syncPoint, null, 'no syncpoint when datetimeObject not set on playlist');

newPlaylist.segments.forEach((segment, index) => {
segment.dateTimeObject = new Date(2012, 11, 12, 12, 12, 22 + (index * 10));
});

syncPoint = strategy.run(this.syncController, newPlaylist, duration, timeline, 23);

assert.deepEqual(syncPoint, {
time: 20,
segmentIndex: 1
}, 'syncpoint found for ProgramDateTime set');
});

QUnit.test('Does not set date time mapping if date time info not on first segment',
function(assert) {
let playlist = playlistWithDuration(40);

playlist.segments[1].dateTimeObject = new Date(2012, 11, 12, 12, 12, 12);

this.syncController.setDateTimeMapping(playlist);

assert.notOk(this.syncController.datetimeToDisplayTime, 'did not set datetime mapping');

playlist.segments[0].dateTimeObject = new Date(2012, 11, 12, 12, 12, 2);

this.syncController.setDateTimeMapping(playlist);

assert.ok(this.syncController.datetimeToDisplayTime, 'did set date time mapping');
});

QUnit.test('returns correct sync point for Segment strategy', function(assert) {
let strategy = getStrategy('Segment');
let playlist = {
Expand Down

0 comments on commit 2609d01

Please sign in to comment.