12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040 |
- import {
- getUniqueTimelineStarts,
- findPlaylistWithName,
- getMediaGroupPlaylists,
- updateMediaSequenceForPlaylist,
- updateSequenceNumbers,
- positionManifestOnTimeline
- } from '../src/playlist-merge';
- import { merge } from '../src/utils/object';
- import QUnit from 'qunit';
- QUnit.module('getUniqueTimelineStarts');
- QUnit.test('handles multiple playlists', function(assert) {
- const listOfTimelineStartLists = [
- [{ start: 0, timeline: 0 }, { start: 10, timeline: 10 }, { start: 20, timeline: 20 }],
- [{ start: 0, timeline: 0 }, { start: 10, timeline: 10 }, { start: 20, timeline: 20 }],
- [{ start: 10, timeline: 10 }, { start: 20, timeline: 20 }],
- [{ start: 0, timeline: 0 }, { start: 20, timeline: 20 }],
- [{ start: 30, timeline: 30 }]
- ];
- assert.deepEqual(
- getUniqueTimelineStarts(listOfTimelineStartLists),
- [{
- start: 0,
- timeline: 0
- }, {
- start: 10,
- timeline: 10
- }, {
- start: 20,
- timeline: 20
- }, {
- start: 30,
- timeline: 30
- }],
- 'handled multiple playlists with differing timeline starts'
- );
- });
- QUnit.module('findPlaylistWithName');
- QUnit.test('returns nothing when no playlists', function(assert) {
- assert.notOk(findPlaylistWithName([], 'A'), 'nothing when no playlists');
- });
- QUnit.test('returns nothing when no match', function(assert) {
- const playlists = [
- { attributes: { NAME: 'B' } }
- ];
- assert.notOk(findPlaylistWithName(playlists, 'A'), 'nothing when no match');
- });
- QUnit.test('returns matching playlist', function(assert) {
- const playlists = [
- { attributes: { NAME: 'A' } },
- { attributes: { NAME: 'B' } },
- { attributes: { NAME: 'C' } }
- ];
- assert.deepEqual(
- findPlaylistWithName(playlists, 'B'),
- playlists[1],
- 'returns matching playlist'
- );
- });
- QUnit.module('getMediaGroupPlaylists');
- QUnit.test('returns nothing when no media group playlists', function(assert) {
- const manifest = {
- mediaGroups: {
- AUDIO: {}
- }
- };
- assert.deepEqual(
- getMediaGroupPlaylists(manifest),
- [],
- 'nothing when no media group playlists'
- );
- });
- QUnit.test('returns media group playlists', function(assert) {
- const playlistEnA = { attributes: { NAME: 'A' } };
- const playlistEnB = { attributes: { NAME: 'B' } };
- const playlistEnC = { attributes: { NAME: 'C' } };
- const playlistFrA = { attributes: { NAME: 'A' } };
- const playlistFrB = { attributes: { NAME: 'B' } };
- const manifest = {
- mediaGroups: {
- AUDIO: {
- audio: {
- en: {
- playlists: [playlistEnA, playlistEnB, playlistEnC]
- },
- fr: {
- playlists: [playlistFrA, playlistFrB]
- }
- }
- }
- }
- };
- assert.deepEqual(
- getMediaGroupPlaylists(manifest),
- [playlistEnA, playlistEnB, playlistEnC, playlistFrA, playlistFrB],
- 'returns media group playlists'
- );
- });
- QUnit.module('updateMediaSequenceForPlaylist');
- QUnit.test('no segments means only top level mediaSequence is updated', function(assert) {
- const playlist = { mediaSequence: 1, segments: [] };
- updateMediaSequenceForPlaylist({ playlist, mediaSequence: 3 });
- assert.deepEqual(
- playlist,
- { mediaSequence: 3, segments: [] },
- 'updated only top level mediaSequence'
- );
- });
- QUnit.test('updates top level mediaSequence and segments', function(assert) {
- const playlist = {
- mediaSequence: 1,
- segments: [{ number: 1 }, { number: 2 }, { number: 3 }]
- };
- updateMediaSequenceForPlaylist({ playlist, mediaSequence: 3 });
- assert.deepEqual(
- playlist,
- { mediaSequence: 3, segments: [{ number: 3 }, { number: 4 }, { number: 5 }] },
- 'updated top level mediaSequence and segments'
- );
- });
- QUnit.module('updateSequenceNumbers');
- QUnit.test('no playlists, no update', function(assert) {
- const oldPlaylists = [];
- const newPlaylists = [];
- const timelineStarts = [];
- updateSequenceNumbers({ oldPlaylists, newPlaylists, timelineStarts });
- assert.deepEqual(newPlaylists, [], 'new playlists unchanged');
- });
- QUnit.test('no matching playlists only updates discontinuity sequence', function(assert) {
- const oldPlaylists = [{
- discontinuitySequence: 1,
- discontinuityStarts: [],
- timeline: 5,
- attributes: { NAME: 'A' }
- }, {
- discontinuitySequence: 2,
- discontinuityStarts: [],
- timeline: 10,
- attributes: { NAME: 'B' }
- }];
- const newPlaylists = [{
- discontinuitySequence: 0,
- discontinuityStarts: [],
- timeline: 5,
- attributes: { NAME: 'C' }
- }, {
- discontinuitySequence: 0,
- discontinuityStarts: [],
- timeline: 10,
- attributes: { NAME: 'D' }
- }];
- const timelineStarts = [
- { start: 0, timeline: 0 },
- { start: 5, timeline: 5 },
- { start: 10, timeline: 10 }
- ];
- updateSequenceNumbers({ oldPlaylists, newPlaylists, timelineStarts });
- assert.deepEqual(
- newPlaylists,
- [{
- discontinuitySequence: 1,
- discontinuityStarts: [],
- timeline: 5,
- attributes: { NAME: 'C' }
- }, {
- discontinuitySequence: 2,
- discontinuityStarts: [],
- timeline: 10,
- attributes: { NAME: 'D' }
- }],
- 'new playlist discontinuity sequence numbers updated'
- );
- });
- QUnit.test('segment match of matching playlist', function(assert) {
- const oldPlaylists = [{
- discontinuitySequence: 1,
- discontinuityStarts: [],
- mediaSequence: 5,
- timeline: 5,
- attributes: { NAME: 'C' },
- segments: [{
- presentationTime: 10,
- timeline: 5,
- number: 5
- }, {
- presentationTime: 12,
- timeline: 5,
- number: 6
- }, {
- presentationTime: 14,
- timeline: 5,
- number: 7
- }]
- }];
- const newPlaylists = [{
- discontinuitySequence: 0,
- discontinuityStarts: [],
- mediaSequence: 0,
- timeline: 5,
- attributes: { NAME: 'C' },
- segments: [{
- presentationTime: 12,
- timeline: 5,
- number: 0
- }, {
- presentationTime: 14,
- timeline: 5,
- number: 1
- }]
- }];
- const timelineStarts = [
- { start: 0, timeline: 0 },
- { start: 5, timeline: 5 }
- ];
- updateSequenceNumbers({ oldPlaylists, newPlaylists, timelineStarts });
- assert.deepEqual(
- newPlaylists,
- [{
- discontinuitySequence: 1,
- discontinuityStarts: [],
- mediaSequence: 6,
- timeline: 5,
- attributes: { NAME: 'C' },
- segments: [{
- presentationTime: 12,
- timeline: 5,
- number: 6
- }, {
- presentationTime: 14,
- timeline: 5,
- number: 7
- }]
- }],
- 'new playlist updated'
- );
- });
- QUnit.test('complete refresh of matching playlist', function(assert) {
- const oldPlaylists = [{
- discontinuitySequence: 1,
- discontinuityStarts: [],
- mediaSequence: 5,
- timeline: 5,
- attributes: { NAME: 'C' },
- segments: [{
- presentationTime: 10,
- timeline: 5,
- number: 5
- }, {
- presentationTime: 12,
- timeline: 5,
- number: 6
- }, {
- presentationTime: 14,
- timeline: 5,
- number: 7
- }]
- }];
- const newPlaylists = [{
- discontinuitySequence: 0,
- discontinuityStarts: [],
- mediaSequence: 0,
- timeline: 5,
- attributes: { NAME: 'C' },
- segments: [{
- presentationTime: 16,
- timeline: 5,
- number: 0
- }, {
- presentationTime: 18,
- timeline: 5,
- number: 1
- }]
- }];
- const timelineStarts = [
- { start: 0, timeline: 0 },
- { start: 5, timeline: 5 }
- ];
- updateSequenceNumbers({ oldPlaylists, newPlaylists, timelineStarts });
- assert.deepEqual(
- newPlaylists,
- [{
- discontinuitySequence: 1,
- discontinuityStarts: [0],
- mediaSequence: 8,
- timeline: 5,
- attributes: { NAME: 'C' },
- segments: [{
- discontinuity: true,
- presentationTime: 16,
- timeline: 5,
- number: 8
- }, {
- presentationTime: 18,
- timeline: 5,
- number: 9
- }]
- }],
- 'new playlist updated after complete refresh'
- );
- });
- QUnit.module('positionManifestOnTimeline');
- QUnit.test('handles multiple playlists, including added and removed', function(assert) {
- const oldPlaylistA = {
- attributes: { NAME: 'A' },
- mediaSequence: 12,
- discontinuitySequence: 2,
- discontinuityStarts: [1],
- timelineStarts: [
- // only this playlist has the 20 timeline
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- timeline: 20,
- segments: [{
- number: 12,
- timeline: 20,
- presentationTime: 31
- }, {
- discontinuity: true,
- number: 13,
- timeline: 33,
- presentationTime: 33
- }, {
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- };
- const oldPlaylistB = {
- attributes: { NAME: 'B' },
- mediaSequence: 13,
- discontinuitySequence: 2,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- discontinuity: true,
- number: 13,
- timeline: 33,
- presentationTime: 33
- }, {
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- };
- // same as A just with a different name
- const oldPlaylistC = merge(oldPlaylistA, {
- attributes: { NAME: 'C' }
- });
- const newPlaylistA = {
- attributes: { NAME: 'A' },
- mediaSequence: 0,
- discontinuitySequence: 0,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- // no discontinuity is marked because from the context of the new playlist, it's the
- // first period
- number: 0,
- timeline: 33,
- presentationTime: 33
- }, {
- number: 1,
- timeline: 33,
- presentationTime: 35
- }]
- };
- const newPlaylistB = {
- attributes: { NAME: 'B' },
- mediaSequence: 0,
- discontinuitySequence: 0,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- number: 0,
- timeline: 33,
- presentationTime: 35
- }]
- };
- // same as B but with a different name
- const newPlaylistD = merge(newPlaylistB, {
- attributes: { NAME: 'D' }
- });
- const oldManifest = {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- // The manifest's timeline starts will account for all seen timeline starts. Since the
- // lowest playlist discontinuity sequence is 2, that means there are two additional
- // timeline starts here that aren't present in any playlists.
- timelineStarts: [
- { start: 10, timeline: 10 },
- { start: 15, timeline: 15 },
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- playlists: [oldPlaylistA, oldPlaylistB, oldPlaylistC]
- };
- const newManifest = {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- timelineStarts: [
- // removed 20 timeline
- { start: 33, timeline: 33 }
- ],
- // removed C, added D
- playlists: [newPlaylistA, newPlaylistB, newPlaylistD]
- };
- assert.deepEqual(
- positionManifestOnTimeline({ oldManifest, newManifest }),
- {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- timelineStarts: [
- { start: 10, timeline: 10 },
- { start: 15, timeline: 15 },
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- playlists: [{
- attributes: { NAME: 'A' },
- // updated mediaSequence
- mediaSequence: 13,
- // updated discontinuitySequence
- discontinuitySequence: 2,
- discontinuityStarts: [0],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- discontinuity: true,
- // updated sequence number
- number: 13,
- timeline: 33,
- presentationTime: 33
- }, {
- // updated sequence number
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- }, {
- attributes: { NAME: 'B' },
- // updated mediaSequence
- mediaSequence: 14,
- // updated discontinuitySequence, note that it's one greater than A
- discontinuitySequence: 3,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- // updated sequence number
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- }, {
- attributes: { NAME: 'D' },
- // since D is a new playlist, media sequence is 0
- mediaSequence: 0,
- // updated discontinuitySequence, note that it's one greater than A
- discontinuitySequence: 3,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- // updated sequence number
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- }]
- },
- 'handled updated, removed, and added playlists'
- );
- });
- QUnit.test('handles playlist and media group playlist', function(assert) {
- const oldPlaylistA = {
- attributes: { NAME: 'A' },
- mediaSequence: 12,
- discontinuitySequence: 2,
- discontinuityStarts: [1],
- timelineStarts: [
- // only this playlist has the 20 timeline
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- timeline: 20,
- segments: [{
- number: 12,
- timeline: 20,
- presentationTime: 31
- }, {
- discontinuity: true,
- number: 13,
- timeline: 33,
- presentationTime: 33
- }, {
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- };
- const oldPlaylistB = {
- attributes: { NAME: 'B' },
- mediaSequence: 13,
- discontinuitySequence: 2,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- discontinuity: true,
- number: 13,
- timeline: 33,
- presentationTime: 33
- }, {
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- };
- const newPlaylistA = {
- attributes: { NAME: 'A' },
- mediaSequence: 0,
- discontinuitySequence: 0,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- // no discontinuity is marked because from the context of the new playlist, it's the
- // first period
- number: 0,
- timeline: 33,
- presentationTime: 33
- }, {
- number: 1,
- timeline: 33,
- presentationTime: 35
- }]
- };
- const newPlaylistB = {
- attributes: { NAME: 'B' },
- mediaSequence: 0,
- discontinuitySequence: 0,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- number: 0,
- timeline: 33,
- presentationTime: 35
- }]
- };
- const oldManifest = {
- mediaGroups: {
- AUDIO: {
- audio: {
- en: {
- playlists: [oldPlaylistA]
- }
- }
- },
- VIDEO: {},
- ['CLOSED-CAPTIONS']: {},
- SUBTITLES: {}
- },
- // The manifest's timeline starts will account for all seen timeline starts. Since the
- // lowest playlist discontinuity sequence is 2, that means there are two additional
- // timeline starts here that aren't present in any playlists.
- timelineStarts: [
- { start: 10, timeline: 10 },
- { start: 15, timeline: 15 },
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- playlists: [oldPlaylistB]
- };
- const newManifest = {
- mediaGroups: {
- AUDIO: {
- audio: {
- en: {
- playlists: [newPlaylistA]
- }
- }
- },
- VIDEO: {},
- ['CLOSED-CAPTIONS']: {},
- SUBTITLES: {}
- },
- timelineStarts: [
- // removed 20 timeline
- { start: 33, timeline: 33 }
- ],
- // removed C, added D
- playlists: [newPlaylistB]
- };
- assert.deepEqual(
- positionManifestOnTimeline({ oldManifest, newManifest }),
- {
- mediaGroups: {
- AUDIO: {
- audio: {
- en: {
- playlists: [{
- attributes: { NAME: 'A' },
- // updated mediaSequence
- mediaSequence: 13,
- // updated discontinuitySequence
- discontinuitySequence: 2,
- discontinuityStarts: [0],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- discontinuity: true,
- // updated sequence number
- number: 13,
- timeline: 33,
- presentationTime: 33
- }, {
- // updated sequence number
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- }]
- }
- }
- },
- VIDEO: {},
- ['CLOSED-CAPTIONS']: {},
- SUBTITLES: {}
- },
- timelineStarts: [
- { start: 10, timeline: 10 },
- { start: 15, timeline: 15 },
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- playlists: [{
- attributes: { NAME: 'B' },
- // updated mediaSequence
- mediaSequence: 14,
- // updated discontinuitySequence, note that it's one greater than A
- discontinuitySequence: 3,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- // updated sequence number
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- }]
- },
- 'handled playlist and media group playlist'
- );
- });
- QUnit.test('complete refresh same timeline', function(assert) {
- const oldPlaylistA = {
- attributes: { NAME: 'A' },
- mediaSequence: 12,
- discontinuitySequence: 2,
- discontinuityStarts: [1],
- timelineStarts: [
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- timeline: 20,
- segments: [{
- number: 12,
- timeline: 20,
- presentationTime: 31
- }, {
- discontinuity: true,
- number: 13,
- timeline: 33,
- presentationTime: 33
- }, {
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- };
- const newPlaylistA = {
- attributes: { NAME: 'A' },
- mediaSequence: 0,
- discontinuitySequence: 0,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- number: 0,
- timeline: 33,
- // missed a large portion of time, but still within same timeline
- presentationTime: 50
- }, {
- number: 1,
- timeline: 33,
- presentationTime: 52
- }]
- };
- const oldManifest = {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- // The manifest's timeline starts will account for all seen timeline starts. Since the
- // lowest playlist discontinuity sequence is 2, that means there are two additional
- // timeline starts here that aren't present in any playlists.
- timelineStarts: [
- { start: 10, timeline: 10 },
- { start: 15, timeline: 15 },
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- playlists: [oldPlaylistA]
- };
- const newManifest = {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- timelineStarts: [
- // removed 20 timeline
- { start: 33, timeline: 33 }
- ],
- playlists: [newPlaylistA]
- };
- assert.deepEqual(
- positionManifestOnTimeline({ oldManifest, newManifest }),
- {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- timelineStarts: [
- { start: 10, timeline: 10 },
- { start: 15, timeline: 15 },
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- playlists: [{
- attributes: { NAME: 'A' },
- // updated mediaSequence to one greater than last seen
- mediaSequence: 15,
- // updated discontinuitySequence to account for timeline 33 discontinuity falling
- // off
- discontinuitySequence: 3,
- // added discontinuity to beginning
- discontinuityStarts: [0],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- discontinuity: true,
- // updated sequence number
- number: 15,
- timeline: 33,
- presentationTime: 50
- }, {
- // updated sequence number
- number: 16,
- timeline: 33,
- presentationTime: 52
- }]
- }]
- },
- 'handled complete refresh on same timeline'
- );
- });
- QUnit.test('complete refresh different timeline', function(assert) {
- const oldPlaylistA = {
- attributes: { NAME: 'A' },
- mediaSequence: 12,
- // timeline 10 is the start (thus no disco)
- // removed 1 disco at timeline 15, and another for the start of timeline 20
- discontinuitySequence: 2,
- discontinuityStarts: [1],
- timelineStarts: [
- // only this playlist has the 20 timeline
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- timeline: 20,
- segments: [{
- number: 12,
- timeline: 20,
- presentationTime: 31
- }, {
- discontinuity: true,
- number: 13,
- timeline: 33,
- presentationTime: 33
- }, {
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- };
- const newPlaylistA = {
- attributes: { NAME: 'A' },
- mediaSequence: 0,
- discontinuitySequence: 0,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 50, timeline: 50 }
- ],
- timeline: 50,
- segments: [{
- number: 0,
- // new timeline
- timeline: 50,
- presentationTime: 50
- }, {
- number: 1,
- timeline: 50,
- presentationTime: 52
- }]
- };
- const oldManifest = {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- // The manifest's timeline starts will account for all seen timeline starts. Since the
- // lowest playlist discontinuity sequence is 2, that means there are two additional
- // timeline starts here that aren't present in any playlists.
- timelineStarts: [
- { start: 10, timeline: 10 },
- { start: 15, timeline: 15 },
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- playlists: [oldPlaylistA]
- };
- const newManifest = {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- timelineStarts: [
- // removed 20 and 33 timelines, added 50
- { start: 50, timeline: 50 }
- ],
- playlists: [newPlaylistA]
- };
- assert.deepEqual(
- positionManifestOnTimeline({ oldManifest, newManifest }),
- {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- timelineStarts: [
- { start: 10, timeline: 10 },
- { start: 15, timeline: 15 },
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 },
- // added new timeline and retained the ones from before
- { start: 50, timeline: 50 }
- ],
- playlists: [{
- attributes: { NAME: 'A' },
- // updated mediaSequence to one greater than last seen
- mediaSequence: 15,
- // updated discontinuitySequence to account for removed discos (previously the
- // disco at 15 and 20, plus the disco starting timeline 33 on the refresh)
- discontinuitySequence: 3,
- // added discontinuity to beginning
- discontinuityStarts: [0],
- timelineStarts: [
- { start: 50, timeline: 50 }
- ],
- timeline: 50,
- segments: [{
- discontinuity: true,
- // updated sequence number
- number: 15,
- timeline: 50,
- presentationTime: 50
- }, {
- // updated sequence number
- number: 16,
- timeline: 50,
- presentationTime: 52
- }]
- }]
- },
- 'handled complete refresh on different timeline'
- );
- });
- QUnit.test('no change, first segment a discontinuity', function(assert) {
- const oldPlaylistA = {
- attributes: { NAME: 'A' },
- mediaSequence: 13,
- discontinuitySequence: 2,
- discontinuityStarts: [0],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- discontinuity: true,
- number: 13,
- timeline: 33,
- presentationTime: 33
- }, {
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- };
- const newPlaylistA = {
- attributes: { NAME: 'A' },
- mediaSequence: 0,
- discontinuitySequence: 0,
- discontinuityStarts: [],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- // no discontinuity marked for the refresh, should be added by merging logic
- number: 0,
- timeline: 33,
- presentationTime: 33
- }, {
- number: 1,
- timeline: 33,
- presentationTime: 35
- }]
- };
- const oldManifest = {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- // The manifest's timeline starts will account for all seen timeline starts. Since the
- // lowest playlist discontinuity sequence is 3, that means there are three additional
- // timeline starts here that aren't present in any playlists, plus the original at 0.
- timelineStarts: [
- { start: 10, timeline: 10 },
- { start: 15, timeline: 15 },
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- playlists: [oldPlaylistA]
- };
- const newManifest = {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- timelineStarts: [{ start: 33, timeline: 33 }],
- playlists: [newPlaylistA]
- };
- assert.deepEqual(
- positionManifestOnTimeline({ oldManifest, newManifest }),
- {
- mediaGroups: { AUDIO: {}, VIDEO: {}, ['CLOSED-CAPTIONS']: {}, SUBTITLES: {} },
- timelineStarts: [
- { start: 10, timeline: 10 },
- { start: 15, timeline: 15 },
- { start: 20, timeline: 20 },
- { start: 33, timeline: 33 }
- ],
- playlists: [{
- attributes: { NAME: 'A' },
- mediaSequence: 13,
- discontinuitySequence: 2,
- // discontinuity at beginning
- discontinuityStarts: [0],
- timelineStarts: [
- { start: 33, timeline: 33 }
- ],
- timeline: 33,
- segments: [{
- // discontinuity added to new playlist
- discontinuity: true,
- // updated sequence number
- number: 13,
- timeline: 33,
- presentationTime: 33
- }, {
- // updated sequence number
- number: 14,
- timeline: 33,
- presentationTime: 35
- }]
- }]
- },
- 'handled no change with first segment a discontinuity'
- );
- });
|