Skip to content
This repository has been archived by the owner on Jan 16, 2023. It is now read-only.

Commit

Permalink
Add a fragment request timeout (Dash-Industry-Forum#3422)
Browse files Browse the repository at this point in the history
* Created test for fragment request timeout set

* Exposed setting fragment timeouts on media player interface

* Added logging to report HTTPLoader ontimeout callback

* Update to use settings instead of functions on MediaPlayer

* Add fragmentRequestTimeout JSDoc and type definition, and default to 0 when NaN.

Co-authored-by: magnuswoody <magnus.woodgate@bbc.co.uk>
  • Loading branch information
2 people authored and bbert committed Nov 4, 2020
1 parent 236c2d6 commit 3f3a001
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 3 deletions.
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ declare namespace dashjs {
audio?: TrackSwitchMode;
}
selectionModeForInitialTrack?: TrackSelectionMode
fragmentRequestTimeout?: number;
retryIntervals?: {
'MPD'?: number;
'XLinkExpansion'?: number;
Expand Down
3 changes: 3 additions & 0 deletions src/core/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
* lastBitrateCachingInfo: { enabled: true, ttl: 360000 },
* lastMediaSettingsCachingInfo: { enabled: true, ttl: 360000 },
* cacheLoadThresholds: { video: 50, audio: 5 },
* fragmentRequestTimeout: 0,
* retryIntervals: {
* MPD: 500,
* XLinkExpansion: 500,
Expand Down Expand Up @@ -331,6 +332,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
* @property {module:Settings~AudioVideoSettings} [cacheLoadThresholds={video: 50, audio: 5}]
* For a given media type, the threshold which defines if the response to a fragment
* request is coming from browser cache or not.
* @property {module:Settings~RequestTypeSettings} [fragmentRequestTimeout] Time in milliseconds before timing out on loading a media fragment. Fragments that timeout are retried as if they failed.
* @property {module:Settings~RequestTypeSettings} [retryIntervals] Time in milliseconds of which to reload a failed file load attempt. For low latency mode these values are divided by lowLatencyReductionFactor.
* @property {module:Settings~RequestTypeSettings} [retryAttempts] Total number of retry attempts that will occur on a file load before it fails. For low latency mode these values are multiplied by lowLatencyMultiplyFactor.
* @property {module:Settings~AbrSettings} abr Adaptive Bitrate algorithm related settings.
Expand Down Expand Up @@ -419,6 +421,7 @@ function Settings() {
cacheLoadThresholds: {video: 50, audio: 5},
trackSwitchMode: {audio: Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE, video: Constants.TRACK_SWITCH_MODE_NEVER_REPLACE},
selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE,
fragmentRequestTimeout: 0,
retryIntervals: {
[HTTPRequest.MPD_TYPE]: 500,
[HTTPRequest.XLINK_EXPANSION_TYPE]: 500,
Expand Down
3 changes: 2 additions & 1 deletion src/streaming/FragmentLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ function FragmentLoader(config) {
urlUtils: urlUtils,
constants: Constants,
boxParser: config.boxParser,
dashConstants: config.dashConstants
dashConstants: config.dashConstants,
requestTimeout: config.settings.get().streaming.fragmentRequestTimeout
});
}

Expand Down
21 changes: 19 additions & 2 deletions src/streaming/net/HTTPLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import FactoryMaker from '../../core/FactoryMaker';
import DashJSError from '../vo/DashJSError';
import CmcdModel from '../models/CmcdModel';
import Utils from '../../core/Utils';
import Debug from '../../core/Debug';

/**
* @module HTTPLoader
Expand All @@ -54,15 +55,18 @@ function HTTPLoader(cfg) {
const boxParser = cfg.boxParser;
const useFetch = cfg.useFetch || false;
const errors = cfg.errors;
const requestTimeout = cfg.requestTimeout || 0;

let instance,
requests,
delayedRequests,
retryRequests,
downloadErrorToRequestTypeMap,
cmcdModel;
cmcdModel,
logger;

function setup() {
logger = Debug(context).getInstance().getLogger(instance);
requests = [];
delayedRequests = [];
retryRequests = [];
Expand Down Expand Up @@ -204,6 +208,17 @@ function HTTPLoader(cfg) {
}
};

const ontimeout = function (event) {
let timeoutMessage;
if (event.lengthComputable) {
let percentageComplete = (event.loaded / event.total) * 100;
timeoutMessage = 'Request timeout: loaded: ' + event.loaded + ', out of: ' + event.total + ' : ' + percentageComplete.toFixed(3) + '% Completed';
} else {
timeoutMessage = 'Request timeout: non-computable download size';
}
logger.warn(timeoutMessage);
};

let loader;
if (useFetch && window.fetch && request.responseType === 'arraybuffer' && request.type === HTTPRequest.MEDIA_SEGMENT_TYPE) {
loader = FetchLoader(context).create({
Expand Down Expand Up @@ -233,7 +248,9 @@ function HTTPLoader(cfg) {
onerror: onloadend,
progress: progress,
onabort: onabort,
loader: loader
ontimeout: ontimeout,
loader: loader,
timeout: requestTimeout
};

// Adds the ability to delay single fragment loading time to control buffer.
Expand Down
1 change: 1 addition & 0 deletions src/streaming/net/URLLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ function URLLoader(cfg) {
constants: cfg.constants ? cfg.constants : null,
dashConstants: cfg.dashConstants ? cfg.dashConstants : null,
urlUtils: cfg.urlUtils ? cfg.urlUtils : null,
requestTimeout: !isNaN(cfg.requestTimeout) ? cfg.requestTimeout : 0,
errors: cfg.errors
});

Expand Down
2 changes: 2 additions & 0 deletions src/streaming/net/XHRLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ function XHRLoader(cfg) {
xhr.onerror = httpRequest.onerror;
xhr.onprogress = httpRequest.progress;
xhr.onabort = httpRequest.onabort;
xhr.ontimeout = httpRequest.ontimeout;
xhr.timeout = httpRequest.timeout;

xhr.send();

Expand Down
14 changes: 14 additions & 0 deletions test/unit/streaming.net.XHRLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,18 @@ describe('XHRLoader', function () {
sinon.assert.notCalled(callbackAbort);
expect(callbackError.calledBefore(callbackCompleted)).to.be.true; // jshint ignore:line
});

it('should set timeout on the sending XHR request', () => {
xhrLoader = XHRLoader(context).create({
requestModifier: requestModifier
});
const request = {
request: {
checkExistenceOnly: true
},
timeout: 100
};
xhrLoader.load(request);
expect(request.response.timeout).to.be.equal(100);
});
});

0 comments on commit 3f3a001

Please sign in to comment.