mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-16 16:16:40 +03:00
40f9113bb2
When the network becomes slow, we check if stopping the current request and download the content with lower resolution is faster. If so, abort the current request and start a new one. Issue #1051 Change-Id: I588e524469432e362361d1cfbde6cd45c2009959
143 lines
4.8 KiB
JavaScript
143 lines
4.8 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2016 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
goog.provide('shaka.net.HttpXHRPlugin');
|
|
|
|
goog.require('goog.asserts');
|
|
goog.require('shaka.net.HttpPluginUtils');
|
|
goog.require('shaka.net.NetworkingEngine');
|
|
goog.require('shaka.util.AbortableOperation');
|
|
goog.require('shaka.util.Error');
|
|
|
|
|
|
/**
|
|
* @namespace
|
|
* @summary A networking plugin to handle http and https URIs via XHR.
|
|
* @param {string} uri
|
|
* @param {shaka.extern.Request} request
|
|
* @param {shaka.net.NetworkingEngine.RequestType} requestType
|
|
* @param {shaka.extern.ProgressUpdated=} progressUpdated Called when a
|
|
* progress event happened.
|
|
* @return {!shaka.extern.IAbortableOperation.<shaka.extern.Response>}
|
|
* @export
|
|
*/
|
|
shaka.net.HttpXHRPlugin = function(uri, request, requestType, progressUpdated) {
|
|
let xhr = new shaka.net.HttpXHRPlugin.Xhr_();
|
|
|
|
// Last time stamp when we got a progress event.
|
|
let lastTime = Date.now();
|
|
// Last number of bytes loaded, from progress event.
|
|
let lastLoaded = 0;
|
|
|
|
let promise = new Promise(function(resolve, reject) {
|
|
xhr.open(request.method, uri, true);
|
|
xhr.responseType = 'arraybuffer';
|
|
xhr.timeout = request.retryParameters.timeout;
|
|
xhr.withCredentials = request.allowCrossSiteCredentials;
|
|
|
|
xhr.onabort = function() {
|
|
reject(new shaka.util.Error(
|
|
shaka.util.Error.Severity.RECOVERABLE,
|
|
shaka.util.Error.Category.NETWORK,
|
|
shaka.util.Error.Code.OPERATION_ABORTED,
|
|
uri, requestType));
|
|
};
|
|
xhr.onload = function(event) {
|
|
let target = event.target;
|
|
goog.asserts.assert(target, 'XHR onload has no target!');
|
|
// Since IE and Edge incorrectly return the header with a leading new line
|
|
// character ('\n'), we trim the header here.
|
|
const headerLines = target.getAllResponseHeaders().trim().split('\r\n');
|
|
const headers = {};
|
|
for (const header of headerLines) {
|
|
/** @type {!Array.<string>} */
|
|
const parts = header.split(': ');
|
|
headers[parts[0].toLowerCase()] = parts.slice(1).join(': ');
|
|
}
|
|
|
|
try {
|
|
let response = shaka.net.HttpPluginUtils.makeResponse(headers,
|
|
target.response, target.status, uri, target.responseURL,
|
|
requestType);
|
|
resolve(response);
|
|
} catch (error) {
|
|
goog.asserts.assert(error instanceof shaka.util.Error,
|
|
'Wrong error type!');
|
|
reject(error);
|
|
}
|
|
};
|
|
xhr.onerror = function(event) {
|
|
reject(new shaka.util.Error(
|
|
shaka.util.Error.Severity.RECOVERABLE,
|
|
shaka.util.Error.Category.NETWORK,
|
|
shaka.util.Error.Code.HTTP_ERROR,
|
|
uri, event, requestType));
|
|
};
|
|
xhr.ontimeout = function(event) {
|
|
reject(new shaka.util.Error(
|
|
shaka.util.Error.Severity.RECOVERABLE,
|
|
shaka.util.Error.Category.NETWORK,
|
|
shaka.util.Error.Code.TIMEOUT,
|
|
uri, requestType));
|
|
};
|
|
xhr.onprogress = function(event) {
|
|
let currentTime = Date.now();
|
|
// If the time between last time and this time we got progress event
|
|
// is long enough, or if a whole segment is downloaded, call
|
|
// progressUpdated().
|
|
if (currentTime - lastTime > 100 ||
|
|
(event.lengthComputable && event.loaded == event.total)) {
|
|
progressUpdated(currentTime - lastTime, event.loaded - lastLoaded,
|
|
event.total - event.loaded);
|
|
lastLoaded = event.loaded;
|
|
lastTime = currentTime;
|
|
}
|
|
};
|
|
|
|
for (let key in request.headers) {
|
|
// The Fetch API automatically normalizes outgoing header keys to
|
|
// lowercase. For consistency's sake, do it here too.
|
|
let lowercasedKey = key.toLowerCase();
|
|
xhr.setRequestHeader(lowercasedKey, request.headers[key]);
|
|
}
|
|
xhr.send(request.body);
|
|
});
|
|
|
|
return new shaka.util.AbortableOperation(
|
|
promise,
|
|
() => {
|
|
xhr.abort();
|
|
return Promise.resolve();
|
|
});
|
|
};
|
|
|
|
|
|
/**
|
|
* Overridden in unit tests, but compiled out in production.
|
|
*
|
|
* @const {function(new: XMLHttpRequest)}
|
|
* @private
|
|
*/
|
|
shaka.net.HttpXHRPlugin.Xhr_ = window.XMLHttpRequest;
|
|
|
|
|
|
shaka.net.NetworkingEngine.registerScheme('http', shaka.net.HttpXHRPlugin,
|
|
shaka.net.NetworkingEngine.PluginPriority.FALLBACK);
|
|
shaka.net.NetworkingEngine.registerScheme('https', shaka.net.HttpXHRPlugin,
|
|
shaka.net.NetworkingEngine.PluginPriority.FALLBACK);
|
|
|