hls.js 1.5.2-0.canary.9924 → 1.5.2
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/dist/hls-demo.js +0 -5
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +686 -762
- package/dist/hls.js.d.ts +47 -49
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +471 -563
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +329 -409
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +500 -559
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/dist/hls.worker.js.map +1 -1
- package/package.json +9 -9
- package/src/config.ts +2 -3
- package/src/controller/abr-controller.ts +22 -23
- package/src/controller/audio-stream-controller.ts +14 -11
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +7 -7
- package/src/controller/base-stream-controller.ts +29 -42
- package/src/controller/buffer-controller.ts +11 -10
- package/src/controller/cap-level-controller.ts +2 -1
- package/src/controller/content-steering-controller.ts +6 -8
- package/src/controller/eme-controller.ts +22 -9
- package/src/controller/error-controller.ts +8 -6
- package/src/controller/fps-controller.ts +3 -2
- package/src/controller/gap-controller.ts +10 -16
- package/src/controller/latency-controller.ts +11 -9
- package/src/controller/level-controller.ts +19 -8
- package/src/controller/stream-controller.ts +29 -20
- package/src/controller/subtitle-stream-controller.ts +14 -13
- package/src/controller/subtitle-track-controller.ts +3 -5
- package/src/controller/timeline-controller.ts +30 -23
- package/src/crypt/aes-crypto.ts +2 -21
- package/src/crypt/decrypter.ts +18 -32
- package/src/crypt/fast-aes-key.ts +5 -24
- package/src/demux/audio/adts.ts +4 -9
- package/src/demux/sample-aes.ts +0 -2
- package/src/demux/transmuxer-interface.ts +12 -4
- package/src/demux/transmuxer-worker.ts +4 -4
- package/src/demux/transmuxer.ts +3 -16
- package/src/demux/tsdemuxer.ts +17 -12
- package/src/hls.ts +20 -32
- package/src/loader/fragment-loader.ts +2 -9
- package/src/loader/key-loader.ts +0 -2
- package/src/loader/level-key.ts +9 -10
- package/src/remux/mp4-remuxer.ts +3 -4
- package/src/task-loop.ts +2 -5
- package/src/types/demuxer.ts +0 -1
- package/src/utils/codecs.ts +4 -33
- package/src/utils/logger.ts +24 -53
- package/src/crypt/decrypter-aes-mode.ts +0 -4
- package/src/utils/encryption-methods-util.ts +0 -21
@@ -28,6 +28,7 @@ import type {
|
|
28
28
|
BufferFlushingData,
|
29
29
|
FragLoadingData,
|
30
30
|
} from '../types/events';
|
31
|
+
import { logger } from '../utils/logger';
|
31
32
|
import type Hls from '../hls';
|
32
33
|
import type { ComponentAPI } from '../types/component-api';
|
33
34
|
import type { HlsConfig } from '../config';
|
@@ -135,12 +136,17 @@ export class TimelineController implements ComponentAPI {
|
|
135
136
|
}
|
136
137
|
|
137
138
|
private initCea608Parsers() {
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
139
|
+
if (
|
140
|
+
this.config.enableCEA708Captions &&
|
141
|
+
(!this.cea608Parser1 || !this.cea608Parser2)
|
142
|
+
) {
|
143
|
+
const channel1 = new OutputFilter(this, 'textTrack1');
|
144
|
+
const channel2 = new OutputFilter(this, 'textTrack2');
|
145
|
+
const channel3 = new OutputFilter(this, 'textTrack3');
|
146
|
+
const channel4 = new OutputFilter(this, 'textTrack4');
|
147
|
+
this.cea608Parser1 = new Cea608Parser(1, channel1, channel2);
|
148
|
+
this.cea608Parser2 = new Cea608Parser(3, channel3, channel4);
|
149
|
+
}
|
144
150
|
}
|
145
151
|
|
146
152
|
public addCues(
|
@@ -404,7 +410,7 @@ export class TimelineController implements ComponentAPI {
|
|
404
410
|
.filter((t) => t !== null)
|
405
411
|
.map((t) => (t as TextTrack).label);
|
406
412
|
if (unusedTextTracks.length) {
|
407
|
-
|
413
|
+
logger.warn(
|
408
414
|
`Media element contains unused subtitle tracks: ${unusedTextTracks.join(
|
409
415
|
', ',
|
410
416
|
)}. Replace media element for each source to clear TextTracks and captions menu.`,
|
@@ -462,19 +468,21 @@ export class TimelineController implements ComponentAPI {
|
|
462
468
|
}
|
463
469
|
|
464
470
|
private onFragLoading(event: Events.FRAG_LOADING, data: FragLoadingData) {
|
471
|
+
this.initCea608Parsers();
|
472
|
+
const { cea608Parser1, cea608Parser2, lastCc, lastSn, lastPartIndex } =
|
473
|
+
this;
|
474
|
+
if (!this.enabled || !cea608Parser1 || !cea608Parser2) {
|
475
|
+
return;
|
476
|
+
}
|
465
477
|
// if this frag isn't contiguous, clear the parser so cues with bad start/end times aren't added to the textTrack
|
466
|
-
if (
|
467
|
-
const { cea608Parser1, cea608Parser2, lastSn } = this;
|
468
|
-
if (!cea608Parser1 || !cea608Parser2) {
|
469
|
-
return;
|
470
|
-
}
|
478
|
+
if (data.frag.type === PlaylistLevelType.MAIN) {
|
471
479
|
const { cc, sn } = data.frag;
|
472
|
-
const partIndex = data
|
480
|
+
const partIndex = data?.part?.index ?? -1;
|
473
481
|
if (
|
474
482
|
!(
|
475
483
|
sn === lastSn + 1 ||
|
476
|
-
(sn === lastSn && partIndex ===
|
477
|
-
cc ===
|
484
|
+
(sn === lastSn && partIndex === lastPartIndex + 1) ||
|
485
|
+
cc === lastCc
|
478
486
|
)
|
479
487
|
) {
|
480
488
|
cea608Parser1.reset();
|
@@ -542,7 +550,7 @@ export class TimelineController implements ComponentAPI {
|
|
542
550
|
});
|
543
551
|
},
|
544
552
|
(error) => {
|
545
|
-
|
553
|
+
logger.log(`Failed to parse IMSC1: ${error}`);
|
546
554
|
hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, {
|
547
555
|
success: false,
|
548
556
|
frag: frag,
|
@@ -589,7 +597,7 @@ export class TimelineController implements ComponentAPI {
|
|
589
597
|
this._fallbackToIMSC1(frag, payload);
|
590
598
|
}
|
591
599
|
// Something went wrong while parsing. Trigger event with success false.
|
592
|
-
|
600
|
+
logger.log(`Failed to parse VTT cue: ${error}`);
|
593
601
|
if (missingInitPTS && maxAvCC > frag.cc) {
|
594
602
|
return;
|
595
603
|
}
|
@@ -661,7 +669,9 @@ export class TimelineController implements ComponentAPI {
|
|
661
669
|
event: Events.FRAG_PARSING_USERDATA,
|
662
670
|
data: FragParsingUserdataData,
|
663
671
|
) {
|
664
|
-
|
672
|
+
this.initCea608Parsers();
|
673
|
+
const { cea608Parser1, cea608Parser2 } = this;
|
674
|
+
if (!this.enabled || !cea608Parser1 || !cea608Parser2) {
|
665
675
|
return;
|
666
676
|
}
|
667
677
|
const { frag, samples } = data;
|
@@ -676,12 +686,9 @@ export class TimelineController implements ComponentAPI {
|
|
676
686
|
for (let i = 0; i < samples.length; i++) {
|
677
687
|
const ccBytes = samples[i].bytes;
|
678
688
|
if (ccBytes) {
|
679
|
-
if (!this.cea608Parser1) {
|
680
|
-
this.initCea608Parsers();
|
681
|
-
}
|
682
689
|
const ccdatas = this.extractCea608Data(ccBytes);
|
683
|
-
|
684
|
-
|
690
|
+
cea608Parser1.addData(samples[i].pts, ccdatas[0]);
|
691
|
+
cea608Parser2.addData(samples[i].pts, ccdatas[1]);
|
685
692
|
}
|
686
693
|
}
|
687
694
|
}
|
package/src/crypt/aes-crypto.ts
CHANGED
@@ -1,32 +1,13 @@
|
|
1
|
-
import { DecrypterAesMode } from './decrypter-aes-mode';
|
2
|
-
|
3
1
|
export default class AESCrypto {
|
4
2
|
private subtle: SubtleCrypto;
|
5
3
|
private aesIV: Uint8Array;
|
6
|
-
private aesMode: DecrypterAesMode;
|
7
4
|
|
8
|
-
constructor(subtle: SubtleCrypto, iv: Uint8Array
|
5
|
+
constructor(subtle: SubtleCrypto, iv: Uint8Array) {
|
9
6
|
this.subtle = subtle;
|
10
7
|
this.aesIV = iv;
|
11
|
-
this.aesMode = aesMode;
|
12
8
|
}
|
13
9
|
|
14
10
|
decrypt(data: ArrayBuffer, key: CryptoKey) {
|
15
|
-
|
16
|
-
case DecrypterAesMode.cbc:
|
17
|
-
return this.subtle.decrypt(
|
18
|
-
{ name: 'AES-CBC', iv: this.aesIV },
|
19
|
-
key,
|
20
|
-
data,
|
21
|
-
);
|
22
|
-
case DecrypterAesMode.ctr:
|
23
|
-
return this.subtle.decrypt(
|
24
|
-
{ name: 'AES-CTR', counter: this.aesIV, length: 64 }, //64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
|
25
|
-
key,
|
26
|
-
data,
|
27
|
-
);
|
28
|
-
default:
|
29
|
-
throw new Error(`[AESCrypto] invalid aes mode ${this.aesMode}`);
|
30
|
-
}
|
11
|
+
return this.subtle.decrypt({ name: 'AES-CBC', iv: this.aesIV }, key, data);
|
31
12
|
}
|
32
13
|
}
|
package/src/crypt/decrypter.ts
CHANGED
@@ -4,7 +4,6 @@ import AESDecryptor, { removePadding } from './aes-decryptor';
|
|
4
4
|
import { logger } from '../utils/logger';
|
5
5
|
import { appendUint8Array } from '../utils/mp4-tools';
|
6
6
|
import { sliceUint8 } from '../utils/typed-array';
|
7
|
-
import { DecrypterAesMode } from './decrypter-aes-mode';
|
8
7
|
import type { HlsConfig } from '../config';
|
9
8
|
|
10
9
|
const CHUNK_SIZE = 16; // 16 bytes, 128 bits
|
@@ -20,10 +19,9 @@ export default class Decrypter {
|
|
20
19
|
private currentIV: ArrayBuffer | null = null;
|
21
20
|
private currentResult: ArrayBuffer | null = null;
|
22
21
|
private useSoftware: boolean;
|
23
|
-
private enableSoftwareAES: boolean;
|
24
22
|
|
25
23
|
constructor(config: HlsConfig, { removePKCS7Padding = true } = {}) {
|
26
|
-
this.
|
24
|
+
this.useSoftware = config.enableSoftwareAES;
|
27
25
|
this.removePKCS7Padding = removePKCS7Padding;
|
28
26
|
// built in decryptor expects PKCS7 padding
|
29
27
|
if (removePKCS7Padding) {
|
@@ -38,7 +36,9 @@ export default class Decrypter {
|
|
38
36
|
/* no-op */
|
39
37
|
}
|
40
38
|
}
|
41
|
-
|
39
|
+
if (this.subtle === null) {
|
40
|
+
this.useSoftware = true;
|
41
|
+
}
|
42
42
|
}
|
43
43
|
|
44
44
|
destroy() {
|
@@ -82,11 +82,10 @@ export default class Decrypter {
|
|
82
82
|
data: Uint8Array | ArrayBuffer,
|
83
83
|
key: ArrayBuffer,
|
84
84
|
iv: ArrayBuffer,
|
85
|
-
aesMode: DecrypterAesMode,
|
86
85
|
): Promise<ArrayBuffer> {
|
87
86
|
if (this.useSoftware) {
|
88
87
|
return new Promise((resolve, reject) => {
|
89
|
-
this.softwareDecrypt(new Uint8Array(data), key, iv
|
88
|
+
this.softwareDecrypt(new Uint8Array(data), key, iv);
|
90
89
|
const decryptResult = this.flush();
|
91
90
|
if (decryptResult) {
|
92
91
|
resolve(decryptResult.buffer);
|
@@ -95,7 +94,7 @@ export default class Decrypter {
|
|
95
94
|
}
|
96
95
|
});
|
97
96
|
}
|
98
|
-
return this.webCryptoDecrypt(new Uint8Array(data), key, iv
|
97
|
+
return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
|
99
98
|
}
|
100
99
|
|
101
100
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
@@ -104,13 +103,8 @@ export default class Decrypter {
|
|
104
103
|
data: Uint8Array,
|
105
104
|
key: ArrayBuffer,
|
106
105
|
iv: ArrayBuffer,
|
107
|
-
aesMode: DecrypterAesMode,
|
108
106
|
): ArrayBuffer | null {
|
109
107
|
const { currentIV, currentResult, remainderData } = this;
|
110
|
-
if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
|
111
|
-
logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
|
112
|
-
return null;
|
113
|
-
}
|
114
108
|
this.logOnce('JS AES decrypt');
|
115
109
|
// The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
|
116
110
|
// This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
|
@@ -153,22 +147,21 @@ export default class Decrypter {
|
|
153
147
|
data: Uint8Array,
|
154
148
|
key: ArrayBuffer,
|
155
149
|
iv: ArrayBuffer,
|
156
|
-
aesMode: DecrypterAesMode,
|
157
150
|
): Promise<ArrayBuffer> {
|
158
151
|
const subtle = this.subtle;
|
159
152
|
if (this.key !== key || !this.fastAesKey) {
|
160
153
|
this.key = key;
|
161
|
-
this.fastAesKey = new FastAESKey(subtle, key
|
154
|
+
this.fastAesKey = new FastAESKey(subtle, key);
|
162
155
|
}
|
163
156
|
return this.fastAesKey
|
164
157
|
.expandKey()
|
165
|
-
.then((aesKey
|
158
|
+
.then((aesKey) => {
|
166
159
|
// decrypt using web crypto
|
167
160
|
if (!subtle) {
|
168
161
|
return Promise.reject(new Error('web crypto not initialized'));
|
169
162
|
}
|
170
163
|
this.logOnce('WebCrypto AES decrypt');
|
171
|
-
const crypto = new AESCrypto(subtle, new Uint8Array(iv)
|
164
|
+
const crypto = new AESCrypto(subtle, new Uint8Array(iv));
|
172
165
|
return crypto.decrypt(data.buffer, aesKey);
|
173
166
|
})
|
174
167
|
.catch((err) => {
|
@@ -176,26 +169,19 @@ export default class Decrypter {
|
|
176
169
|
`[decrypter]: WebCrypto Error, disable WebCrypto API, ${err.name}: ${err.message}`,
|
177
170
|
);
|
178
171
|
|
179
|
-
return this.onWebCryptoError(data, key, iv
|
172
|
+
return this.onWebCryptoError(data, key, iv);
|
180
173
|
});
|
181
174
|
}
|
182
175
|
|
183
|
-
private onWebCryptoError(data, key, iv
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
if (decryptResult) {
|
191
|
-
return decryptResult.buffer;
|
192
|
-
}
|
176
|
+
private onWebCryptoError(data, key, iv): ArrayBuffer | never {
|
177
|
+
this.useSoftware = true;
|
178
|
+
this.logEnabled = true;
|
179
|
+
this.softwareDecrypt(data, key, iv);
|
180
|
+
const decryptResult = this.flush();
|
181
|
+
if (decryptResult) {
|
182
|
+
return decryptResult.buffer;
|
193
183
|
}
|
194
|
-
throw new Error(
|
195
|
-
'WebCrypto' +
|
196
|
-
(enableSoftwareAES ? ' and softwareDecrypt' : '') +
|
197
|
-
': failed to decrypt data',
|
198
|
-
);
|
184
|
+
throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
|
199
185
|
}
|
200
186
|
|
201
187
|
private getValidChunk(data: Uint8Array): Uint8Array {
|
@@ -1,35 +1,16 @@
|
|
1
|
-
import { DecrypterAesMode } from './decrypter-aes-mode';
|
2
|
-
|
3
1
|
export default class FastAESKey {
|
4
2
|
private subtle: any;
|
5
3
|
private key: ArrayBuffer;
|
6
|
-
private aesMode: DecrypterAesMode;
|
7
4
|
|
8
|
-
constructor(subtle, key
|
5
|
+
constructor(subtle, key) {
|
9
6
|
this.subtle = subtle;
|
10
7
|
this.key = key;
|
11
|
-
this.aesMode = aesMode;
|
12
8
|
}
|
13
9
|
|
14
10
|
expandKey() {
|
15
|
-
|
16
|
-
|
17
|
-
'
|
18
|
-
|
19
|
-
{ name: subtleAlgoName },
|
20
|
-
false,
|
21
|
-
['encrypt', 'decrypt'],
|
22
|
-
);
|
23
|
-
}
|
24
|
-
}
|
25
|
-
|
26
|
-
function getSubtleAlgoName(aesMode: DecrypterAesMode) {
|
27
|
-
switch (aesMode) {
|
28
|
-
case DecrypterAesMode.cbc:
|
29
|
-
return 'AES-CBC';
|
30
|
-
case DecrypterAesMode.ctr:
|
31
|
-
return 'AES-CTR';
|
32
|
-
default:
|
33
|
-
throw new Error(`[FastAESKey] invalid aes mode ${aesMode}`);
|
11
|
+
return this.subtle.importKey('raw', this.key, { name: 'AES-CBC' }, false, [
|
12
|
+
'encrypt',
|
13
|
+
'decrypt',
|
14
|
+
]);
|
34
15
|
}
|
35
16
|
}
|
package/src/demux/audio/adts.ts
CHANGED
@@ -17,7 +17,6 @@ type AudioConfig = {
|
|
17
17
|
samplerate: number;
|
18
18
|
channelCount: number;
|
19
19
|
codec: string;
|
20
|
-
parsedCodec: string;
|
21
20
|
manifestCodec: string;
|
22
21
|
};
|
23
22
|
|
@@ -33,7 +32,6 @@ export function getAudioConfig(
|
|
33
32
|
audioCodec: string,
|
34
33
|
): AudioConfig | void {
|
35
34
|
let adtsObjectType: number;
|
36
|
-
let originalAdtsObjectType: number;
|
37
35
|
let adtsExtensionSamplingIndex: number;
|
38
36
|
let adtsChannelConfig: number;
|
39
37
|
let config: number[];
|
@@ -44,8 +42,7 @@ export function getAudioConfig(
|
|
44
42
|
8000, 7350,
|
45
43
|
];
|
46
44
|
// byte 2
|
47
|
-
adtsObjectType =
|
48
|
-
((data[offset + 2] & 0xc0) >>> 6) + 1;
|
45
|
+
adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
49
46
|
const adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
|
50
47
|
if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
|
51
48
|
const error = new Error(`invalid ADTS sampling index:${adtsSamplingIndex}`);
|
@@ -64,8 +61,8 @@ export function getAudioConfig(
|
|
64
61
|
logger.log(
|
65
62
|
`manifest codec:${audioCodec}, ADTS type:${adtsObjectType}, samplingIndex:${adtsSamplingIndex}`,
|
66
63
|
);
|
67
|
-
//
|
68
|
-
if (/firefox
|
64
|
+
// firefox: freq less than 24kHz = AAC SBR (HE-AAC)
|
65
|
+
if (/firefox/i.test(userAgent)) {
|
69
66
|
if (adtsSamplingIndex >= 6) {
|
70
67
|
adtsObjectType = 5;
|
71
68
|
config = new Array(4);
|
@@ -170,7 +167,6 @@ export function getAudioConfig(
|
|
170
167
|
samplerate: adtsSamplingRates[adtsSamplingIndex],
|
171
168
|
channelCount: adtsChannelConfig,
|
172
169
|
codec: 'mp4a.40.' + adtsObjectType,
|
173
|
-
parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
|
174
170
|
manifestCodec,
|
175
171
|
};
|
176
172
|
}
|
@@ -248,9 +244,8 @@ export function initTrackConfig(
|
|
248
244
|
track.channelCount = config.channelCount;
|
249
245
|
track.codec = config.codec;
|
250
246
|
track.manifestCodec = config.manifestCodec;
|
251
|
-
track.parsedCodec = config.parsedCodec;
|
252
247
|
logger.log(
|
253
|
-
`parsed codec:${track.
|
248
|
+
`parsed codec:${track.codec}, rate:${config.samplerate}, channels:${config.channelCount}`,
|
254
249
|
);
|
255
250
|
}
|
256
251
|
}
|
package/src/demux/sample-aes.ts
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
|
5
5
|
import { HlsConfig } from '../config';
|
6
6
|
import Decrypter from '../crypt/decrypter';
|
7
|
-
import { DecrypterAesMode } from '../crypt/decrypter-aes-mode';
|
8
7
|
import { HlsEventEmitter } from '../events';
|
9
8
|
import type {
|
10
9
|
AudioSample,
|
@@ -31,7 +30,6 @@ class SampleAesDecrypter {
|
|
31
30
|
encryptedData,
|
32
31
|
this.keyData.key.buffer,
|
33
32
|
this.keyData.iv.buffer,
|
34
|
-
DecrypterAesMode.cbc,
|
35
33
|
);
|
36
34
|
}
|
37
35
|
|
@@ -12,13 +12,14 @@ import Transmuxer, {
|
|
12
12
|
} from '../demux/transmuxer';
|
13
13
|
import { logger } from '../utils/logger';
|
14
14
|
import { ErrorTypes, ErrorDetails } from '../errors';
|
15
|
+
import { getMediaSource } from '../utils/mediasource-helper';
|
15
16
|
import { EventEmitter } from 'eventemitter3';
|
16
17
|
import { Fragment, Part } from '../loader/fragment';
|
17
|
-
import { getM2TSSupportedAudioTypes } from '../utils/codecs';
|
18
18
|
import type { ChunkMetadata, TransmuxerResult } from '../types/transmuxer';
|
19
19
|
import type Hls from '../hls';
|
20
20
|
import type { HlsEventEmitter } from '../events';
|
21
21
|
import type { PlaylistLevelType } from '../types/loader';
|
22
|
+
import type { TypeSupported } from './tsdemuxer';
|
22
23
|
import type { RationalTimestamp } from '../utils/timescale-conversion';
|
23
24
|
|
24
25
|
export default class TransmuxerInterface {
|
@@ -63,9 +64,16 @@ export default class TransmuxerInterface {
|
|
63
64
|
this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
|
64
65
|
this.observer.on(Events.ERROR, forwardMessage);
|
65
66
|
|
66
|
-
const
|
67
|
-
|
68
|
-
|
67
|
+
const MediaSource = getMediaSource(config.preferManagedMediaSource) || {
|
68
|
+
isTypeSupported: () => false,
|
69
|
+
};
|
70
|
+
const m2tsTypeSupported: TypeSupported = {
|
71
|
+
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
72
|
+
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
73
|
+
ac3: __USE_M2TS_ADVANCED_CODECS__
|
74
|
+
? MediaSource.isTypeSupported('audio/mp4; codecs="ac-3"')
|
75
|
+
: false,
|
76
|
+
};
|
69
77
|
|
70
78
|
// navigator.vendor is not always available in Web Worker
|
71
79
|
// refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import Transmuxer, { isPromise } from '../demux/transmuxer';
|
2
2
|
import { Events } from '../events';
|
3
|
-
import {
|
3
|
+
import { ILogFunction, enableLogs, logger } from '../utils/logger';
|
4
4
|
import { EventEmitter } from 'eventemitter3';
|
5
5
|
import { ErrorDetails, ErrorTypes } from '../errors';
|
6
6
|
import type { RemuxedTrack, RemuxerResult } from '../types/remuxer';
|
@@ -21,7 +21,7 @@ function startWorker(self) {
|
|
21
21
|
observer.on(Events.ERROR, forwardMessage);
|
22
22
|
|
23
23
|
// forward logger events to main thread
|
24
|
-
const forwardWorkerLogs = (
|
24
|
+
const forwardWorkerLogs = () => {
|
25
25
|
for (const logFn in logger) {
|
26
26
|
const func: ILogFunction = (message?) => {
|
27
27
|
forwardMessage('workerLog', {
|
@@ -46,8 +46,8 @@ function startWorker(self) {
|
|
46
46
|
data.vendor,
|
47
47
|
data.id,
|
48
48
|
);
|
49
|
-
|
50
|
-
forwardWorkerLogs(
|
49
|
+
enableLogs(config.debug, data.id);
|
50
|
+
forwardWorkerLogs();
|
51
51
|
forwardMessage('init', null);
|
52
52
|
break;
|
53
53
|
}
|
package/src/demux/transmuxer.ts
CHANGED
@@ -4,23 +4,18 @@ import { ErrorTypes, ErrorDetails } from '../errors';
|
|
4
4
|
import Decrypter from '../crypt/decrypter';
|
5
5
|
import AACDemuxer from './audio/aacdemuxer';
|
6
6
|
import MP4Demuxer from '../demux/mp4demuxer';
|
7
|
-
import TSDemuxer from '../demux/tsdemuxer';
|
7
|
+
import TSDemuxer, { TypeSupported } from '../demux/tsdemuxer';
|
8
8
|
import MP3Demuxer from './audio/mp3demuxer';
|
9
9
|
import { AC3Demuxer } from './audio/ac3-demuxer';
|
10
10
|
import MP4Remuxer from '../remux/mp4-remuxer';
|
11
11
|
import PassThroughRemuxer from '../remux/passthrough-remuxer';
|
12
12
|
import { logger } from '../utils/logger';
|
13
|
-
import {
|
14
|
-
isFullSegmentEncryption,
|
15
|
-
getAesModeFromFullSegmentMethod,
|
16
|
-
} from '../utils/encryption-methods-util';
|
17
13
|
import type { Demuxer, DemuxerResult, KeyData } from '../types/demuxer';
|
18
14
|
import type { Remuxer } from '../types/remuxer';
|
19
15
|
import type { TransmuxerResult, ChunkMetadata } from '../types/transmuxer';
|
20
16
|
import type { HlsConfig } from '../config';
|
21
17
|
import type { DecryptData } from '../loader/level-key';
|
22
18
|
import type { PlaylistLevelType } from '../types/loader';
|
23
|
-
import type { TypeSupported } from '../utils/codecs';
|
24
19
|
import type { RationalTimestamp } from '../utils/timescale-conversion';
|
25
20
|
import { optionalSelf } from '../utils/global';
|
26
21
|
|
@@ -119,10 +114,8 @@ export default class Transmuxer {
|
|
119
114
|
} = transmuxConfig;
|
120
115
|
|
121
116
|
const keyData = getEncryptionType(uintData, decryptdata);
|
122
|
-
if (keyData &&
|
117
|
+
if (keyData && keyData.method === 'AES-128') {
|
123
118
|
const decrypter = this.getDecrypter();
|
124
|
-
const aesMode = getAesModeFromFullSegmentMethod(keyData.method);
|
125
|
-
|
126
119
|
// Software decryption is synchronous; webCrypto is not
|
127
120
|
if (decrypter.isSync()) {
|
128
121
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
@@ -131,7 +124,6 @@ export default class Transmuxer {
|
|
131
124
|
uintData,
|
132
125
|
keyData.key.buffer,
|
133
126
|
keyData.iv.buffer,
|
134
|
-
aesMode,
|
135
127
|
);
|
136
128
|
// For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
|
137
129
|
const loadingParts = chunkMeta.part > -1;
|
@@ -145,12 +137,7 @@ export default class Transmuxer {
|
|
145
137
|
uintData = new Uint8Array(decryptedData);
|
146
138
|
} else {
|
147
139
|
this.decryptionPromise = decrypter
|
148
|
-
.webCryptoDecrypt(
|
149
|
-
uintData,
|
150
|
-
keyData.key.buffer,
|
151
|
-
keyData.iv.buffer,
|
152
|
-
aesMode,
|
153
|
-
)
|
140
|
+
.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer)
|
154
141
|
.then((decryptedData): TransmuxerResult => {
|
155
142
|
// Calling push here is important; if flush() is called while this is still resolving, this ensures that
|
156
143
|
// the decrypted data has been transmuxed
|
package/src/demux/tsdemuxer.ts
CHANGED
@@ -20,21 +20,20 @@ import { logger } from '../utils/logger';
|
|
20
20
|
import { ErrorTypes, ErrorDetails } from '../errors';
|
21
21
|
import type { HlsConfig } from '../config';
|
22
22
|
import type { HlsEventEmitter } from '../events';
|
23
|
-
import type { TypeSupported } from '../utils/codecs';
|
24
23
|
import {
|
24
|
+
DemuxedVideoTrack,
|
25
|
+
DemuxedAudioTrack,
|
26
|
+
DemuxedTrack,
|
27
|
+
Demuxer,
|
28
|
+
DemuxerResult,
|
29
|
+
VideoSample,
|
30
|
+
DemuxedMetadataTrack,
|
31
|
+
DemuxedUserdataTrack,
|
32
|
+
ElementaryStreamData,
|
33
|
+
KeyData,
|
25
34
|
MetadataSchema,
|
26
|
-
type DemuxedVideoTrack,
|
27
|
-
type DemuxedAudioTrack,
|
28
|
-
type DemuxedTrack,
|
29
|
-
type Demuxer,
|
30
|
-
type DemuxerResult,
|
31
|
-
type VideoSample,
|
32
|
-
type DemuxedMetadataTrack,
|
33
|
-
type DemuxedUserdataTrack,
|
34
|
-
type ElementaryStreamData,
|
35
|
-
type KeyData,
|
36
35
|
} from '../types/demuxer';
|
37
|
-
import
|
36
|
+
import { AudioFrame } from '../types/demuxer';
|
38
37
|
|
39
38
|
export type ParsedTimestamp = {
|
40
39
|
pts?: number;
|
@@ -49,6 +48,12 @@ export type PES = ParsedTimestamp & {
|
|
49
48
|
export type ParsedVideoSample = ParsedTimestamp &
|
50
49
|
Omit<VideoSample, 'pts' | 'dts'>;
|
51
50
|
|
51
|
+
export interface TypeSupported {
|
52
|
+
mpeg: boolean;
|
53
|
+
mp3: boolean;
|
54
|
+
ac3: boolean;
|
55
|
+
}
|
56
|
+
|
52
57
|
const PACKET_LENGTH = 188;
|
53
58
|
|
54
59
|
class TSDemuxer implements Demuxer {
|