123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- import QUnit from 'qunit';
- import {
- default as SyncController,
- syncPointStrategies as strategies } from '../src/sync-controller.js';
- import { playlistWithDuration } from './test-helpers.js';
- function getStrategy(name) {
- for (let i = 0; i < strategies.length; i++) {
- if (strategies[i].name === name) {
- return strategies[i];
- }
- }
- throw new Error('No sync-strategy named "${name}" was found!');
- }
- QUnit.module('SyncController', {
- beforeEach() {
- this.syncController = new SyncController();
- }
- });
- QUnit.test('returns correct sync point for VOD strategy', function(assert) {
- let playlist = playlistWithDuration(40);
- let duration = 40;
- let timeline = 0;
- let vodStrategy = getStrategy('VOD');
- let syncPoint = vodStrategy.run(this.syncController, playlist, duration, timeline);
- assert.deepEqual(syncPoint, { time: 0, segmentIndex: 0 }, 'sync point found for vod');
- duration = Infinity;
- syncPoint = vodStrategy.run(this.syncController, playlist, duration, timeline);
- assert.equal(syncPoint, null, 'no syncpoint found for non vod ');
- });
- QUnit.test('returns correct sync point for ProgramDateTime strategy', function(assert) {
- let strategy = getStrategy('ProgramDateTime');
- let datetime = new Date(2012, 11, 12, 12, 12, 12);
- let playlist = playlistWithDuration(40);
- let timeline = 0;
- let duration = Infinity;
- let syncPoint;
- syncPoint = strategy.run(this.syncController, playlist, duration, timeline);
- assert.equal(syncPoint, null, 'no syncpoint when datetimeToDisplayTime not set');
- playlist.dateTimeObject = datetime;
- 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.dateTimeObject = new Date(2012, 11, 12, 12, 12, 22);
- syncPoint = strategy.run(this.syncController, newPlaylist, duration, timeline);
- assert.deepEqual(syncPoint, {
- time: 10,
- segmentIndex: 0
- }, 'syncpoint found for ProgramDateTime set');
- });
- QUnit.test('returns correct sync point for Segment strategy', function(assert) {
- let strategy = getStrategy('Segment');
- let playlist = {
- segments: [
- { timeline: 0 },
- { timeline: 0 },
- { timeline: 1, start: 10 },
- { timeline: 1, start: 20 },
- { timeline: 1 },
- { timeline: 1 },
- { timeline: 1, start: 50 },
- { timeline: 1, start: 60 }
- ]
- };
- let currentTimeline;
- let syncPoint;
- currentTimeline = 0;
- syncPoint = strategy.run(this.syncController, playlist, 80, currentTimeline, 0);
- assert.equal(syncPoint, null, 'no syncpoint for timeline 0');
- currentTimeline = 1;
- syncPoint = strategy.run(this.syncController, playlist, 80, currentTimeline, 30);
- assert.deepEqual(syncPoint, { time: 20, segmentIndex: 3 },
- 'closest sync point found');
- syncPoint = strategy.run(this.syncController, playlist, 80, currentTimeline, 40);
- assert.deepEqual(syncPoint, { time: 50, segmentIndex: 6 },
- 'closest sync point found');
- syncPoint = strategy.run(this.syncController, playlist, 80, currentTimeline, 50);
- assert.deepEqual(syncPoint, { time: 50, segmentIndex: 6 },
- 'exact sync point found');
- });
- QUnit.test('returns correct sync point for Discontinuity strategy', function(assert) {
- let strategy = getStrategy('Discontinuity');
- let playlist = {
- targetDuration: 10,
- discontinuitySequence: 2,
- discontinuityStarts: [2, 5],
- segments: [
- { timeline: 2, start: 20, end: 30, duration: 10 },
- { timeline: 2, start: 30, end: 40, duration: 10 },
- { timeline: 3, start: 40, end: 50, duration: 10, discontinuity: true },
- { timeline: 3, start: 50, end: 60, duration: 10 },
- { timeline: 3, start: 60, end: 70, duration: 10 },
- { timeline: 4, start: 70, end: 80, duration: 10, discontinuity: true },
- { timeline: 4, start: 80, end: 90, duration: 10 },
- { timeline: 4, start: 90, end: 100, duration: 10 }
- ]
- };
- let segmentInfo = {
- playlist,
- segment: playlist.segments[2],
- mediaIndex: 2
- };
- let currentTimeline = 3;
- let syncPoint;
- syncPoint = strategy.run(this.syncController, playlist, 100, currentTimeline, 0);
- assert.equal(syncPoint, null, 'no sync point when no discontinuities saved');
- this.syncController.saveDiscontinuitySyncInfo_(segmentInfo);
- syncPoint = strategy.run(this.syncController, playlist, 100, currentTimeline, 55);
- assert.deepEqual(syncPoint, { time: 40, segmentIndex: 2 },
- 'found sync point for timeline 3');
- segmentInfo.mediaIndex = 6;
- segmentInfo.segment = playlist.segments[6];
- currentTimeline = 4;
- this.syncController.saveDiscontinuitySyncInfo_(segmentInfo);
- syncPoint = strategy.run(this.syncController, playlist, 100, currentTimeline, 90);
- assert.deepEqual(syncPoint, { time: 70, segmentIndex: 5 },
- 'found sync point for timeline 4');
- });
- QUnit.test('returns correct sync point for Playlist strategy', function(assert) {
- let strategy = getStrategy('Playlist');
- let playlist = { mediaSequence: 100 };
- let syncPoint;
- syncPoint = strategy.run(this.syncController, playlist, 40, 0);
- assert.equal(syncPoint, null, 'no sync point if no sync info');
- playlist.mediaSequence = 102;
- playlist.syncInfo = { time: 10, mediaSequence: 100};
- syncPoint = strategy.run(this.syncController, playlist, 40, 0);
- assert.deepEqual(syncPoint, { time: 10, segmentIndex: -2 },
- 'found sync point in playlist');
- });
- QUnit.test('saves expired info onto new playlist for sync point', function(assert) {
- let oldPlaylist = playlistWithDuration(50);
- let newPlaylist = playlistWithDuration(50);
- oldPlaylist.mediaSequence = 100;
- newPlaylist.mediaSequence = 103;
- oldPlaylist.segments[0].start = 390;
- oldPlaylist.segments[1].start = 400;
- this.syncController.saveExpiredSegmentInfo(oldPlaylist, newPlaylist);
- assert.deepEqual(newPlaylist.syncInfo, { mediaSequence: 101, time: 400 },
- 'saved correct info for expired segment onto new playlist');
- });
- QUnit.test('Correctly updates time mapping and discontinuity info when probing segments',
- function(assert) {
- let syncCon = this.syncController;
- let playlist = playlistWithDuration(60);
- playlist.discontinuityStarts = [3];
- playlist.discontinuitySequence = 0;
- playlist.segments[3].discontinuity = true;
- playlist.segments.forEach((segment, i) => {
- if (i >= playlist.discontinuityStarts[0]) {
- segment.timeline = 1;
- } else {
- segment.timeline = 0;
- }
- });
- syncCon.probeTsSegment_ = function(segmentInfo) {
- return {
- // offset segment timing to make things interesting
- start: segmentInfo.mediaIndex * 10 + 5 + (6 * segmentInfo.timeline),
- end: segmentInfo.mediaIndex * 10 + 10 + 5 + (6 * segmentInfo.timeline)
- };
- };
- let segment = playlist.segments[0];
- let segmentInfo = {
- mediaIndex: 0,
- playlist,
- timeline: 0,
- timestampOffset: 0,
- startOfSegment: 0,
- segment
- };
- syncCon.probeSegmentInfo(segmentInfo);
- assert.ok(syncCon.timelines[0], 'created mapping object for timeline 0');
- assert.deepEqual(syncCon.timelines[0], { time: 0, mapping: -5 },
- 'mapping object correct');
- assert.equal(segment.start, 0, 'correctly calculated segment start');
- assert.equal(segment.end, 10, 'correctly calculated segment end');
- assert.ok(syncCon.discontinuities[1], 'created discontinuity info for timeline 1');
- assert.deepEqual(syncCon.discontinuities[1], { time: 30, accuracy: 3 },
- 'discontinuity sync info correct');
- segmentInfo.timestampOffset = null;
- segmentInfo.startOfSegment = 10;
- segmentInfo.mediaIndex = 1;
- segment = playlist.segments[1];
- segmentInfo.segment = segment;
- syncCon.probeSegmentInfo(segmentInfo);
- assert.equal(segment.start, 10, 'correctly calculated segment start');
- assert.equal(segment.end, 20, 'correctly calculated segment end');
- assert.deepEqual(syncCon.discontinuities[1], { time: 30, accuracy: 2 },
- 'discontinuity sync info correctly updated with new accuracy');
- segmentInfo.timestampOffset = 30;
- segmentInfo.startOfSegment = 30;
- segmentInfo.mediaIndex = 3;
- segmentInfo.timeline = 1;
- segment = playlist.segments[3];
- segmentInfo.segment = segment;
- syncCon.probeSegmentInfo(segmentInfo);
- assert.ok(syncCon.timelines[1], 'created mapping object for timeline 1');
- assert.deepEqual(syncCon.timelines[1], { time: 30, mapping: -11 },
- 'mapping object correct');
- assert.equal(segment.start, 30, 'correctly calculated segment start');
- assert.equal(segment.end, 40, 'correctly calculated segment end');
- assert.deepEqual(syncCon.discontinuities[1], { time: 30, accuracy: 0 },
- 'discontinuity sync info correctly updated with new accuracy');
- });
- QUnit.test('Correctly calculates expired time', function(assert) {
- let playlist = {
- targetDuration: 10,
- mediaSequence: 100,
- discontinuityStarts: [],
- syncInfo: {
- time: 50,
- mediaSequence: 95
- },
- segments: [
- {
- duration: 10,
- uri: '0.ts'
- },
- {
- duration: 10,
- uri: '1.ts'
- },
- {
- duration: 10,
- uri: '2.ts'
- },
- {
- duration: 10,
- uri: '3.ts'
- },
- {
- duration: 10,
- uri: '4.ts'
- }
- ]
- };
- let expired = this.syncController.getExpiredTime(playlist, Infinity);
- assert.equal(expired, 100, 'estimated expired time using segmentSync');
- playlist = {
- targetDuration: 10,
- discontinuityStarts: [],
- mediaSequence: 100,
- segments: [
- {
- duration: 10,
- uri: '0.ts'
- },
- {
- duration: 10,
- uri: '1.ts',
- start: 108.5,
- end: 118.4
- },
- {
- duration: 10,
- uri: '2.ts'
- },
- {
- duration: 10,
- uri: '3.ts'
- },
- {
- duration: 10,
- uri: '4.ts'
- }
- ]
- };
- expired = this.syncController.getExpiredTime(playlist, Infinity);
- assert.equal(expired, 98.5, 'estimated expired time using segmentSync');
- playlist = {
- discontinuityStarts: [],
- targetDuration: 10,
- mediaSequence: 100,
- syncInfo: {
- time: 50,
- mediaSequence: 95
- },
- segments: [
- {
- duration: 10,
- uri: '0.ts'
- },
- {
- duration: 10,
- uri: '1.ts',
- start: 108.5,
- end: 118.5
- },
- {
- duration: 10,
- uri: '2.ts'
- },
- {
- duration: 10,
- uri: '3.ts'
- },
- {
- duration: 10,
- uri: '4.ts'
- }
- ]
- };
- expired = this.syncController.getExpiredTime(playlist, Infinity);
- assert.equal(expired, 98.5, 'estimated expired time using segmentSync');
- playlist = {
- targetDuration: 10,
- discontinuityStarts: [],
- mediaSequence: 100,
- syncInfo: {
- time: 90.8,
- mediaSequence: 99
- },
- segments: [
- {
- duration: 10,
- uri: '0.ts'
- },
- {
- duration: 10,
- uri: '1.ts'
- },
- {
- duration: 10,
- uri: '2.ts',
- start: 118.5,
- end: 128.5
- },
- {
- duration: 10,
- uri: '3.ts'
- },
- {
- duration: 10,
- uri: '4.ts'
- }
- ]
- };
- expired = this.syncController.getExpiredTime(playlist, Infinity);
- assert.equal(expired, 100.8, 'estimated expired time using segmentSync');
- playlist = {
- targetDuration: 10,
- discontinuityStarts: [],
- mediaSequence: 100,
- endList: true,
- segments: [
- {
- duration: 10,
- uri: '0.ts'
- },
- {
- duration: 10,
- uri: '1.ts'
- },
- {
- duration: 10,
- uri: '2.ts'
- },
- {
- duration: 10,
- uri: '3.ts'
- },
- {
- duration: 10,
- uri: '4.ts'
- }
- ]
- };
- expired = this.syncController.getExpiredTime(playlist, 50);
- assert.equal(expired, 0, 'estimated expired time using segmentSync');
- playlist = {
- targetDuration: 10,
- discontinuityStarts: [],
- mediaSequence: 100,
- endList: true,
- segments: [
- {
- start: 0.006,
- duration: 10,
- uri: '0.ts',
- end: 9.982
- },
- {
- duration: 10,
- uri: '1.ts'
- },
- {
- duration: 10,
- uri: '2.ts'
- },
- {
- duration: 10,
- uri: '3.ts'
- },
- {
- duration: 10,
- uri: '4.ts'
- }
- ]
- };
- expired = this.syncController.getExpiredTime(playlist, 50);
- assert.equal(expired, 0, 'estimated expired time using segmentSync');
- });
|