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
@@ -5,7 +5,7 @@
|
|
5
5
|
*/
|
6
6
|
import { Events } from '../events';
|
7
7
|
import { ErrorTypes, ErrorDetails } from '../errors';
|
8
|
-
import {
|
8
|
+
import { logger } from '../utils/logger';
|
9
9
|
import {
|
10
10
|
getKeySystemsForConfig,
|
11
11
|
getSupportedMediaKeySystemConfigurations,
|
@@ -41,6 +41,9 @@ import type {
|
|
41
41
|
LoaderConfiguration,
|
42
42
|
LoaderContext,
|
43
43
|
} from '../types/loader';
|
44
|
+
|
45
|
+
const LOGGER_PREFIX = '[eme]';
|
46
|
+
|
44
47
|
interface KeySystemAccessPromises {
|
45
48
|
keySystemAccess: Promise<MediaKeySystemAccess>;
|
46
49
|
mediaKeys?: Promise<MediaKeys>;
|
@@ -65,7 +68,7 @@ export interface MediaKeySessionContext {
|
|
65
68
|
* @class
|
66
69
|
* @constructor
|
67
70
|
*/
|
68
|
-
class EMEController
|
71
|
+
class EMEController implements ComponentAPI {
|
69
72
|
public static CDMCleanupPromise: Promise<void> | void;
|
70
73
|
|
71
74
|
private readonly hls: Hls;
|
@@ -87,9 +90,15 @@ class EMEController extends Logger implements ComponentAPI {
|
|
87
90
|
private setMediaKeysQueue: Promise<void>[] = EMEController.CDMCleanupPromise
|
88
91
|
? [EMEController.CDMCleanupPromise]
|
89
92
|
: [];
|
93
|
+
private onMediaEncrypted = this._onMediaEncrypted.bind(this);
|
94
|
+
private onWaitingForKey = this._onWaitingForKey.bind(this);
|
95
|
+
|
96
|
+
private debug: (msg: any) => void = logger.debug.bind(logger, LOGGER_PREFIX);
|
97
|
+
private log: (msg: any) => void = logger.log.bind(logger, LOGGER_PREFIX);
|
98
|
+
private warn: (msg: any) => void = logger.warn.bind(logger, LOGGER_PREFIX);
|
99
|
+
private error: (msg: any) => void = logger.error.bind(logger, LOGGER_PREFIX);
|
90
100
|
|
91
101
|
constructor(hls: Hls) {
|
92
|
-
super('eme', hls.logger);
|
93
102
|
this.hls = hls;
|
94
103
|
this.config = hls.config;
|
95
104
|
this.registerListeners();
|
@@ -104,9 +113,13 @@ class EMEController extends Logger implements ComponentAPI {
|
|
104
113
|
config.licenseXhrSetup = config.licenseResponseCallback = undefined;
|
105
114
|
config.drmSystems = config.drmSystemOptions = {};
|
106
115
|
// @ts-ignore
|
107
|
-
this.hls =
|
116
|
+
this.hls =
|
117
|
+
this.onMediaEncrypted =
|
118
|
+
this.onWaitingForKey =
|
119
|
+
this.keyIdToKeySessionPromise =
|
120
|
+
null as any;
|
108
121
|
// @ts-ignore
|
109
|
-
this.
|
122
|
+
this.config = null;
|
110
123
|
}
|
111
124
|
|
112
125
|
private registerListeners() {
|
@@ -510,7 +523,7 @@ class EMEController extends Logger implements ComponentAPI {
|
|
510
523
|
return this.attemptKeySystemAccess(keySystemsToAttempt);
|
511
524
|
}
|
512
525
|
|
513
|
-
private
|
526
|
+
private _onMediaEncrypted(event: MediaEncryptedEvent) {
|
514
527
|
const { initDataType, initData } = event;
|
515
528
|
this.debug(`"${event.type}" event: init data type: "${initDataType}"`);
|
516
529
|
|
@@ -626,11 +639,11 @@ class EMEController extends Logger implements ComponentAPI {
|
|
626
639
|
);
|
627
640
|
}
|
628
641
|
keySessionContextPromise.catch((error) => this.handleError(error));
|
629
|
-
}
|
642
|
+
}
|
630
643
|
|
631
|
-
private
|
644
|
+
private _onWaitingForKey(event: Event) {
|
632
645
|
this.log(`"${event.type}" event`);
|
633
|
-
}
|
646
|
+
}
|
634
647
|
|
635
648
|
private attemptSetMediaKeys(
|
636
649
|
keySystem: KeySystems,
|
@@ -8,7 +8,7 @@ import {
|
|
8
8
|
} from '../utils/error-helper';
|
9
9
|
import { findFragmentByPTS } from './fragment-finders';
|
10
10
|
import { HdcpLevel, HdcpLevels } from '../types/level';
|
11
|
-
import {
|
11
|
+
import { logger } from '../utils/logger';
|
12
12
|
import type Hls from '../hls';
|
13
13
|
import type { RetryConfig } from '../config';
|
14
14
|
import type { NetworkComponentAPI } from '../types/component-api';
|
@@ -50,17 +50,19 @@ type PenalizedRendition = {
|
|
50
50
|
|
51
51
|
type PenalizedRenditions = { [key: number]: PenalizedRendition };
|
52
52
|
|
53
|
-
export default class ErrorController
|
54
|
-
extends Logger
|
55
|
-
implements NetworkComponentAPI
|
56
|
-
{
|
53
|
+
export default class ErrorController implements NetworkComponentAPI {
|
57
54
|
private readonly hls: Hls;
|
58
55
|
private playlistError: number = 0;
|
59
56
|
private penalizedRenditions: PenalizedRenditions = {};
|
57
|
+
private log: (msg: any) => void;
|
58
|
+
private warn: (msg: any) => void;
|
59
|
+
private error: (msg: any) => void;
|
60
60
|
|
61
61
|
constructor(hls: Hls) {
|
62
|
-
super('error-controller', hls.logger);
|
63
62
|
this.hls = hls;
|
63
|
+
this.log = logger.log.bind(logger, `[info]:`);
|
64
|
+
this.warn = logger.warn.bind(logger, `[warning]:`);
|
65
|
+
this.error = logger.error.bind(logger, `[error]:`);
|
64
66
|
this.registerListeners();
|
65
67
|
}
|
66
68
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { Events } from '../events';
|
2
|
+
import { logger } from '../utils/logger';
|
2
3
|
import type { ComponentAPI } from '../types/component-api';
|
3
4
|
import type Hls from '../hls';
|
4
5
|
import type { MediaAttachingData } from '../types/events';
|
@@ -83,13 +84,13 @@ class FPSController implements ComponentAPI {
|
|
83
84
|
totalDroppedFrames: droppedFrames,
|
84
85
|
});
|
85
86
|
if (droppedFPS > 0) {
|
86
|
-
//
|
87
|
+
// logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
87
88
|
if (
|
88
89
|
currentDropped >
|
89
90
|
hls.config.fpsDroppedMonitoringThreshold * currentDecoded
|
90
91
|
) {
|
91
92
|
let currentLevel = hls.currentLevel;
|
92
|
-
|
93
|
+
logger.warn(
|
93
94
|
'drop FPS ratio greater than max allowed value for currentLevel: ' +
|
94
95
|
currentLevel,
|
95
96
|
);
|
@@ -1,10 +1,10 @@
|
|
1
|
+
import type { BufferInfo } from '../utils/buffer-helper';
|
1
2
|
import { BufferHelper } from '../utils/buffer-helper';
|
2
3
|
import { ErrorTypes, ErrorDetails } from '../errors';
|
3
4
|
import { PlaylistLevelType } from '../types/loader';
|
4
5
|
import { Events } from '../events';
|
5
|
-
import {
|
6
|
+
import { logger } from '../utils/logger';
|
6
7
|
import type Hls from '../hls';
|
7
|
-
import type { BufferInfo } from '../utils/buffer-helper';
|
8
8
|
import type { HlsConfig } from '../config';
|
9
9
|
import type { Fragment } from '../loader/fragment';
|
10
10
|
import type { FragmentTracker } from './fragment-tracker';
|
@@ -14,7 +14,7 @@ export const MAX_START_GAP_JUMP = 2.0;
|
|
14
14
|
export const SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
|
15
15
|
export const SKIP_BUFFER_RANGE_START = 0.05;
|
16
16
|
|
17
|
-
export default class GapController
|
17
|
+
export default class GapController {
|
18
18
|
private config: HlsConfig;
|
19
19
|
private media: HTMLMediaElement | null = null;
|
20
20
|
private fragmentTracker: FragmentTracker;
|
@@ -25,13 +25,7 @@ export default class GapController extends Logger {
|
|
25
25
|
private moved: boolean = false;
|
26
26
|
private seeking: boolean = false;
|
27
27
|
|
28
|
-
constructor(
|
29
|
-
config: HlsConfig,
|
30
|
-
media: HTMLMediaElement,
|
31
|
-
fragmentTracker: FragmentTracker,
|
32
|
-
hls: Hls,
|
33
|
-
) {
|
34
|
-
super('gap-controller', hls.logger);
|
28
|
+
constructor(config, media, fragmentTracker, hls) {
|
35
29
|
this.config = config;
|
36
30
|
this.media = media;
|
37
31
|
this.fragmentTracker = fragmentTracker;
|
@@ -71,7 +65,7 @@ export default class GapController extends Logger {
|
|
71
65
|
// The playhead is now moving, but was previously stalled
|
72
66
|
if (this.stallReported) {
|
73
67
|
const stalledDuration = self.performance.now() - stalled;
|
74
|
-
|
68
|
+
logger.warn(
|
75
69
|
`playback not stuck anymore @${currentTime}, after ${Math.round(
|
76
70
|
stalledDuration,
|
77
71
|
)}ms`,
|
@@ -212,7 +206,7 @@ export default class GapController extends Logger {
|
|
212
206
|
bufferInfo.nextStart - currentTime < config.maxBufferHole)) &&
|
213
207
|
stalledDurationMs > config.highBufferWatchdogPeriod * 1000
|
214
208
|
) {
|
215
|
-
|
209
|
+
logger.warn('Trying to nudge playhead over buffer-hole');
|
216
210
|
// Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
|
217
211
|
// We only try to jump the hole if it's under the configured size
|
218
212
|
// Reset stalled so to rearm watchdog timer
|
@@ -236,7 +230,7 @@ export default class GapController extends Logger {
|
|
236
230
|
media.currentTime
|
237
231
|
} due to low buffer (${JSON.stringify(bufferInfo)})`,
|
238
232
|
);
|
239
|
-
|
233
|
+
logger.warn(error.message);
|
240
234
|
hls.trigger(Events.ERROR, {
|
241
235
|
type: ErrorTypes.MEDIA_ERROR,
|
242
236
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -311,7 +305,7 @@ export default class GapController extends Logger {
|
|
311
305
|
startTime + SKIP_BUFFER_RANGE_START,
|
312
306
|
currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS,
|
313
307
|
);
|
314
|
-
|
308
|
+
logger.warn(
|
315
309
|
`skipping hole, adjusting currentTime from ${currentTime} to ${targetTime}`,
|
316
310
|
);
|
317
311
|
this.moved = true;
|
@@ -354,7 +348,7 @@ export default class GapController extends Logger {
|
|
354
348
|
const error = new Error(
|
355
349
|
`Nudging 'currentTime' from ${currentTime} to ${targetTime}`,
|
356
350
|
);
|
357
|
-
|
351
|
+
logger.warn(error.message);
|
358
352
|
media.currentTime = targetTime;
|
359
353
|
hls.trigger(Events.ERROR, {
|
360
354
|
type: ErrorTypes.MEDIA_ERROR,
|
@@ -366,7 +360,7 @@ export default class GapController extends Logger {
|
|
366
360
|
const error = new Error(
|
367
361
|
`Playhead still not moving while enough data buffered @${currentTime} after ${config.nudgeMaxRetry} nudges`,
|
368
362
|
);
|
369
|
-
|
363
|
+
logger.error(error.message);
|
370
364
|
hls.trigger(Events.ERROR, {
|
371
365
|
type: ErrorTypes.MEDIA_ERROR,
|
372
366
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -6,6 +6,7 @@ import type {
|
|
6
6
|
LevelUpdatedData,
|
7
7
|
MediaAttachingData,
|
8
8
|
} from '../types/events';
|
9
|
+
import { logger } from '../utils/logger';
|
9
10
|
import type { ComponentAPI } from '../types/component-api';
|
10
11
|
import type Hls from '../hls';
|
11
12
|
import type { HlsConfig } from '../config';
|
@@ -18,6 +19,7 @@ export default class LatencyController implements ComponentAPI {
|
|
18
19
|
private currentTime: number = 0;
|
19
20
|
private stallCount: number = 0;
|
20
21
|
private _latency: number | null = null;
|
22
|
+
private timeupdateHandler = () => this.timeupdate();
|
21
23
|
|
22
24
|
constructor(hls: Hls) {
|
23
25
|
this.hls = hls;
|
@@ -124,7 +126,7 @@ export default class LatencyController implements ComponentAPI {
|
|
124
126
|
this.onMediaDetaching();
|
125
127
|
this.levelDetails = null;
|
126
128
|
// @ts-ignore
|
127
|
-
this.hls = null;
|
129
|
+
this.hls = this.timeupdateHandler = null;
|
128
130
|
}
|
129
131
|
|
130
132
|
private registerListeners() {
|
@@ -148,12 +150,12 @@ export default class LatencyController implements ComponentAPI {
|
|
148
150
|
data: MediaAttachingData,
|
149
151
|
) {
|
150
152
|
this.media = data.media;
|
151
|
-
this.media.addEventListener('timeupdate', this.
|
153
|
+
this.media.addEventListener('timeupdate', this.timeupdateHandler);
|
152
154
|
}
|
153
155
|
|
154
156
|
private onMediaDetaching() {
|
155
157
|
if (this.media) {
|
156
|
-
this.media.removeEventListener('timeupdate', this.
|
158
|
+
this.media.removeEventListener('timeupdate', this.timeupdateHandler);
|
157
159
|
this.media = null;
|
158
160
|
}
|
159
161
|
}
|
@@ -170,10 +172,10 @@ export default class LatencyController implements ComponentAPI {
|
|
170
172
|
) {
|
171
173
|
this.levelDetails = details;
|
172
174
|
if (details.advanced) {
|
173
|
-
this.
|
175
|
+
this.timeupdate();
|
174
176
|
}
|
175
177
|
if (!details.live && this.media) {
|
176
|
-
this.media.removeEventListener('timeupdate', this.
|
178
|
+
this.media.removeEventListener('timeupdate', this.timeupdateHandler);
|
177
179
|
}
|
178
180
|
}
|
179
181
|
|
@@ -183,13 +185,13 @@ export default class LatencyController implements ComponentAPI {
|
|
183
185
|
}
|
184
186
|
this.stallCount++;
|
185
187
|
if (this.levelDetails?.live) {
|
186
|
-
|
187
|
-
'[
|
188
|
+
logger.warn(
|
189
|
+
'[playback-rate-controller]: Stall detected, adjusting target latency',
|
188
190
|
);
|
189
191
|
}
|
190
192
|
}
|
191
193
|
|
192
|
-
private
|
194
|
+
private timeupdate() {
|
193
195
|
const { media, levelDetails } = this;
|
194
196
|
if (!media || !levelDetails) {
|
195
197
|
return;
|
@@ -240,7 +242,7 @@ export default class LatencyController implements ComponentAPI {
|
|
240
242
|
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
241
243
|
media.playbackRate = 1;
|
242
244
|
}
|
243
|
-
}
|
245
|
+
}
|
244
246
|
|
245
247
|
private estimateLiveEdge(): number | null {
|
246
248
|
const { levelDetails } = this;
|
@@ -16,7 +16,6 @@ import {
|
|
16
16
|
codecsSetSelectionPreferenceValue,
|
17
17
|
convertAVC1ToAVCOTI,
|
18
18
|
getCodecCompatibleName,
|
19
|
-
getM2TSSupportedAudioTypes,
|
20
19
|
videoCodecPreferenceValue,
|
21
20
|
} from '../utils/codecs';
|
22
21
|
import BasePlaylistController from './base-playlist-controller';
|
@@ -28,6 +27,8 @@ import type Hls from '../hls';
|
|
28
27
|
import type { HlsUrlParameters, LevelParsed } from '../types/level';
|
29
28
|
import type { MediaPlaylist } from '../types/media-playlist';
|
30
29
|
|
30
|
+
let chromeOrFirefox: boolean;
|
31
|
+
|
31
32
|
export default class LevelController extends BasePlaylistController {
|
32
33
|
private _levels: Level[] = [];
|
33
34
|
private _firstLevel: number = -1;
|
@@ -44,7 +45,7 @@ export default class LevelController extends BasePlaylistController {
|
|
44
45
|
hls: Hls,
|
45
46
|
contentSteeringController: ContentSteeringController | null,
|
46
47
|
) {
|
47
|
-
super(hls, 'level-controller');
|
48
|
+
super(hls, '[level-controller]');
|
48
49
|
this.steering = contentSteeringController;
|
49
50
|
this._registerListeners();
|
50
51
|
}
|
@@ -118,12 +119,22 @@ export default class LevelController extends BasePlaylistController {
|
|
118
119
|
|
119
120
|
data.levels.forEach((levelParsed: LevelParsed) => {
|
120
121
|
const attributes = levelParsed.attrs;
|
122
|
+
|
123
|
+
// erase audio codec info if browser does not support mp4a.40.34.
|
124
|
+
// demuxer will autodetect codec and fallback to mpeg/audio
|
121
125
|
let { audioCodec, videoCodec } = levelParsed;
|
126
|
+
if (audioCodec?.indexOf('mp4a.40.34') !== -1) {
|
127
|
+
chromeOrFirefox ||= /chrome|firefox/i.test(navigator.userAgent);
|
128
|
+
if (chromeOrFirefox) {
|
129
|
+
levelParsed.audioCodec = audioCodec = undefined;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
122
133
|
if (audioCodec) {
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
134
|
+
levelParsed.audioCodec = audioCodec = getCodecCompatibleName(
|
135
|
+
audioCodec,
|
136
|
+
preferManagedMediaSource,
|
137
|
+
);
|
127
138
|
}
|
128
139
|
|
129
140
|
if (videoCodec?.indexOf('avc1') === 0) {
|
@@ -296,8 +307,8 @@ export default class LevelController extends BasePlaylistController {
|
|
296
307
|
return valueB - valueA;
|
297
308
|
}
|
298
309
|
}
|
299
|
-
if (a.
|
300
|
-
return a.
|
310
|
+
if (a.averageBitrate !== b.averageBitrate) {
|
311
|
+
return a.averageBitrate - b.averageBitrate;
|
301
312
|
}
|
302
313
|
return 0;
|
303
314
|
});
|
@@ -49,6 +49,8 @@ export default class StreamController
|
|
49
49
|
private altAudio: boolean = false;
|
50
50
|
private audioOnly: boolean = false;
|
51
51
|
private fragPlaying: Fragment | null = null;
|
52
|
+
private onvplaying: EventListener | null = null;
|
53
|
+
private onvseeked: EventListener | null = null;
|
52
54
|
private fragLastKbps: number = 0;
|
53
55
|
private couldBacktrack: boolean = false;
|
54
56
|
private backtrackFragment: Fragment | null = null;
|
@@ -64,15 +66,17 @@ export default class StreamController
|
|
64
66
|
hls,
|
65
67
|
fragmentTracker,
|
66
68
|
keyLoader,
|
67
|
-
'stream-controller',
|
69
|
+
'[stream-controller]',
|
68
70
|
PlaylistLevelType.MAIN,
|
69
71
|
);
|
70
|
-
this.
|
72
|
+
this._registerListeners();
|
71
73
|
}
|
72
74
|
|
73
|
-
|
74
|
-
super.registerListeners();
|
75
|
+
private _registerListeners() {
|
75
76
|
const { hls } = this;
|
77
|
+
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
78
|
+
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
79
|
+
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
76
80
|
hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
77
81
|
hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
|
78
82
|
hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
@@ -81,6 +85,7 @@ export default class StreamController
|
|
81
85
|
this.onFragLoadEmergencyAborted,
|
82
86
|
this,
|
83
87
|
);
|
88
|
+
hls.on(Events.ERROR, this.onError, this);
|
84
89
|
hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
85
90
|
hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
86
91
|
hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -89,9 +94,11 @@ export default class StreamController
|
|
89
94
|
hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
90
95
|
}
|
91
96
|
|
92
|
-
protected
|
93
|
-
super.unregisterListeners();
|
97
|
+
protected _unregisterListeners() {
|
94
98
|
const { hls } = this;
|
99
|
+
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
100
|
+
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
101
|
+
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
95
102
|
hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
96
103
|
hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
97
104
|
hls.off(
|
@@ -99,6 +106,7 @@ export default class StreamController
|
|
99
106
|
this.onFragLoadEmergencyAborted,
|
100
107
|
this,
|
101
108
|
);
|
109
|
+
hls.off(Events.ERROR, this.onError, this);
|
102
110
|
hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
103
111
|
hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
104
112
|
hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -108,9 +116,7 @@ export default class StreamController
|
|
108
116
|
}
|
109
117
|
|
110
118
|
protected onHandlerDestroying() {
|
111
|
-
|
112
|
-
this.onMediaPlaying = this.onMediaSeeked = null;
|
113
|
-
this.unregisterListeners();
|
119
|
+
this._unregisterListeners();
|
114
120
|
super.onHandlerDestroying();
|
115
121
|
}
|
116
122
|
|
@@ -509,8 +515,10 @@ export default class StreamController
|
|
509
515
|
) {
|
510
516
|
super.onMediaAttached(event, data);
|
511
517
|
const media = data.media;
|
512
|
-
|
513
|
-
|
518
|
+
this.onvplaying = this.onMediaPlaying.bind(this);
|
519
|
+
this.onvseeked = this.onMediaSeeked.bind(this);
|
520
|
+
media.addEventListener('playing', this.onvplaying as EventListener);
|
521
|
+
media.addEventListener('seeked', this.onvseeked as EventListener);
|
514
522
|
this.gapController = new GapController(
|
515
523
|
this.config,
|
516
524
|
media,
|
@@ -521,9 +529,10 @@ export default class StreamController
|
|
521
529
|
|
522
530
|
protected onMediaDetaching() {
|
523
531
|
const { media } = this;
|
524
|
-
if (media) {
|
525
|
-
media.removeEventListener('playing', this.
|
526
|
-
media.removeEventListener('seeked', this.
|
532
|
+
if (media && this.onvplaying && this.onvseeked) {
|
533
|
+
media.removeEventListener('playing', this.onvplaying);
|
534
|
+
media.removeEventListener('seeked', this.onvseeked);
|
535
|
+
this.onvplaying = this.onvseeked = null;
|
527
536
|
this.videoBuffer = null;
|
528
537
|
}
|
529
538
|
this.fragPlaying = null;
|
@@ -534,12 +543,12 @@ export default class StreamController
|
|
534
543
|
super.onMediaDetaching();
|
535
544
|
}
|
536
545
|
|
537
|
-
private onMediaPlaying
|
546
|
+
private onMediaPlaying() {
|
538
547
|
// tick to speed up FRAG_CHANGED triggering
|
539
548
|
this.tick();
|
540
|
-
}
|
549
|
+
}
|
541
550
|
|
542
|
-
private onMediaSeeked
|
551
|
+
private onMediaSeeked() {
|
543
552
|
const media = this.media;
|
544
553
|
const currentTime = media ? media.currentTime : null;
|
545
554
|
if (Number.isFinite(currentTime)) {
|
@@ -559,9 +568,9 @@ export default class StreamController
|
|
559
568
|
|
560
569
|
// tick to speed up FRAG_CHANGED triggering
|
561
570
|
this.tick();
|
562
|
-
}
|
571
|
+
}
|
563
572
|
|
564
|
-
|
573
|
+
private onManifestLoading() {
|
565
574
|
// reset buffer on manifest loading
|
566
575
|
this.log('Trigger BUFFER_RESET');
|
567
576
|
this.hls.trigger(Events.BUFFER_RESET, undefined);
|
@@ -874,7 +883,7 @@ export default class StreamController
|
|
874
883
|
this.fragBufferedComplete(frag, part);
|
875
884
|
}
|
876
885
|
|
877
|
-
|
886
|
+
private onError(event: Events.ERROR, data: ErrorData) {
|
878
887
|
if (data.fatal) {
|
879
888
|
this.state = State.ERROR;
|
880
889
|
return;
|
@@ -9,10 +9,6 @@ import { PlaylistLevelType } from '../types/loader';
|
|
9
9
|
import { Level } from '../types/level';
|
10
10
|
import { subtitleOptionsIdentical } from '../utils/media-option-attributes';
|
11
11
|
import { ErrorDetails, ErrorTypes } from '../errors';
|
12
|
-
import {
|
13
|
-
isFullSegmentEncryption,
|
14
|
-
getAesModeFromFullSegmentMethod,
|
15
|
-
} from '../utils/encryption-methods-util';
|
16
12
|
import type { NetworkComponentAPI } from '../types/component-api';
|
17
13
|
import type Hls from '../hls';
|
18
14
|
import type { FragmentTracker } from './fragment-tracker';
|
@@ -55,22 +51,25 @@ export class SubtitleStreamController
|
|
55
51
|
hls,
|
56
52
|
fragmentTracker,
|
57
53
|
keyLoader,
|
58
|
-
'subtitle-stream-controller',
|
54
|
+
'[subtitle-stream-controller]',
|
59
55
|
PlaylistLevelType.SUBTITLE,
|
60
56
|
);
|
61
|
-
this.
|
57
|
+
this._registerListeners();
|
62
58
|
}
|
63
59
|
|
64
60
|
protected onHandlerDestroying() {
|
65
|
-
this.
|
61
|
+
this._unregisterListeners();
|
66
62
|
super.onHandlerDestroying();
|
67
63
|
this.mainDetails = null;
|
68
64
|
}
|
69
65
|
|
70
|
-
|
71
|
-
super.registerListeners();
|
66
|
+
private _registerListeners() {
|
72
67
|
const { hls } = this;
|
68
|
+
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
69
|
+
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
70
|
+
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
73
71
|
hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
72
|
+
hls.on(Events.ERROR, this.onError, this);
|
74
73
|
hls.on(Events.SUBTITLE_TRACKS_UPDATED, this.onSubtitleTracksUpdated, this);
|
75
74
|
hls.on(Events.SUBTITLE_TRACK_SWITCH, this.onSubtitleTrackSwitch, this);
|
76
75
|
hls.on(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this);
|
@@ -79,10 +78,13 @@ export class SubtitleStreamController
|
|
79
78
|
hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
80
79
|
}
|
81
80
|
|
82
|
-
|
83
|
-
super.unregisterListeners();
|
81
|
+
private _unregisterListeners() {
|
84
82
|
const { hls } = this;
|
83
|
+
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
84
|
+
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
85
|
+
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
85
86
|
hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
87
|
+
hls.off(Events.ERROR, this.onError, this);
|
86
88
|
hls.off(Events.SUBTITLE_TRACKS_UPDATED, this.onSubtitleTracksUpdated, this);
|
87
89
|
hls.off(Events.SUBTITLE_TRACK_SWITCH, this.onSubtitleTrackSwitch, this);
|
88
90
|
hls.off(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this);
|
@@ -358,7 +360,7 @@ export class SubtitleStreamController
|
|
358
360
|
payload.byteLength > 0 &&
|
359
361
|
decryptData?.key &&
|
360
362
|
decryptData.iv &&
|
361
|
-
|
363
|
+
decryptData.method === 'AES-128'
|
362
364
|
) {
|
363
365
|
const startTime = performance.now();
|
364
366
|
// decrypt the subtitles
|
@@ -367,7 +369,6 @@ export class SubtitleStreamController
|
|
367
369
|
new Uint8Array(payload),
|
368
370
|
decryptData.key.buffer,
|
369
371
|
decryptData.iv.buffer,
|
370
|
-
getAesModeFromFullSegmentMethod(decryptData.method),
|
371
372
|
)
|
372
373
|
.catch((err) => {
|
373
374
|
hls.trigger(Events.ERROR, {
|
@@ -35,14 +35,13 @@ class SubtitleTrackController extends BasePlaylistController {
|
|
35
35
|
private currentTrack: MediaPlaylist | null = null;
|
36
36
|
private selectDefaultTrack: boolean = true;
|
37
37
|
private queuedDefaultTrack: number = -1;
|
38
|
+
private asyncPollTrackChange: () => void = () => this.pollTrackChange(0);
|
38
39
|
private useTextTrackPolling: boolean = false;
|
39
40
|
private subtitlePollingInterval: number = -1;
|
40
41
|
private _subtitleDisplay: boolean = true;
|
41
42
|
|
42
|
-
private asyncPollTrackChange = () => this.pollTrackChange(0);
|
43
|
-
|
44
43
|
constructor(hls: Hls) {
|
45
|
-
super(hls, 'subtitle-track-controller');
|
44
|
+
super(hls, '[subtitle-track-controller]');
|
46
45
|
this.registerListeners();
|
47
46
|
}
|
48
47
|
|
@@ -51,8 +50,7 @@ class SubtitleTrackController extends BasePlaylistController {
|
|
51
50
|
this.tracks.length = 0;
|
52
51
|
this.tracksInGroup.length = 0;
|
53
52
|
this.currentTrack = null;
|
54
|
-
|
55
|
-
this.onTextTracksChanged = this.asyncPollTrackChange = null;
|
53
|
+
this.onTextTracksChanged = this.asyncPollTrackChange = null as any;
|
56
54
|
super.destroy();
|
57
55
|
}
|
58
56
|
|