Skip to content

Commit

Permalink
fix: always append init segment after trackinfo change (#913)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonocasey authored Jul 22, 2020
1 parent a4ab285 commit ea3650a
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 4 deletions.
28 changes: 25 additions & 3 deletions src/segment-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -1453,11 +1453,31 @@ export default class SegmentLoader extends videojs.EventTarget {
// Guard against cases where we're not getting track info at all until we are
// certain that all streams will provide it.
if (!shallowEqual(this.startingMedia_, trackInfo)) {
this.appendInitSegment_ = {
audio: true,
video: true
};

this.startingMedia_ = trackInfo;
this.logger_('trackinfo update', trackInfo);
this.trigger('trackinfo');
}

// trackinfo may cause an abort if the trackinfo
// causes a codec change to an unsupported codec.
if (this.checkForAbort_(simpleSegment.requestId) ||
this.abortRequestEarly_(simpleSegment.stats)) {
return;
}

// set trackinfo on the pending segment so that
// it can append.
this.pendingSegment_.trackInfo = trackInfo;

// check if any calls were waiting on the track info
if (this.hasEnoughInfoToAppend_()) {
this.processCallQueue_();
}
}

handleTimingInfo_(simpleSegment, mediaType, timeType, time) {
Expand Down Expand Up @@ -1678,8 +1698,10 @@ export default class SegmentLoader extends videojs.EventTarget {

const segmentInfo = this.pendingSegment_;

if (!segmentInfo || !this.startingMedia_) {
// no segment to append any data for
// no segment to append any data for or
// we do not have information on this specific
// segment yet
if (!segmentInfo || !segmentInfo.trackInfo) {
return false;
}

Expand Down Expand Up @@ -1895,7 +1917,7 @@ export default class SegmentLoader extends videojs.EventTarget {

this.sourceUpdater_.appendBuffer({segmentInfo, type, bytes}, (error) => {
if (error) {
this.error(`appenderror for ${type} append with ${bytes.length} bytes`);
this.error(`${type} append of ${bytes.length}b failed for segment #${segmentInfo.mediaIndex} in playlist ${segmentInfo.playlist.id}`);
// If an append errors, we can't recover.
// (see https://w3c.github.io/media-source/#sourcebuffer-append-error).
// Trigger a special error so that it can be handled separately from normal,
Expand Down
57 changes: 56 additions & 1 deletion test/segment-loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2324,7 +2324,11 @@ QUnit.module('SegmentLoader', function(hooks) {
loader.one('error', reject);
});
}).then(() => {
assert.deepEqual(loader.error_, 'appenderror for video append with 2960 bytes', 'loader triggered and saved the appenderror');
assert.deepEqual(
loader.error_,
'video append of 2960b failed for segment #0 in playlist playlist.m3u8',
'loader triggered and saved the appenderror'
);
});
});

Expand Down Expand Up @@ -2586,6 +2590,57 @@ QUnit.module('SegmentLoader', function(hooks) {
});
});

QUnit.test('re-appends init segments after different trackinfo', function(assert) {
const appends = [];
const oldTrackInfo = loader.handleTrackInfo_;

return setupMediaSource(loader.mediaSource_, loader.sourceUpdater_).then(() => {
const origAppendToSourceBuffer = loader.appendToSourceBuffer_.bind(loader);

loader.appendToSourceBuffer_ = (config) => {
appends.push(config);
origAppendToSourceBuffer(config);
};

loader.playlist(playlistWithDuration(20));
loader.load();
this.clock.tick(1);
standardXHRResponse(this.requests.shift(), muxedSegment());

loader.handleTrackInfo_ = (simpleSegment, trackInfo) => {
trackInfo.foo = true;
return oldTrackInfo.call(loader, simpleSegment, trackInfo);
};

return new Promise((resolve, reject) => {
loader.one('appended', resolve);
loader.one('error', reject);
});
}).then(() => {
this.clock.tick(1);

assert.equal(appends.length, 2, 'two appends');
assert.equal(appends[0].type, 'video', 'appended to video buffer');
assert.ok(appends[0].initSegment, 'appended video init segment');
assert.equal(appends[1].type, 'audio', 'appended to audio buffer');
assert.ok(appends[1].initSegment, 'appended audio init segment');

standardXHRResponse(this.requests.shift(), muxedSegment());
return new Promise((resolve, reject) => {
loader.one('appended', resolve);
loader.one('error', reject);
});
}).then(() => {
this.clock.tick(1);

assert.equal(appends.length, 4, 'two more appends');
assert.equal(appends[2].type, 'video', 'appended to video buffer');
assert.ok(appends[2].initSegment, 'appended video init segment');
assert.equal(appends[3].type, 'audio', 'appended to audio buffer');
assert.ok(appends[3].initSegment, 'appended audio init segment');
});
});

QUnit.test('stores and reuses audio init segments from map tag', function(assert) {
loader.dispose();
loader = new SegmentLoader(LoaderCommonSettings.call(this, {
Expand Down

0 comments on commit ea3650a

Please sign in to comment.