Skip to content

Commit

Permalink
add new error FRAG_LOOP_LOADING_ERROR, raised upon detection of same …
Browse files Browse the repository at this point in the history
…fragment being requested in loop.
  • Loading branch information
mangui committed Jul 9, 2015
1 parent ccb9f03 commit 7b2029f
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 7 deletions.
3 changes: 3 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ each error is categorized by :
- ```Hls.ErrorDetails.LEVEL_LOAD_TIMEOUT```raised when level loading fails because of a timeout
- ```Hls.ErrorDetails.LEVEL_SWITCH_ERROR```raised when level switching fails
- ```Hls.ErrorDetails.FRAG_LOAD_ERROR```raised when fragment loading fails because of a network error
- ```Hls.ErrorDetails.FRAG_LOOP_LOADING_ERROR```raised upon detection of same fragment being requested in loop
- ```Hls.ErrorDetails.FRAG_LOAD_TIMEOUT```raised when fragment loading fails because of a timeout
- ```Hls.ErrorDetails.FRAG_PARSING_ERROR```raised when fragment parsing fails
- ```Hls.ErrorDetails.FRAG_APPENDING_ERROR```raised when mp4 boxes appending in SourceBuffer fails
Expand Down Expand Up @@ -406,6 +407,8 @@ full list of Errors is described below:
- data: { type : ```OTHER_ERROR```, details : ```Hls.ErrorDetails.LEVEL_SWITCH_ERROR```, fatal : ```false```,level : failed level index, reason : failure reason}
- ```Hls.ErrorDetails.FRAG_LOAD_ERROR```raised when fragment loading fails because of a network error
- data: { type : ```NETWORK_ERROR```, details : ```Hls.ErrorDetails.FRAG_LOAD_ERROR```, fatal : ```true/false```,frag : fragment object, response : xhr response}
- ```Hls.ErrorDetails.FRAG_LOOP_LOADING_ERROR```raised upon detection of same fragment being requested in loop
- data: { type : ```NETWORK_ERROR```, details : ```Hls.ErrorDetails.FRAG_LOOP_LOADING_ERROR```, fatal : ```true/false```,frag : fragment object}
- ```Hls.ErrorDetails.FRAG_LOAD_TIMEOUT```raised when fragment loading fails because of a timeout
- data: { type : ```NETWORK_ERROR```, details : ```Hls.ErrorDetails.FRAG_LOAD_TIMEOUT```, fatal : ```true/false```,frag : fragment object}
- ```Hls.ErrorDetails.FRAG_PARSING_ERROR```raised when fragment parsing fails
Expand Down
3 changes: 3 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ <h4> Stats Display </h4>
case Hls.ErrorDetails.FRAG_APPENDING_ERROR:
$("#HlsStatus").text("Frag Appending Error");
break;
case Hls.ErrorDetails.FRAG_LOOP_LOADING_ERROR:
$("#HlsStatus").text("Frag Loop Loading Error");
break;
default:
break;
}
Expand Down
7 changes: 5 additions & 2 deletions design.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ design idea is pretty simple :
- [src/controller/buffer-controller.js][]
- in charge of:
- ensuring that buffer is filled as per defined quality selection logic.
- monitoring current playback quality level
- monitoring current playback quality level (buffer controller maintains a map between media position and quality level)
- if buffer is not filled up appropriately (i.e. as per defined maximum buffer size, or as per defined quality level), buffer controller will trigger the following actions:
- retrieve "not buffered" media position greater then current playback position
- retrieve "not buffered" media position greater then current playback position. this is performed by comparing video.buffered and video.currentTime.
- retrieve URL of fragment matching with this media position, and appropriate quality level
- trigger fragment loading
- monitor fragment loading speed:
Expand Down Expand Up @@ -110,6 +110,9 @@ design idea is pretty simple :
- ```FRAG_LOAD_ERROR``` is raised by [src/loader/fragment-loader.js][] upon xhr failure detected by [src/utils/xhr-loader.js][].
- if auto level switch is enabled and loaded frag level is greater than 0, this error is not fatal: in that case [src/controller/level-controller.js][] will trigger an emergency switch down to level 0.
- if frag level is 0 or auto level switch is disabled, this error is marked as fatal and a call to ```hls.recoverNetworkError()``` could help recover it.
- ```FRAG_LOOP_LOADING_ERROR``` is raised by [src/controller/buffer-controller.js][] upon detection of same fragment being requested in loop. this could happen with badly formatted fragments.
- if auto level switch is enabled and loaded frag level is greater than 0, this error is not fatal: in that case [src/controller/level-controller.js][] will trigger an emergency switch down to level 0.
- if frag level is 0 or auto level switch is disabled, this error is marked as fatal and a call to ```hls.recoverNetworkError()``` could help recover it.
- ```FRAG_LOAD_TIMEOUT``` is raised by [src/loader/fragment-loader.js][] upon xhr timeout detected by [src/utils/xhr-loader.js][].
- if auto level switch is enabled and loaded frag level is greater than 0, this error is not fatal: in that case [src/controller/level-controller.js][] will trigger an emergency switch down to level 0.
- if frag level is 0 or auto level switch is disabled, this error is marked as fatal and a call to ```hls.recoverNetworkError()``` could help recover it.
Expand Down
30 changes: 25 additions & 5 deletions src/controller/buffer-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
this.stop();
this.demuxer = new Demuxer(this.config);
this.timer = setInterval(this.ontick, 100);
this.appendError=0;
this.level = -1;
observer.on(Event.FRAG_LOADED, this.onfl);
observer.on(Event.FRAG_PARSING_INIT_SEGMENT, this.onis);
Expand All @@ -91,7 +90,6 @@
}
this.frag = null;
}
this.flushBufferCounter = 0;
if(this.sourceBuffer) {
for(var type in this.sourceBuffer) {
var sb = this.sourceBuffer[type];
Expand Down Expand Up @@ -252,6 +250,26 @@
frag.expectedLen = Math.round(frag.duration*this.levels[level].bitrate/8);
frag.trequest = new Date();
}

// ensure that we are not reloading the same fragments in loop ...
(this.fragLoadIdx !== undefined) ? this.fragLoadIdx++ : this.fragLoadIdx = 0;
if(frag.loadCounter) {
frag.loadCounter++;
let maxThreshold = this.config.fragLoadingLoopThreshold;
// if this frag has already been loaded 3 times, and if it has been reloaded recently
if(frag.loadCounter > maxThreshold && (Math.abs(this.fragLoadIdx - frag.loadIdx) < maxThreshold)) {
// if auto level switch is enabled and loaded frag level is greater than 0, this error is not fatal
let fatal = !(this.hls.autoLevelEnabled && level);
observer.trigger(Event.ERROR, {type : ErrorTypes.MEDIA_ERROR, details : ErrorDetails.FRAG_LOOP_LOADING_ERROR, fatal:fatal, frag : this.frag});
if(fatal) {
this.state = this.ERROR;
}
return;
}
} else {
frag.loadCounter=1;
}
frag.loadIdx = this.fragLoadIdx;
this.frag = frag;
this.startFragmentRequested = true;
observer.trigger(Event.FRAG_LOADING, { frag: frag });
Expand Down Expand Up @@ -323,7 +341,7 @@
// in case any error occured while appending, put back segment in mp4segments table
logger.log(`error while trying to append buffer:${err.message},try appending later`);
this.mp4segments.unshift(segment);
this.appendError++;
this.appendError ? this.appendError++ : this.appendError=1;
if(this.appendError > 3) {
logger.log(`fail 3 times to append segment in sourceBuffer`);
observer.trigger(Event.ERROR, {type : ErrorTypes.MEDIA_ERROR, details : ErrorDetails.FRAG_APPENDING_ERROR, fatal : true, frag : this.frag});
Expand All @@ -343,8 +361,6 @@
if(this.flushBuffer(range.start,range.end)) {
// range flushed, remove from flush array
this.flushRange.shift();
// reset flush counter
this.flushBufferCounter = 0;
} else {
// flush in progress, come back later
break;
Expand All @@ -356,6 +372,8 @@
this.state = this.IDLE;
// reset reference to frag
this.frag = null;
// increase fragment load Index to avoid frag loop loading error after buffer flush
this.fragLoadIdx+=2*this.config.fragLoadingLoopThreshold;
}
/* if not everything flushed, stay in BUFFER_FLUSHING state. we will come back here
each time sourceBuffer updateend() callback will be triggered
Expand Down Expand Up @@ -572,6 +590,7 @@
this.frag.loader.abort();
}
// flush everything
this.flushBufferCounter = 0;
this.flushRange.push({ start : 0, end : Number.POSITIVE_INFINITY});
// trigger a sourceBuffer flush
this.state = this.BUFFER_FLUSHING;
Expand Down Expand Up @@ -625,6 +644,7 @@
}
}
if(this.flushRange.length) {
this.flushBufferCounter = 0;
// trigger a sourceBuffer flush
this.state = this.BUFFER_FLUSHING;
// speed up switching, trigger timer function
Expand Down
2 changes: 2 additions & 0 deletions src/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export var ErrorDetails = {
LEVEL_SWITCH_ERROR : 'levelSwitchError',
// Identifier for fragment load error - data: { frag : fragment object, response : XHR response}
FRAG_LOAD_ERROR : 'fragLoadError',
// Identifier for fragment loop loading error - data: { frag : fragment object}
FRAG_LOOP_LOADING_ERROR : 'fragLoopLoadingError',
// Identifier for fragment load timeout error - data: { frag : fragment object}
FRAG_LOAD_TIMEOUT : 'fragLoadTimeOut',
// Identifier for a fragment parsing error event - data: parsing error description
Expand Down
1 change: 1 addition & 0 deletions src/hls.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class Hls {
fragLoadingTimeOut : 20000,
fragLoadingMaxRetry : 3,
fragLoadingRetryDelay : 1000,
fragLoadingLoopThreshold : 3,
manifestLoadingTimeOut : 10000,
manifestLoadingMaxRetry : 3,
manifestLoadingRetryDelay : 1000,
Expand Down

0 comments on commit 7b2029f

Please sign in to comment.