Skip to content

Commit

Permalink
fix: catch remove errors, remove all data on QUOTA_EXCEEDED (#1101)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonocasey authored Mar 16, 2021
1 parent 7ae58c5 commit 86f77fe
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 30 deletions.
35 changes: 17 additions & 18 deletions src/segment-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -1099,9 +1099,10 @@ export default class SegmentLoader extends videojs.EventTarget {
* @param {number} start - the start time of the region to remove from the buffer
* @param {number} end - the end time of the region to remove from the buffer
* @param {Function} [done] - an optional callback to be executed when the remove
* @param {boolean} force - force all remove operations to happen
* operation is complete
*/
remove(start, end, done = () => {}) {
remove(start, end, done = () => {}, force = false) {
// clamp end to duration if we need to remove everything.
// This is due to a browser bug that causes issues if we remove to Infinity.
// videojs/videojs-contrib-hls#1225
Expand All @@ -1124,7 +1125,7 @@ export default class SegmentLoader extends videojs.EventTarget {
}
};

if (!this.audioDisabled_) {
if (force || !this.audioDisabled_) {
removesRemaining++;
this.sourceUpdater_.removeAudio(start, end, removeFinished);
}
Expand All @@ -1137,7 +1138,7 @@ export default class SegmentLoader extends videojs.EventTarget {
// the event that we're switching between renditions and from video to audio only
// (when we add support for that), we may need to clear the video contents despite
// what the new media will contain.
if (this.loaderType_ === 'main') {
if (force || this.loaderType_ === 'main') {
this.gopBuffer_ = removeGopBuffer(this.gopBuffer_, start, end, this.timeMapping_);
removesRemaining++;
this.sourceUpdater_.removeVideo(start, end, removeFinished);
Expand Down Expand Up @@ -2129,21 +2130,19 @@ export default class SegmentLoader extends videojs.EventTarget {
// before retrying.
const timeToRemoveUntil = currentTime - MIN_BACK_BUFFER;

this.logger_(`On QUOTA_EXCEEDED_ERR, removing video from 0 to ${timeToRemoveUntil}`);
this.sourceUpdater_.removeVideo(0, timeToRemoveUntil, () => {
this.logger_(`On QUOTA_EXCEEDED_ERR, removing audio from 0 to ${timeToRemoveUntil}`);
this.sourceUpdater_.removeAudio(0, timeToRemoveUntil, () => {
this.logger_(`On QUOTA_EXCEEDED_ERR, retrying append in ${MIN_BACK_BUFFER}s`);
this.waitingOnRemove_ = false;
// wait the length of time alotted in the back buffer to prevent wasted
// attempts (since we can't clear less than the minimum)
this.quotaExceededErrorRetryTimeout_ = window.setTimeout(() => {
this.logger_('On QUOTA_EXCEEDED_ERR, re-processing call queue');
this.quotaExceededErrorRetryTimeout_ = null;
this.processCallQueue_();
}, MIN_BACK_BUFFER * 1000);
});
});
this.logger_(`On QUOTA_EXCEEDED_ERR, removing audio/video from 0 to ${timeToRemoveUntil}`);
this.remove(0, timeToRemoveUntil, () => {

this.logger_(`On QUOTA_EXCEEDED_ERR, retrying append in ${MIN_BACK_BUFFER}s`);
this.waitingOnRemove_ = false;
// wait the length of time alotted in the back buffer to prevent wasted
// attempts (since we can't clear less than the minimum)
this.quotaExceededErrorRetryTimeout_ = window.setTimeout(() => {
this.logger_('On QUOTA_EXCEEDED_ERR, re-processing call queue');
this.quotaExceededErrorRetryTimeout_ = null;
this.processCallQueue_();
}, MIN_BACK_BUFFER * 1000);
}, true);
}

handleAppendError_({segmentInfo, type, bytes}, error) {
Expand Down
6 changes: 5 additions & 1 deletion src/source-updater.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,11 @@ const actions = {
}

sourceUpdater.logger_(`Removing ${start} to ${end} from ${type}Buffer`);
sourceBuffer.remove(start, end);
try {
sourceBuffer.remove(start, end);
} catch (e) {
sourceUpdater.logger_(`Remove ${start} to ${end} from ${type}Buffer failed`);
}
},
timestampOffset: (offset) => (type, sourceUpdater) => {
const sourceBuffer = sourceUpdater[`${type}Buffer`];
Expand Down
23 changes: 12 additions & 11 deletions test/segment-loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4174,22 +4174,23 @@ QUnit.module('SegmentLoader', function(hooks) {

QUnit.test('QUOTA_EXCEEDED_ERR triggers error if no room for single segment', function(assert) {
return setupMediaSource(loader.mediaSource_, loader.sourceUpdater_).then(() => {
const playlist = playlistWithDuration(40);

loader.playlist(playlist);
loader.load();
this.clock.tick(1);

loader.sourceUpdater_.appendBuffer = ({type, bytes}, callback) => {
callback({type: 'QUOTA_EXCEEDED_ERR', code: QUOTA_EXCEEDED_ERR});
};
return new Promise((resolve, reject) => {
const playlist = playlistWithDuration(40);

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

return new Promise((resolve, reject) => {
// appenderrors are fatal, we don't want them in this case
loader.one('appenderror', reject);
loader.one('error', resolve);

loader.sourceUpdater_.appendBuffer = ({type, bytes}, callback) => {
callback({type: 'QUOTA_EXCEEDED_ERR', code: QUOTA_EXCEEDED_ERR});
};

standardXHRResponse(this.requests.shift(), muxedSegment());

});
}).then(() => {
// buffer was empty, meaning there wasn't room for a single segment from that
Expand Down

0 comments on commit 86f77fe

Please sign in to comment.