aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Taylor <user234683@users.noreply.github.com>2021-09-01 17:32:18 -0700
committerJesús <heckyel@hyperbola.info>2021-09-01 20:12:14 -0500
commitfc0fa9aaba9caa0b849a91f1c989e52ab4a7ca15 (patch)
tree8072e39d06422a4b5975f37435690148f9e9b55b
parent06e091e020a2fecd1ef927edc4f55e999804b5f0 (diff)
downloadyt-local-fc0fa9aaba9caa0b849a91f1c989e52ab4a7ca15.tar.lz
yt-local-fc0fa9aaba9caa0b849a91f1c989e52ab4a7ca15.tar.xz
yt-local-fc0fa9aaba9caa0b849a91f1c989e52ab4a7ca15.zip
av-merge: Fix segments not properly reappended during QuotaExceeded
Two issues fixed: 1. The append was only retried if it was the result of a seek event. But if the video is paused (such as if the video was finished and the user seeks back to the beginning), the seek won't happen because the MediaSource will not issue a sourceopen until the user plays the video. A better strategy that solves the true issue is to retry the append if it is for the segment corresponding to the current time, since that is critical to get immediately. 2. If the append was not retried, entry.requested was not getting marked as false, so it would refuse to ever rerequest the segment, so it would stall. Set it to false if we decide not to retry the append, so it can be rerequested later. Signed-off-by: Jesús <heckyel@hyperbola.info>
-rw-r--r--youtube/static/js/av-merge.js39
1 files changed, 23 insertions, 16 deletions
diff --git a/youtube/static/js/av-merge.js b/youtube/static/js/av-merge.js
index dfbf3c9..6a5e044 100644
--- a/youtube/static/js/av-merge.js
+++ b/youtube/static/js/av-merge.js
@@ -166,7 +166,7 @@ function Stream(avMerge, source, startTime, avRatio) {
this.mediaSource = avMerge.mediaSource;
this.sidx = null;
this.appendRetries = 0;
- this.appendQueue = []; // list of [segmentIdx, forSeek, data]
+ this.appendQueue = []; // list of [segmentIdx, data]
this.sourceBuffer = this.mediaSource.addSourceBuffer(this.mimeCodec);
this.sourceBuffer.mode = 'segments';
this.sourceBuffer.addEventListener('error', (e) => {
@@ -189,7 +189,7 @@ Stream.prototype.setup = async function(){
var init_end = this.initRange.end - this.initRange.start + 1;
var index_start = this.indexRange.start - this.initRange.start;
var index_end = this.indexRange.end - this.initRange.start + 1;
- this.appendSegment(null, false, buffer.slice(0, init_end));
+ this.appendSegment(null, buffer.slice(0, init_end));
this.setupSegments(buffer.slice(index_start, index_end));
}
)
@@ -199,7 +199,7 @@ Stream.prototype.setup = async function(){
this.url,
this.initRange.start,
this.initRange.end,
- this.appendSegment.bind(this, false, null),
+ this.appendSegment.bind(this, null),
);
// sidx (segment index) table
fetchRange(
@@ -224,7 +224,7 @@ Stream.prototype.close = function() {
this.mediaSource.removeSourceBuffer(this.sourceBuffer);
this.updateendEvt.remove();
}
-Stream.prototype.appendSegment = function(segmentIdx, forSeek, chunk) {
+Stream.prototype.appendSegment = function(segmentIdx, chunk) {
if (this.closed)
return;
@@ -233,7 +233,7 @@ Stream.prototype.appendSegment = function(segmentIdx, forSeek, chunk) {
// cannot append right now, schedule for updateend
if (this.sourceBuffer.updating) {
this.reportDebug('sourceBuffer updating, queueing for later');
- this.appendQueue.push([segmentIdx, forSeek, chunk]);
+ this.appendQueue.push([segmentIdx, chunk]);
if (this.appendQueue.length > 2){
this.reportWarning('appendQueue length:', this.appendQueue.length);
}
@@ -267,25 +267,26 @@ Stream.prototype.appendSegment = function(segmentIdx, forSeek, chunk) {
this.reportDebug('New buffer target:', this.bufferTarget);
}
- // Delete 3 segments (arbitrary) from buffer, making sure
+ // Delete 10 segments (arbitrary) from buffer, making sure
// not to delete current one
var currentSegment = this.getSegmentIdx(this.video.currentTime);
var numDeleted = 0;
var i = 0;
+ const DELETION_TARGET = 10;
var toDelete = []; // See below for why we have to schedule it
this.reportDebug('Deleting segments from beginning of buffer.');
- while (numDeleted < 3 && i < currentSegment) {
+ while (numDeleted < DELETION_TARGET && i < currentSegment) {
if (this.sidx.entries[i].have) {
toDelete.push(i)
numDeleted++;
}
i++;
}
- if (numDeleted < 3)
+ if (numDeleted < DELETION_TARGET)
this.reportDebug('Deleting segments from end of buffer.');
i = this.sidx.entries.length - 1;
- while (numDeleted < 3 && i > currentSegment) {
+ while (numDeleted < DELETION_TARGET && i > currentSegment) {
if (this.sidx.entries[i].have) {
toDelete.push(i)
numDeleted++;
@@ -297,15 +298,21 @@ Stream.prototype.appendSegment = function(segmentIdx, forSeek, chunk) {
// state, and remove cannot be called until it is done. So we have
// to delete on the updateend event for subsequent ones.
var removeFinishedEvent;
+ var deletedStuff = (toDelete.length !== 0)
var deleteSegment = () => {
if (toDelete.length === 0) {
- // If QuotaExceeded happened during seeking, retry the append
- // Pass false as forSeek to avoid infinite looping if it
- // doesn't work. Rescheduling will take care of updating=true
- // problem.
removeFinishedEvent.remove();
- if (forSeek) {
- this.appendSegment(segmentIdx, false, chunk);
+ // If QuotaExceeded happened for current segment, retry the
+ // append
+ // Rescheduling will take care of updating=true problem.
+ // Also check that we found segments to delete, to avoid
+ // infinite looping if we can't delete anything
+ if (segmentIdx === currentSegment && deletedStuff) {
+ this.reportDebug('Retrying appendSegment for', segmentIdx);
+ this.appendSegment(segmentIdx, chunk);
+ } else {
+ this.reportDebug('Not retrying segment', segmentIdx);
+ this.sidx.entries[segmentIdx].requested = false;
}
return;
}
@@ -440,7 +447,7 @@ Stream.prototype.fetchSegment = function(segmentIdx) {
this.url,
entry.start,
entry.end,
- this.appendSegment.bind(this, segmentIdx, this.avMerge.seeking),
+ this.appendSegment.bind(this, segmentIdx),
);
}
Stream.prototype.fetchSegmentIfNeeded = function(segmentIdx) {