1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | import videojs from 'video.js';
|
13 | import window from 'global/window';
|
14 |
|
15 | const {
|
16 | xhr: videojsXHR,
|
17 | mergeOptions
|
18 | } = videojs;
|
19 |
|
20 | const callbackWrapper = function(request, error, response, callback) {
|
21 | const reqResponse = request.responseType === 'arraybuffer' ? request.response : request.responseText;
|
22 |
|
23 | if (!error && reqResponse) {
|
24 | request.responseTime = Date.now();
|
25 | request.roundTripTime = request.responseTime - request.requestTime;
|
26 | request.bytesReceived = reqResponse.byteLength || reqResponse.length;
|
27 | if (!request.bandwidth) {
|
28 | request.bandwidth =
|
29 | Math.floor((request.bytesReceived / request.roundTripTime) * 8 * 1000);
|
30 | }
|
31 | }
|
32 |
|
33 | if (response.headers) {
|
34 | request.responseHeaders = response.headers;
|
35 | }
|
36 |
|
37 |
|
38 |
|
39 |
|
40 | if (error && error.code === 'ETIMEDOUT') {
|
41 | request.timedout = true;
|
42 | }
|
43 |
|
44 |
|
45 |
|
46 |
|
47 | if (!error &&
|
48 | !request.aborted &&
|
49 | response.statusCode !== 200 &&
|
50 | response.statusCode !== 206 &&
|
51 | response.statusCode !== 0) {
|
52 | error = new Error('XHR Failed with a response of: ' +
|
53 | (request && (reqResponse || request.responseText)));
|
54 | }
|
55 |
|
56 | callback(error, request);
|
57 | };
|
58 |
|
59 | const xhrFactory = function() {
|
60 | const xhr = function XhrFunction(options, callback) {
|
61 |
|
62 | options = mergeOptions({
|
63 | timeout: 45e3
|
64 | }, options);
|
65 |
|
66 |
|
67 |
|
68 | const beforeRequest = XhrFunction.beforeRequest || videojs.Vhs.xhr.beforeRequest;
|
69 |
|
70 | if (beforeRequest && typeof beforeRequest === 'function') {
|
71 | const newOptions = beforeRequest(options);
|
72 |
|
73 | if (newOptions) {
|
74 | options = newOptions;
|
75 | }
|
76 | }
|
77 |
|
78 |
|
79 |
|
80 | const xhrMethod = videojs.Vhs.xhr.original === true ? videojsXHR : videojs.Vhs.xhr;
|
81 |
|
82 | const request = xhrMethod(options, function(error, response) {
|
83 | return callbackWrapper(request, error, response, callback);
|
84 | });
|
85 | const originalAbort = request.abort;
|
86 |
|
87 | request.abort = function() {
|
88 | request.aborted = true;
|
89 | return originalAbort.apply(request, arguments);
|
90 | };
|
91 | request.uri = options.uri;
|
92 | request.requestTime = Date.now();
|
93 | return request;
|
94 | };
|
95 |
|
96 | xhr.original = true;
|
97 |
|
98 | return xhr;
|
99 | };
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 | export const byterangeStr = function(byterange) {
|
109 |
|
110 |
|
111 | let byterangeEnd;
|
112 | const byterangeStart = byterange.offset;
|
113 |
|
114 | if (typeof byterange.offset === 'bigint' || typeof byterange.length === 'bigint') {
|
115 | byterangeEnd = window.BigInt(byterange.offset) + window.BigInt(byterange.length) - window.BigInt(1);
|
116 | } else {
|
117 | byterangeEnd = byterange.offset + byterange.length - 1;
|
118 | }
|
119 |
|
120 | return 'bytes=' + byterangeStart + '-' + byterangeEnd;
|
121 | };
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 | const segmentXhrHeaders = function(segment) {
|
130 | const headers = {};
|
131 |
|
132 | if (segment.byterange) {
|
133 | headers.Range = byterangeStr(segment.byterange);
|
134 | }
|
135 | return headers;
|
136 | };
|
137 |
|
138 | export {segmentXhrHeaders, callbackWrapper, xhrFactory};
|
139 |
|
140 | export default xhrFactory;
|