From 18a54767da1cb0f5f2e7bed0913a7035e314aeff Mon Sep 17 00:00:00 2001 From: brandonocasey Date: Wed, 10 Feb 2021 13:29:27 -0500 Subject: [PATCH] unit tests --- src/segment-loader.js | 24 ++++++ test/loader-common.js | 142 ++++++++++++++++++++++++++++++++++++ test/segment-loader.test.js | 1 + test/test-helpers.js | 30 ++++++-- 4 files changed, 191 insertions(+), 6 deletions(-) diff --git a/src/segment-loader.js b/src/segment-loader.js index d9b303e38..788e29b57 100644 --- a/src/segment-loader.js +++ b/src/segment-loader.js @@ -968,6 +968,30 @@ export default class SegmentLoader extends videojs.EventTarget { // equal to the last appended mediaIndex if (this.mediaIndex !== null) { this.mediaIndex -= mediaSequenceDiff; + + /* + // mediaIndex is invalid, set it to null + if (this.mediaIndex < 0) { + this.resyncLoader(); + } else { + const segment = this.playlist_.segments[this.mediaIndex]; + + // partIndex should remain the same for the same segment + // unless parts fell off of the playlist for this segment. + // In that case we need to reset partIndex and resync + if (this.partIndex && (!segment.parts || !segment.parts.length || !segment.parts[this.partIndex])) { + console.log(`part fell off on part ${this.partIndex}`); + this.partIndex = null; + this.remove(0, Infinity); + + // clears fmp4 captions + if (this.transmuxer_) { + this.transmuxer_.postMessage({ + action: 'clearAllMp4Captions' + }); + } + } + }*/ } // update the mediaIndex on the SegmentInfo object diff --git a/test/loader-common.js b/test/loader-common.js index 94238dd52..95e437269 100644 --- a/test/loader-common.js +++ b/test/loader-common.js @@ -802,6 +802,148 @@ export const LoaderCommonFactory = ({ }); }); + QUnit.test('mediaIndex and partIndex are used', function(assert) { + const appendPart = (segmentIndex, partIndex) => { + this.clock.tick(1); + + assert.equal( + this.requests[0].url, + `segment${segmentIndex}.part${partIndex}.ts`, + `requested mediaIndex #${segmentIndex} partIndex #${partIndex}` + ); + standardXHRResponse(this.requests.shift(), testData()); + + if (usesAsyncAppends) { + return new Promise((resolve, reject) => { + loader.one('appended', resolve); + loader.one('error', reject); + }); + } + + return Promise.resolve(); + }; + + return setupMediaSource(loader.mediaSource_, loader.sourceUpdater_).then(() => { + loader.playlist(playlistWithDuration(50, { + mediaSequence: 0, + endList: false, + llhls: true + })); + + loader.load(); + loader.mediaIndex = 2; + return Promise.resolve(); + }).then(() => appendPart(2, 0)) + .then(() => appendPart(2, 1)) + .then(() => appendPart(2, 2)) + .then(() => appendPart(2, 3)) + .then(() => appendPart(2, 4)) + .then(() => appendPart(3, 0)); + }); + + QUnit.test('mediaIndex and partIndex survive playlist change', function(assert) { + const appendPart = (segmentIndex, partIndex) => { + this.clock.tick(1); + + assert.equal( + this.requests[0].url, + `segment${segmentIndex}.part${partIndex}.ts`, + `requested mediaIndex #${segmentIndex} partIndex #${partIndex}` + ); + standardXHRResponse(this.requests.shift(), testData()); + + if (usesAsyncAppends) { + return new Promise((resolve, reject) => { + loader.one('appended', resolve); + loader.one('error', reject); + }); + } + + return Promise.resolve(); + }; + + return setupMediaSource(loader.mediaSource_, loader.sourceUpdater_).then(() => { + loader.playlist(playlistWithDuration(50, { + mediaSequence: 0, + endList: false, + llhls: true + })); + + loader.load(); + loader.mediaIndex = 4; + return Promise.resolve(); + }).then(() => appendPart(4, 0)) + .then(() => appendPart(4, 1)) + .then(() => appendPart(4, 2)) + .then(() => { + + // Update the playlist shifting the mediaSequence by 2 which will result + // in a decrement of the mediaIndex by 2 to 1 + loader.playlist(playlistWithDuration(50, { + mediaSequence: 2, + endList: false, + llhls: true + })); + // verify that we still try to append the next part for that segment. + return appendPart(2, 3); + }).then(() => appendPart(2, 4)); + }); + + QUnit.test('drops partIndex if playlist update drops parts', function(assert) { + const appendPart = (segmentIndex, partIndex) => { + this.clock.tick(1); + + assert.equal( + this.requests[0].url, + `segment${segmentIndex}.part${partIndex}.ts`, + `requested mediaIndex #${segmentIndex} partIndex #${partIndex}` + ); + standardXHRResponse(this.requests.shift(), testData()); + + if (usesAsyncAppends) { + return new Promise((resolve, reject) => { + loader.one('appended', resolve); + loader.one('error', reject); + }); + } + + return Promise.resolve(); + }; + + return setupMediaSource(loader.mediaSource_, loader.sourceUpdater_).then(() => { + loader.playlist(playlistWithDuration(50, { + mediaSequence: 0, + endList: false, + llhls: true + })); + + loader.load(); + loader.mediaIndex = 4; + return Promise.resolve(); + }).then(() => appendPart(4, 0)) + .then(() => appendPart(4, 1)) + .then(() => appendPart(4, 2)) + .then(() => { + + // Update the playlist shifting the mediaSequence by 2 which will result + // in a decrement of the mediaIndex by 2 to 1 + loader.playlist(playlistWithDuration(50, { + mediaSequence: 4, + endList: false, + llhls: true + })); + + assert.equal(loader.partIndex, null, 'partIndex was dropped'); + this.clock.tick(1); + + assert.equal( + this.requests[0].url, + '1.ts', + 'requested mediaIndex 1 only' + ); + }); + }); + QUnit.test('segment 404s should trigger an error', function(assert) { const errors = []; diff --git a/test/segment-loader.test.js b/test/segment-loader.test.js index ee76c0008..220f596fd 100644 --- a/test/segment-loader.test.js +++ b/test/segment-loader.test.js @@ -993,6 +993,7 @@ QUnit.module('SegmentLoader', function(hooks) { this.clock.tick(1); assert.equal(loader.mediaIndex, null, 'mediaIndex reset by seek to seekable'); + assert.equal(loader.partIndex, null, 'partIndex reset by seek to seekable'); assert.equal(syncInfoUpdates, 1, 'syncinfoupdate was triggered'); }); }); diff --git a/test/test-helpers.js b/test/test-helpers.js index 67ec13cbd..64185b277 100644 --- a/test/test-helpers.js +++ b/test/test-helpers.js @@ -433,7 +433,7 @@ export const playlistWithDuration = function(time, conf) { result.id = result.uri; - const count = Math.floor(time / 10); + const count = Math.ceil(time / 10); const remainder = time % 10; let i; const isEncrypted = conf && conf.isEncrypted; @@ -447,19 +447,37 @@ export const playlistWithDuration = function(time, conf) { timeline++; discontinuityStartsIndex++; } - - result.segments.push({ + const segment = { uri: i + extension, resolvedUri: i + extension, - duration: 10, + // last segment will be less then 10 if duration is uneven + duration: i + 1 === count && remainder ? remainder : 10, timeline - }); + }; + if (isEncrypted) { - result.segments[i].key = { + segment.key = { uri: i + '-key.php', resolvedUri: i + '-key.php' }; } + if (conf && conf.llhls) { + // only add parts for the last 3 segments + if ((count - i) <= 3) { + segment.parts = []; + for (let z = 0; z < 5; z++) { + const uri = `segment${i}.part${z}${extension}`; + + segment.parts.push({ + uri, + resolvedUri: uri, + duration: 2 + }); + } + } + + } + result.segments.push(segment); } if (remainder) { result.segments.push({