@alessmicrosystems/mpegts.js 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +158 -0
- package/README_ja.md +153 -0
- package/README_zh.md +157 -0
- package/d.ts/mpegts.d.ts +524 -0
- package/d.ts/src/core/mse-events.d.ts +9 -0
- package/d.ts/src/core/transmuxing-events.d.ts +24 -0
- package/d.ts/src/demux/aac.d.ts +44 -0
- package/d.ts/src/demux/ac3.d.ts +70 -0
- package/d.ts/src/demux/av1-parser.d.ts +77 -0
- package/d.ts/src/demux/av1.d.ts +11 -0
- package/d.ts/src/demux/base-demuxer.d.ts +55 -0
- package/d.ts/src/demux/h264.d.ts +40 -0
- package/d.ts/src/demux/h265.d.ts +65 -0
- package/d.ts/src/demux/klv.d.ts +17 -0
- package/d.ts/src/demux/mp3.d.ts +6 -0
- package/d.ts/src/demux/mpeg4-audio.d.ts +28 -0
- package/d.ts/src/demux/pat-pmt-pes.d.ts +106 -0
- package/d.ts/src/demux/patpmt.d.ts +40 -0
- package/d.ts/src/demux/pes-private-data.d.ts +14 -0
- package/d.ts/src/demux/pgs-data.d.ts +9 -0
- package/d.ts/src/demux/scte35.d.ts +250 -0
- package/d.ts/src/demux/sei.d.ts +8 -0
- package/d.ts/src/demux/smpte2038.d.ts +22 -0
- package/d.ts/src/demux/ts-demuxer.d.ts +124 -0
- package/d.ts/src/player/live-latency-chaser.d.ts +10 -0
- package/d.ts/src/player/live-latency-synchronizer.d.ts +10 -0
- package/d.ts/src/player/loading-controller.d.ts +19 -0
- package/d.ts/src/player/mse-player.d.ts +30 -0
- package/d.ts/src/player/player-engine-dedicated-thread-worker.d.ts +2 -0
- package/d.ts/src/player/player-engine-dedicated-thread.d.ts +48 -0
- package/d.ts/src/player/player-engine-main-thread.d.ts +50 -0
- package/d.ts/src/player/player-engine-worker-cmd-def.d.ts +25 -0
- package/d.ts/src/player/player-engine-worker-msg-def.d.ts +54 -0
- package/d.ts/src/player/player-engine-worker.d.ts +2 -0
- package/d.ts/src/player/player-engine.d.ts +16 -0
- package/d.ts/src/player/player-events.d.ts +21 -0
- package/d.ts/src/player/seeking-handler.d.ts +22 -0
- package/d.ts/src/player/startup-stall-jumper.d.ts +14 -0
- package/d.ts/src/utils/typedarray-equality.d.ts +2 -0
- package/dist/mpegts.js +3 -0
- package/dist/mpegts.js.LICENSE.txt +7 -0
- package/dist/mpegts.js.map +1 -0
- package/package.json +53 -0
- package/src/config.js +67 -0
- package/src/core/features.js +88 -0
- package/src/core/media-info.js +127 -0
- package/src/core/media-segment-info.js +230 -0
- package/src/core/mse-controller.js +599 -0
- package/src/core/mse-events.ts +28 -0
- package/src/core/transmuxer.js +346 -0
- package/src/core/transmuxing-controller.js +628 -0
- package/src/core/transmuxing-events.ts +43 -0
- package/src/core/transmuxing-worker.js +286 -0
- package/src/demux/aac.ts +397 -0
- package/src/demux/ac3.ts +335 -0
- package/src/demux/amf-parser.js +243 -0
- package/src/demux/av1-parser.ts +629 -0
- package/src/demux/av1.ts +103 -0
- package/src/demux/base-demuxer.ts +69 -0
- package/src/demux/demux-errors.js +26 -0
- package/src/demux/exp-golomb.js +116 -0
- package/src/demux/flv-demuxer.js +1854 -0
- package/src/demux/h264.ts +187 -0
- package/src/demux/h265-parser.js +501 -0
- package/src/demux/h265.ts +214 -0
- package/src/demux/klv.ts +40 -0
- package/src/demux/mp3.ts +7 -0
- package/src/demux/mpeg4-audio.ts +45 -0
- package/src/demux/pat-pmt-pes.ts +132 -0
- package/src/demux/pes-private-data.ts +16 -0
- package/src/demux/pgs-data.ts +11 -0
- package/src/demux/scte35.ts +723 -0
- package/src/demux/sei.ts +99 -0
- package/src/demux/smpte2038.ts +89 -0
- package/src/demux/sps-parser.js +298 -0
- package/src/demux/ts-demuxer.ts +2405 -0
- package/src/index.js +4 -0
- package/src/io/fetch-stream-loader.js +266 -0
- package/src/io/io-controller.js +647 -0
- package/src/io/loader.js +134 -0
- package/src/io/param-seek-handler.js +85 -0
- package/src/io/range-seek-handler.js +52 -0
- package/src/io/speed-sampler.js +93 -0
- package/src/io/websocket-loader.js +151 -0
- package/src/io/xhr-moz-chunked-loader.js +211 -0
- package/src/io/xhr-msstream-loader.js +307 -0
- package/src/io/xhr-range-loader.js +366 -0
- package/src/mpegts.js +95 -0
- package/src/player/live-latency-chaser.ts +66 -0
- package/src/player/live-latency-synchronizer.ts +79 -0
- package/src/player/loading-controller.ts +142 -0
- package/src/player/mse-player.ts +150 -0
- package/src/player/native-player.js +262 -0
- package/src/player/player-engine-dedicated-thread.ts +479 -0
- package/src/player/player-engine-main-thread.ts +463 -0
- package/src/player/player-engine-worker-cmd-def.ts +62 -0
- package/src/player/player-engine-worker-msg-def.ts +102 -0
- package/src/player/player-engine-worker.ts +370 -0
- package/src/player/player-engine.ts +35 -0
- package/src/player/player-errors.js +39 -0
- package/src/player/player-events.ts +40 -0
- package/src/player/seeking-handler.ts +205 -0
- package/src/player/startup-stall-jumper.ts +86 -0
- package/src/remux/aac-silent.js +56 -0
- package/src/remux/mp4-generator.js +866 -0
- package/src/remux/mp4-remuxer.js +778 -0
- package/src/utils/browser.js +128 -0
- package/src/utils/exception.js +73 -0
- package/src/utils/logger.js +140 -0
- package/src/utils/logging-control.js +165 -0
- package/src/utils/polyfill.js +68 -0
- package/src/utils/typedarray-equality.ts +69 -0
- package/src/utils/utf8-conv.js +84 -0
- package/src/utils/webworkify-webpack.js +202 -0
- package/tsconfig.json +16 -0
- package/tslint.json +1 -0
- package/types/index.d.ts +3 -0
- package/types/test-flv.ts +8 -0
- package/types/tsconfig.json +24 -0
- package/webpack.config.js +55 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2016 Bilibili. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* @author zheng qian <xqq@xqq.im>
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import Log from '../utils/logger.js';
|
|
20
|
+
import {BaseLoader, LoaderStatus, LoaderErrors} from './loader.js';
|
|
21
|
+
import {RuntimeException} from '../utils/exception.js';
|
|
22
|
+
|
|
23
|
+
// For FireFox browser which supports `xhr.responseType = 'moz-chunked-arraybuffer'`
|
|
24
|
+
class MozChunkedLoader extends BaseLoader {
|
|
25
|
+
|
|
26
|
+
static isSupported() {
|
|
27
|
+
try {
|
|
28
|
+
let xhr = new XMLHttpRequest();
|
|
29
|
+
// Firefox 37- requires .open() to be called before setting responseType
|
|
30
|
+
xhr.open('GET', 'https://example.com', true);
|
|
31
|
+
xhr.responseType = 'moz-chunked-arraybuffer';
|
|
32
|
+
return (xhr.responseType === 'moz-chunked-arraybuffer');
|
|
33
|
+
} catch (e) {
|
|
34
|
+
Log.w('MozChunkedLoader', e.message);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
constructor(seekHandler, config) {
|
|
40
|
+
super('xhr-moz-chunked-loader');
|
|
41
|
+
this.TAG = 'MozChunkedLoader';
|
|
42
|
+
|
|
43
|
+
this._seekHandler = seekHandler;
|
|
44
|
+
this._config = config;
|
|
45
|
+
this._needStash = true;
|
|
46
|
+
|
|
47
|
+
this._xhr = null;
|
|
48
|
+
this._requestAbort = false;
|
|
49
|
+
this._contentLength = null;
|
|
50
|
+
this._receivedLength = 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
destroy() {
|
|
54
|
+
if (this.isWorking()) {
|
|
55
|
+
this.abort();
|
|
56
|
+
}
|
|
57
|
+
if (this._xhr) {
|
|
58
|
+
this._xhr.onreadystatechange = null;
|
|
59
|
+
this._xhr.onprogress = null;
|
|
60
|
+
this._xhr.onloadend = null;
|
|
61
|
+
this._xhr.onerror = null;
|
|
62
|
+
this._xhr = null;
|
|
63
|
+
}
|
|
64
|
+
super.destroy();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
open(dataSource, range) {
|
|
68
|
+
this._dataSource = dataSource;
|
|
69
|
+
this._range = range;
|
|
70
|
+
|
|
71
|
+
let sourceURL = dataSource.url;
|
|
72
|
+
if (this._config.reuseRedirectedURL && dataSource.redirectedURL != undefined) {
|
|
73
|
+
sourceURL = dataSource.redirectedURL;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let seekConfig = this._seekHandler.getConfig(sourceURL, range);
|
|
77
|
+
this._requestURL = seekConfig.url;
|
|
78
|
+
|
|
79
|
+
let xhr = this._xhr = new XMLHttpRequest();
|
|
80
|
+
xhr.open('GET', seekConfig.url, true);
|
|
81
|
+
xhr.responseType = 'moz-chunked-arraybuffer';
|
|
82
|
+
xhr.onreadystatechange = this._onReadyStateChange.bind(this);
|
|
83
|
+
xhr.onprogress = this._onProgress.bind(this);
|
|
84
|
+
xhr.onloadend = this._onLoadEnd.bind(this);
|
|
85
|
+
xhr.onerror = this._onXhrError.bind(this);
|
|
86
|
+
|
|
87
|
+
// cors is auto detected and enabled by xhr
|
|
88
|
+
|
|
89
|
+
// withCredentials is disabled by default
|
|
90
|
+
if (dataSource.withCredentials) {
|
|
91
|
+
xhr.withCredentials = true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (typeof seekConfig.headers === 'object') {
|
|
95
|
+
let headers = seekConfig.headers;
|
|
96
|
+
|
|
97
|
+
for (let key in headers) {
|
|
98
|
+
if (headers.hasOwnProperty(key)) {
|
|
99
|
+
xhr.setRequestHeader(key, headers[key]);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// add additional headers
|
|
105
|
+
if (typeof this._config.headers === 'object') {
|
|
106
|
+
let headers = this._config.headers;
|
|
107
|
+
|
|
108
|
+
for (let key in headers) {
|
|
109
|
+
if (headers.hasOwnProperty(key)) {
|
|
110
|
+
xhr.setRequestHeader(key, headers[key]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this._status = LoaderStatus.kConnecting;
|
|
116
|
+
xhr.send();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
abort() {
|
|
120
|
+
this._requestAbort = true;
|
|
121
|
+
if (this._xhr) {
|
|
122
|
+
this._xhr.abort();
|
|
123
|
+
}
|
|
124
|
+
this._status = LoaderStatus.kComplete;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
_onReadyStateChange(e) {
|
|
128
|
+
let xhr = e.target;
|
|
129
|
+
|
|
130
|
+
if (xhr.readyState === 2) { // HEADERS_RECEIVED
|
|
131
|
+
if (xhr.responseURL != undefined && xhr.responseURL !== this._requestURL) {
|
|
132
|
+
if (this._onURLRedirect) {
|
|
133
|
+
let redirectedURL = this._seekHandler.removeURLParameters(xhr.responseURL);
|
|
134
|
+
this._onURLRedirect(redirectedURL);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (xhr.status !== 0 && (xhr.status < 200 || xhr.status > 299)) {
|
|
139
|
+
this._status = LoaderStatus.kError;
|
|
140
|
+
if (this._onError) {
|
|
141
|
+
this._onError(LoaderErrors.HTTP_STATUS_CODE_INVALID, {code: xhr.status, msg: xhr.statusText});
|
|
142
|
+
} else {
|
|
143
|
+
throw new RuntimeException('MozChunkedLoader: Http code invalid, ' + xhr.status + ' ' + xhr.statusText);
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
this._status = LoaderStatus.kBuffering;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
_onProgress(e) {
|
|
152
|
+
if (this._status === LoaderStatus.kError) {
|
|
153
|
+
// Ignore error response
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (this._contentLength === null) {
|
|
158
|
+
if (e.total !== null && e.total !== 0) {
|
|
159
|
+
this._contentLength = e.total;
|
|
160
|
+
if (this._onContentLengthKnown) {
|
|
161
|
+
this._onContentLengthKnown(this._contentLength);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let chunk = e.target.response;
|
|
167
|
+
let byteStart = this._range.from + this._receivedLength;
|
|
168
|
+
this._receivedLength += chunk.byteLength;
|
|
169
|
+
|
|
170
|
+
if (this._onDataArrival) {
|
|
171
|
+
this._onDataArrival(chunk, byteStart, this._receivedLength);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
_onLoadEnd(e) {
|
|
176
|
+
if (this._requestAbort === true) {
|
|
177
|
+
this._requestAbort = false;
|
|
178
|
+
return;
|
|
179
|
+
} else if (this._status === LoaderStatus.kError) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
this._status = LoaderStatus.kComplete;
|
|
184
|
+
if (this._onComplete) {
|
|
185
|
+
this._onComplete(this._range.from, this._range.from + this._receivedLength - 1);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
_onXhrError(e) {
|
|
190
|
+
this._status = LoaderStatus.kError;
|
|
191
|
+
let type = 0;
|
|
192
|
+
let info = null;
|
|
193
|
+
|
|
194
|
+
if (this._contentLength && e.loaded < this._contentLength) {
|
|
195
|
+
type = LoaderErrors.EARLY_EOF;
|
|
196
|
+
info = {code: -1, msg: 'Moz-Chunked stream meet Early-Eof'};
|
|
197
|
+
} else {
|
|
198
|
+
type = LoaderErrors.EXCEPTION;
|
|
199
|
+
info = {code: -1, msg: e.constructor.name + ' ' + e.type};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (this._onError) {
|
|
203
|
+
this._onError(type, info);
|
|
204
|
+
} else {
|
|
205
|
+
throw new RuntimeException(info.msg);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export default MozChunkedLoader;
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2016 Bilibili. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* @author zheng qian <xqq@xqq.im>
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import Log from '../utils/logger.js';
|
|
20
|
+
import {BaseLoader, LoaderStatus, LoaderErrors} from './loader.js';
|
|
21
|
+
import {RuntimeException} from '../utils/exception.js';
|
|
22
|
+
|
|
23
|
+
/* Notice: ms-stream may cause IE/Edge browser crash if seek too frequently!!!
|
|
24
|
+
* The browser may crash in wininet.dll. Disable for now.
|
|
25
|
+
*
|
|
26
|
+
* For IE11/Edge browser by microsoft which supports `xhr.responseType = 'ms-stream'`
|
|
27
|
+
* Notice that ms-stream API sucks. The buffer is always expanding along with downloading.
|
|
28
|
+
*
|
|
29
|
+
* We need to abort the xhr if buffer size exceeded limit size (e.g. 16 MiB), then do reconnect.
|
|
30
|
+
* in order to release previous ArrayBuffer to avoid memory leak
|
|
31
|
+
*
|
|
32
|
+
* Otherwise, the ArrayBuffer will increase to a terrible size that equals final file size.
|
|
33
|
+
*/
|
|
34
|
+
class MSStreamLoader extends BaseLoader {
|
|
35
|
+
|
|
36
|
+
static isSupported() {
|
|
37
|
+
try {
|
|
38
|
+
if (typeof self.MSStream === 'undefined' || typeof self.MSStreamReader === 'undefined') {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let xhr = new XMLHttpRequest();
|
|
43
|
+
xhr.open('GET', 'https://example.com', true);
|
|
44
|
+
xhr.responseType = 'ms-stream';
|
|
45
|
+
return (xhr.responseType === 'ms-stream');
|
|
46
|
+
} catch (e) {
|
|
47
|
+
Log.w('MSStreamLoader', e.message);
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
constructor(seekHandler, config) {
|
|
53
|
+
super('xhr-msstream-loader');
|
|
54
|
+
this.TAG = 'MSStreamLoader';
|
|
55
|
+
|
|
56
|
+
this._seekHandler = seekHandler;
|
|
57
|
+
this._config = config;
|
|
58
|
+
this._needStash = true;
|
|
59
|
+
|
|
60
|
+
this._xhr = null;
|
|
61
|
+
this._reader = null; // MSStreamReader
|
|
62
|
+
|
|
63
|
+
this._totalRange = null;
|
|
64
|
+
this._currentRange = null;
|
|
65
|
+
|
|
66
|
+
this._currentRequestURL = null;
|
|
67
|
+
this._currentRedirectedURL = null;
|
|
68
|
+
|
|
69
|
+
this._contentLength = null;
|
|
70
|
+
this._receivedLength = 0;
|
|
71
|
+
|
|
72
|
+
this._bufferLimit = 16 * 1024 * 1024; // 16MB
|
|
73
|
+
this._lastTimeBufferSize = 0;
|
|
74
|
+
this._isReconnecting = false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
destroy() {
|
|
78
|
+
if (this.isWorking()) {
|
|
79
|
+
this.abort();
|
|
80
|
+
}
|
|
81
|
+
if (this._reader) {
|
|
82
|
+
this._reader.onprogress = null;
|
|
83
|
+
this._reader.onload = null;
|
|
84
|
+
this._reader.onerror = null;
|
|
85
|
+
this._reader = null;
|
|
86
|
+
}
|
|
87
|
+
if (this._xhr) {
|
|
88
|
+
this._xhr.onreadystatechange = null;
|
|
89
|
+
this._xhr = null;
|
|
90
|
+
}
|
|
91
|
+
super.destroy();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
open(dataSource, range) {
|
|
95
|
+
this._internalOpen(dataSource, range, false);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
_internalOpen(dataSource, range, isSubrange) {
|
|
99
|
+
this._dataSource = dataSource;
|
|
100
|
+
|
|
101
|
+
if (!isSubrange) {
|
|
102
|
+
this._totalRange = range;
|
|
103
|
+
} else {
|
|
104
|
+
this._currentRange = range;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let sourceURL = dataSource.url;
|
|
108
|
+
if (this._config.reuseRedirectedURL) {
|
|
109
|
+
if (this._currentRedirectedURL != undefined) {
|
|
110
|
+
sourceURL = this._currentRedirectedURL;
|
|
111
|
+
} else if (dataSource.redirectedURL != undefined) {
|
|
112
|
+
sourceURL = dataSource.redirectedURL;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let seekConfig = this._seekHandler.getConfig(sourceURL, range);
|
|
117
|
+
this._currentRequestURL = seekConfig.url;
|
|
118
|
+
|
|
119
|
+
let reader = this._reader = new self.MSStreamReader();
|
|
120
|
+
reader.onprogress = this._msrOnProgress.bind(this);
|
|
121
|
+
reader.onload = this._msrOnLoad.bind(this);
|
|
122
|
+
reader.onerror = this._msrOnError.bind(this);
|
|
123
|
+
|
|
124
|
+
let xhr = this._xhr = new XMLHttpRequest();
|
|
125
|
+
xhr.open('GET', seekConfig.url, true);
|
|
126
|
+
xhr.responseType = 'ms-stream';
|
|
127
|
+
xhr.onreadystatechange = this._xhrOnReadyStateChange.bind(this);
|
|
128
|
+
xhr.onerror = this._xhrOnError.bind(this);
|
|
129
|
+
|
|
130
|
+
if (dataSource.withCredentials) {
|
|
131
|
+
xhr.withCredentials = true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (typeof seekConfig.headers === 'object') {
|
|
135
|
+
let headers = seekConfig.headers;
|
|
136
|
+
|
|
137
|
+
for (let key in headers) {
|
|
138
|
+
if (headers.hasOwnProperty(key)) {
|
|
139
|
+
xhr.setRequestHeader(key, headers[key]);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// add additional headers
|
|
145
|
+
if (typeof this._config.headers === 'object') {
|
|
146
|
+
let headers = this._config.headers;
|
|
147
|
+
|
|
148
|
+
for (let key in headers) {
|
|
149
|
+
if (headers.hasOwnProperty(key)) {
|
|
150
|
+
xhr.setRequestHeader(key, headers[key]);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (this._isReconnecting) {
|
|
156
|
+
this._isReconnecting = false;
|
|
157
|
+
} else {
|
|
158
|
+
this._status = LoaderStatus.kConnecting;
|
|
159
|
+
}
|
|
160
|
+
xhr.send();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
abort() {
|
|
164
|
+
this._internalAbort();
|
|
165
|
+
this._status = LoaderStatus.kComplete;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
_internalAbort() {
|
|
169
|
+
if (this._reader) {
|
|
170
|
+
if (this._reader.readyState === 1) { // LOADING
|
|
171
|
+
this._reader.abort();
|
|
172
|
+
}
|
|
173
|
+
this._reader.onprogress = null;
|
|
174
|
+
this._reader.onload = null;
|
|
175
|
+
this._reader.onerror = null;
|
|
176
|
+
this._reader = null;
|
|
177
|
+
}
|
|
178
|
+
if (this._xhr) {
|
|
179
|
+
this._xhr.abort();
|
|
180
|
+
this._xhr.onreadystatechange = null;
|
|
181
|
+
this._xhr = null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
_xhrOnReadyStateChange(e) {
|
|
186
|
+
let xhr = e.target;
|
|
187
|
+
|
|
188
|
+
if (xhr.readyState === 2) { // HEADERS_RECEIVED
|
|
189
|
+
if (xhr.status >= 200 && xhr.status <= 299) {
|
|
190
|
+
this._status = LoaderStatus.kBuffering;
|
|
191
|
+
|
|
192
|
+
if (xhr.responseURL != undefined) {
|
|
193
|
+
let redirectedURL = this._seekHandler.removeURLParameters(xhr.responseURL);
|
|
194
|
+
if (xhr.responseURL !== this._currentRequestURL && redirectedURL !== this._currentRedirectedURL) {
|
|
195
|
+
this._currentRedirectedURL = redirectedURL;
|
|
196
|
+
if (this._onURLRedirect) {
|
|
197
|
+
this._onURLRedirect(redirectedURL);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
let lengthHeader = xhr.getResponseHeader('Content-Length');
|
|
203
|
+
if (lengthHeader != null && this._contentLength == null) {
|
|
204
|
+
let length = parseInt(lengthHeader);
|
|
205
|
+
if (length > 0) {
|
|
206
|
+
this._contentLength = length;
|
|
207
|
+
if (this._onContentLengthKnown) {
|
|
208
|
+
this._onContentLengthKnown(this._contentLength);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
this._status = LoaderStatus.kError;
|
|
214
|
+
if (this._onError) {
|
|
215
|
+
this._onError(LoaderErrors.HTTP_STATUS_CODE_INVALID, {code: xhr.status, msg: xhr.statusText});
|
|
216
|
+
} else {
|
|
217
|
+
throw new RuntimeException('MSStreamLoader: Http code invalid, ' + xhr.status + ' ' + xhr.statusText);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
} else if (xhr.readyState === 3) { // LOADING
|
|
221
|
+
if (xhr.status >= 200 && xhr.status <= 299) {
|
|
222
|
+
this._status = LoaderStatus.kBuffering;
|
|
223
|
+
|
|
224
|
+
let msstream = xhr.response;
|
|
225
|
+
this._reader.readAsArrayBuffer(msstream);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
_xhrOnError(e) {
|
|
231
|
+
this._status = LoaderStatus.kError;
|
|
232
|
+
let type = LoaderErrors.EXCEPTION;
|
|
233
|
+
let info = {code: -1, msg: e.constructor.name + ' ' + e.type};
|
|
234
|
+
|
|
235
|
+
if (this._onError) {
|
|
236
|
+
this._onError(type, info);
|
|
237
|
+
} else {
|
|
238
|
+
throw new RuntimeException(info.msg);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
_msrOnProgress(e) {
|
|
243
|
+
let reader = e.target;
|
|
244
|
+
let bigbuffer = reader.result;
|
|
245
|
+
if (bigbuffer == null) { // result may be null, workaround for buggy M$
|
|
246
|
+
this._doReconnectIfNeeded();
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
let slice = bigbuffer.slice(this._lastTimeBufferSize);
|
|
251
|
+
this._lastTimeBufferSize = bigbuffer.byteLength;
|
|
252
|
+
let byteStart = this._totalRange.from + this._receivedLength;
|
|
253
|
+
this._receivedLength += slice.byteLength;
|
|
254
|
+
|
|
255
|
+
if (this._onDataArrival) {
|
|
256
|
+
this._onDataArrival(slice, byteStart, this._receivedLength);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (bigbuffer.byteLength >= this._bufferLimit) {
|
|
260
|
+
Log.v(this.TAG, `MSStream buffer exceeded max size near ${byteStart + slice.byteLength}, reconnecting...`);
|
|
261
|
+
this._doReconnectIfNeeded();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
_doReconnectIfNeeded() {
|
|
266
|
+
if (this._contentLength == null || this._receivedLength < this._contentLength) {
|
|
267
|
+
this._isReconnecting = true;
|
|
268
|
+
this._lastTimeBufferSize = 0;
|
|
269
|
+
this._internalAbort();
|
|
270
|
+
|
|
271
|
+
let range = {
|
|
272
|
+
from: this._totalRange.from + this._receivedLength,
|
|
273
|
+
to: -1
|
|
274
|
+
};
|
|
275
|
+
this._internalOpen(this._dataSource, range, true);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
_msrOnLoad(e) { // actually it is onComplete event
|
|
280
|
+
this._status = LoaderStatus.kComplete;
|
|
281
|
+
if (this._onComplete) {
|
|
282
|
+
this._onComplete(this._totalRange.from, this._totalRange.from + this._receivedLength - 1);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
_msrOnError(e) {
|
|
287
|
+
this._status = LoaderStatus.kError;
|
|
288
|
+
let type = 0;
|
|
289
|
+
let info = null;
|
|
290
|
+
|
|
291
|
+
if (this._contentLength && this._receivedLength < this._contentLength) {
|
|
292
|
+
type = LoaderErrors.EARLY_EOF;
|
|
293
|
+
info = {code: -1, msg: 'MSStream meet Early-Eof'};
|
|
294
|
+
} else {
|
|
295
|
+
type = LoaderErrors.EARLY_EOF;
|
|
296
|
+
info = {code: -1, msg: e.constructor.name + ' ' + e.type};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (this._onError) {
|
|
300
|
+
this._onError(type, info);
|
|
301
|
+
} else {
|
|
302
|
+
throw new RuntimeException(info.msg);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export default MSStreamLoader;
|