hls.js 1.5.6-0.canary.10011 → 1.5.6

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.
Files changed (68) hide show
  1. package/README.md +0 -1
  2. package/dist/hls-demo.js +0 -10
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +1134 -2043
  5. package/dist/hls.js.d.ts +50 -65
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +852 -1141
  8. package/dist/hls.light.js.map +1 -1
  9. package/dist/hls.light.min.js +1 -1
  10. package/dist/hls.light.min.js.map +1 -1
  11. package/dist/hls.light.mjs +686 -974
  12. package/dist/hls.light.mjs.map +1 -1
  13. package/dist/hls.min.js +1 -1
  14. package/dist/hls.min.js.map +1 -1
  15. package/dist/hls.mjs +847 -1741
  16. package/dist/hls.mjs.map +1 -1
  17. package/dist/hls.worker.js +1 -1
  18. package/dist/hls.worker.js.map +1 -1
  19. package/package.json +21 -21
  20. package/src/config.ts +2 -3
  21. package/src/controller/abr-controller.ts +20 -21
  22. package/src/controller/audio-stream-controller.ts +16 -15
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +8 -20
  25. package/src/controller/base-stream-controller.ts +33 -149
  26. package/src/controller/buffer-controller.ts +11 -11
  27. package/src/controller/cap-level-controller.ts +2 -1
  28. package/src/controller/cmcd-controller.ts +6 -27
  29. package/src/controller/content-steering-controller.ts +6 -8
  30. package/src/controller/eme-controller.ts +22 -9
  31. package/src/controller/error-controller.ts +8 -6
  32. package/src/controller/fps-controller.ts +3 -2
  33. package/src/controller/gap-controller.ts +16 -43
  34. package/src/controller/latency-controller.ts +11 -9
  35. package/src/controller/level-controller.ts +18 -12
  36. package/src/controller/stream-controller.ts +32 -25
  37. package/src/controller/subtitle-stream-controller.ts +14 -13
  38. package/src/controller/subtitle-track-controller.ts +3 -5
  39. package/src/controller/timeline-controller.ts +30 -23
  40. package/src/crypt/aes-crypto.ts +2 -21
  41. package/src/crypt/decrypter.ts +18 -32
  42. package/src/crypt/fast-aes-key.ts +5 -24
  43. package/src/demux/audio/adts.ts +4 -9
  44. package/src/demux/sample-aes.ts +0 -2
  45. package/src/demux/transmuxer-interface.ts +12 -4
  46. package/src/demux/transmuxer-worker.ts +4 -4
  47. package/src/demux/transmuxer.ts +3 -16
  48. package/src/demux/tsdemuxer.ts +37 -71
  49. package/src/demux/video/avc-video-parser.ts +119 -208
  50. package/src/demux/video/base-video-parser.ts +2 -134
  51. package/src/demux/video/exp-golomb.ts +208 -0
  52. package/src/events.ts +0 -7
  53. package/src/hls.ts +34 -42
  54. package/src/loader/fragment-loader.ts +2 -9
  55. package/src/loader/key-loader.ts +0 -2
  56. package/src/loader/level-key.ts +9 -10
  57. package/src/loader/playlist-loader.ts +5 -4
  58. package/src/remux/mp4-generator.ts +1 -196
  59. package/src/remux/mp4-remuxer.ts +7 -23
  60. package/src/task-loop.ts +2 -5
  61. package/src/types/component-api.ts +0 -2
  62. package/src/types/demuxer.ts +0 -3
  63. package/src/types/events.ts +0 -4
  64. package/src/utils/codecs.ts +4 -33
  65. package/src/utils/logger.ts +24 -54
  66. package/src/crypt/decrypter-aes-mode.ts +0 -4
  67. package/src/demux/video/hevc-video-parser.ts +0 -746
  68. package/src/utils/encryption-methods-util.ts +0 -21
@@ -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
- // hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
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
- hls.logger.warn(
93
+ logger.warn(
93
94
  'drop FPS ratio greater than max allowed value for currentLevel: ' +
94
95
  currentLevel,
95
96
  );
@@ -1,22 +1,20 @@
1
- import { State } from './base-stream-controller';
1
+ import type { BufferInfo } from '../utils/buffer-helper';
2
2
  import { BufferHelper } from '../utils/buffer-helper';
3
3
  import { ErrorTypes, ErrorDetails } from '../errors';
4
4
  import { PlaylistLevelType } from '../types/loader';
5
5
  import { Events } from '../events';
6
- import { Logger } from '../utils/logger';
6
+ import { logger } from '../utils/logger';
7
7
  import type Hls from '../hls';
8
- import type { BufferInfo } from '../utils/buffer-helper';
9
8
  import type { HlsConfig } from '../config';
10
9
  import type { Fragment } from '../loader/fragment';
11
10
  import type { FragmentTracker } from './fragment-tracker';
12
- import type { LevelDetails } from '../loader/level-details';
13
11
 
14
12
  export const STALL_MINIMUM_DURATION_MS = 250;
15
13
  export const MAX_START_GAP_JUMP = 2.0;
16
14
  export const SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
17
15
  export const SKIP_BUFFER_RANGE_START = 0.05;
18
16
 
19
- export default class GapController extends Logger {
17
+ export default class GapController {
20
18
  private config: HlsConfig;
21
19
  private media: HTMLMediaElement | null = null;
22
20
  private fragmentTracker: FragmentTracker;
@@ -26,15 +24,8 @@ export default class GapController extends Logger {
26
24
  private stalled: number | null = null;
27
25
  private moved: boolean = false;
28
26
  private seeking: boolean = false;
29
- private ended: number = 0;
30
27
 
31
- constructor(
32
- config: HlsConfig,
33
- media: HTMLMediaElement,
34
- fragmentTracker: FragmentTracker,
35
- hls: Hls,
36
- ) {
37
- super('gap-controller', hls.logger);
28
+ constructor(config, media, fragmentTracker, hls) {
38
29
  this.config = config;
39
30
  this.media = media;
40
31
  this.fragmentTracker = fragmentTracker;
@@ -53,12 +44,7 @@ export default class GapController extends Logger {
53
44
  *
54
45
  * @param lastCurrentTime - Previously read playhead position
55
46
  */
56
- public poll(
57
- lastCurrentTime: number,
58
- activeFrag: Fragment | null,
59
- levelDetails: LevelDetails | undefined,
60
- state: string,
61
- ) {
47
+ public poll(lastCurrentTime: number, activeFrag: Fragment | null) {
62
48
  const { config, media, stalled } = this;
63
49
  if (media === null) {
64
50
  return;
@@ -71,7 +57,6 @@ export default class GapController extends Logger {
71
57
 
72
58
  // The playhead is moving, no-op
73
59
  if (currentTime !== lastCurrentTime) {
74
- this.ended = 0;
75
60
  this.moved = true;
76
61
  if (!seeking) {
77
62
  this.nudgeRetry = 0;
@@ -80,7 +65,7 @@ export default class GapController extends Logger {
80
65
  // The playhead is now moving, but was previously stalled
81
66
  if (this.stallReported) {
82
67
  const stalledDuration = self.performance.now() - stalled;
83
- this.warn(
68
+ logger.warn(
84
69
  `playback not stuck anymore @${currentTime}, after ${Math.round(
85
70
  stalledDuration,
86
71
  )}ms`,
@@ -143,9 +128,12 @@ export default class GapController extends Logger {
143
128
  // When joining a live stream with audio tracks, account for live playlist window sliding by allowing
144
129
  // a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
145
130
  // that begins over 1 target duration after the video start position.
146
- const isLive = !!levelDetails?.live;
131
+ const level = this.hls.levels
132
+ ? this.hls.levels[this.hls.currentLevel]
133
+ : null;
134
+ const isLive = level?.details?.live;
147
135
  const maxStartGapJump = isLive
148
- ? levelDetails!.targetduration * 2
136
+ ? level!.details!.targetduration * 2
149
137
  : MAX_START_GAP_JUMP;
150
138
  const partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
151
139
  if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
@@ -165,21 +153,6 @@ export default class GapController extends Logger {
165
153
 
166
154
  const stalledDuration = tnow - stalled;
167
155
  if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
168
- // Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
169
- if (
170
- state === State.ENDED &&
171
- !(levelDetails && levelDetails.live) &&
172
- Math.abs(currentTime - (levelDetails?.edge || 0)) < 1
173
- ) {
174
- if (stalledDuration < 1000 || this.ended) {
175
- return;
176
- }
177
- this.ended = currentTime;
178
- this.hls.trigger(Events.MEDIA_ENDED, {
179
- stalled: true,
180
- });
181
- return;
182
- }
183
156
  // Report stalling after trying to fix
184
157
  this._reportStall(bufferInfo);
185
158
  if (!this.media) {
@@ -233,7 +206,7 @@ export default class GapController extends Logger {
233
206
  bufferInfo.nextStart - currentTime < config.maxBufferHole)) &&
234
207
  stalledDurationMs > config.highBufferWatchdogPeriod * 1000
235
208
  ) {
236
- this.warn('Trying to nudge playhead over buffer-hole');
209
+ logger.warn('Trying to nudge playhead over buffer-hole');
237
210
  // Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
238
211
  // We only try to jump the hole if it's under the configured size
239
212
  // Reset stalled so to rearm watchdog timer
@@ -257,7 +230,7 @@ export default class GapController extends Logger {
257
230
  media.currentTime
258
231
  } due to low buffer (${JSON.stringify(bufferInfo)})`,
259
232
  );
260
- this.warn(error.message);
233
+ logger.warn(error.message);
261
234
  hls.trigger(Events.ERROR, {
262
235
  type: ErrorTypes.MEDIA_ERROR,
263
236
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -332,7 +305,7 @@ export default class GapController extends Logger {
332
305
  startTime + SKIP_BUFFER_RANGE_START,
333
306
  currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS,
334
307
  );
335
- this.warn(
308
+ logger.warn(
336
309
  `skipping hole, adjusting currentTime from ${currentTime} to ${targetTime}`,
337
310
  );
338
311
  this.moved = true;
@@ -375,7 +348,7 @@ export default class GapController extends Logger {
375
348
  const error = new Error(
376
349
  `Nudging 'currentTime' from ${currentTime} to ${targetTime}`,
377
350
  );
378
- this.warn(error.message);
351
+ logger.warn(error.message);
379
352
  media.currentTime = targetTime;
380
353
  hls.trigger(Events.ERROR, {
381
354
  type: ErrorTypes.MEDIA_ERROR,
@@ -387,7 +360,7 @@ export default class GapController extends Logger {
387
360
  const error = new Error(
388
361
  `Playhead still not moving while enough data buffered @${currentTime} after ${config.nudgeMaxRetry} nudges`,
389
362
  );
390
- this.error(error.message);
363
+ logger.error(error.message);
391
364
  hls.trigger(Events.ERROR, {
392
365
  type: ErrorTypes.MEDIA_ERROR,
393
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.onTimeupdate);
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.onTimeupdate);
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.onTimeupdate();
175
+ this.timeupdate();
174
176
  }
175
177
  if (!details.live && this.media) {
176
- this.media.removeEventListener('timeupdate', this.onTimeupdate);
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
- this.hls.logger.warn(
187
- '[latency-controller]: Stall detected, adjusting target latency',
188
+ logger.warn(
189
+ '[playback-rate-controller]: Stall detected, adjusting target latency',
188
190
  );
189
191
  }
190
192
  }
191
193
 
192
- private onTimeupdate = () => {
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;
@@ -27,6 +27,8 @@ import type Hls from '../hls';
27
27
  import type { HlsUrlParameters, LevelParsed } from '../types/level';
28
28
  import type { MediaPlaylist } from '../types/media-playlist';
29
29
 
30
+ let chromeOrFirefox: boolean;
31
+
30
32
  export default class LevelController extends BasePlaylistController {
31
33
  private _levels: Level[] = [];
32
34
  private _firstLevel: number = -1;
@@ -43,7 +45,7 @@ export default class LevelController extends BasePlaylistController {
43
45
  hls: Hls,
44
46
  contentSteeringController: ContentSteeringController | null,
45
47
  ) {
46
- super(hls, 'level-controller');
48
+ super(hls, '[level-controller]');
47
49
  this.steering = contentSteeringController;
48
50
  this._registerListeners();
49
51
  }
@@ -117,12 +119,22 @@ export default class LevelController extends BasePlaylistController {
117
119
 
118
120
  data.levels.forEach((levelParsed: LevelParsed) => {
119
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
120
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
+
121
133
  if (audioCodec) {
122
- // Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
123
- levelParsed.audioCodec = audioCodec =
124
- getCodecCompatibleName(audioCodec, preferManagedMediaSource) ||
125
- undefined;
134
+ levelParsed.audioCodec = audioCodec = getCodecCompatibleName(
135
+ audioCodec,
136
+ preferManagedMediaSource,
137
+ );
126
138
  }
127
139
 
128
140
  if (videoCodec?.indexOf('avc1') === 0) {
@@ -556,13 +568,7 @@ export default class LevelController extends BasePlaylistController {
556
568
  if (curLevel.fragmentError === 0) {
557
569
  curLevel.loadError = 0;
558
570
  }
559
- // Ignore matching details populated by loading a Media Playlist directly
560
- let previousDetails = curLevel.details;
561
- if (previousDetails === data.details && previousDetails.advanced) {
562
- previousDetails = undefined;
563
- }
564
-
565
- this.playlistLoaded(level, data, previousDetails);
571
+ this.playlistLoaded(level, data, curLevel.details);
566
572
  } else if (data.deliveryDirectives?.skip) {
567
573
  // received a delta playlist update that cannot be merged
568
574
  details.deltaUpdateFailed = true;
@@ -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.registerListeners();
72
+ this._registerListeners();
71
73
  }
72
74
 
73
- protected registerListeners() {
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 unregisterListeners() {
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
- // @ts-ignore
112
- this.onMediaPlaying = this.onMediaSeeked = null;
113
- this.unregisterListeners();
119
+ this._unregisterListeners();
114
120
  super.onHandlerDestroying();
115
121
  }
116
122
 
@@ -232,7 +238,7 @@ export default class StreamController
232
238
  }
233
239
 
234
240
  const level = hls.nextLoadLevel;
235
- if (!this.buffering || !levels?.[level]) {
241
+ if (!levels?.[level]) {
236
242
  return;
237
243
  }
238
244
 
@@ -510,8 +516,10 @@ export default class StreamController
510
516
  ) {
511
517
  super.onMediaAttached(event, data);
512
518
  const media = data.media;
513
- media.addEventListener('playing', this.onMediaPlaying);
514
- media.addEventListener('seeked', this.onMediaSeeked);
519
+ this.onvplaying = this.onMediaPlaying.bind(this);
520
+ this.onvseeked = this.onMediaSeeked.bind(this);
521
+ media.addEventListener('playing', this.onvplaying as EventListener);
522
+ media.addEventListener('seeked', this.onvseeked as EventListener);
515
523
  this.gapController = new GapController(
516
524
  this.config,
517
525
  media,
@@ -522,9 +530,10 @@ export default class StreamController
522
530
 
523
531
  protected onMediaDetaching() {
524
532
  const { media } = this;
525
- if (media) {
526
- media.removeEventListener('playing', this.onMediaPlaying);
527
- media.removeEventListener('seeked', this.onMediaSeeked);
533
+ if (media && this.onvplaying && this.onvseeked) {
534
+ media.removeEventListener('playing', this.onvplaying);
535
+ media.removeEventListener('seeked', this.onvseeked);
536
+ this.onvplaying = this.onvseeked = null;
528
537
  this.videoBuffer = null;
529
538
  }
530
539
  this.fragPlaying = null;
@@ -535,12 +544,12 @@ export default class StreamController
535
544
  super.onMediaDetaching();
536
545
  }
537
546
 
538
- private onMediaPlaying = () => {
547
+ private onMediaPlaying() {
539
548
  // tick to speed up FRAG_CHANGED triggering
540
549
  this.tick();
541
- };
550
+ }
542
551
 
543
- private onMediaSeeked = () => {
552
+ private onMediaSeeked() {
544
553
  const media = this.media;
545
554
  const currentTime = media ? media.currentTime : null;
546
555
  if (Number.isFinite(currentTime)) {
@@ -560,9 +569,9 @@ export default class StreamController
560
569
 
561
570
  // tick to speed up FRAG_CHANGED triggering
562
571
  this.tick();
563
- };
572
+ }
564
573
 
565
- protected onManifestLoading() {
574
+ private onManifestLoading() {
566
575
  // reset buffer on manifest loading
567
576
  this.log('Trigger BUFFER_RESET');
568
577
  this.hls.trigger(Events.BUFFER_RESET, undefined);
@@ -875,7 +884,7 @@ export default class StreamController
875
884
  this.fragBufferedComplete(frag, part);
876
885
  }
877
886
 
878
- protected onError(event: Events.ERROR, data: ErrorData) {
887
+ private onError(event: Events.ERROR, data: ErrorData) {
879
888
  if (data.fatal) {
880
889
  this.state = State.ERROR;
881
890
  return;
@@ -933,10 +942,8 @@ export default class StreamController
933
942
 
934
943
  if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
935
944
  // Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
936
- const state = this.state;
937
- const activeFrag = state !== State.IDLE ? this.fragCurrent : null;
938
- const levelDetails = this.getLevelDetails();
939
- gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
945
+ const activeFrag = this.state !== State.IDLE ? this.fragCurrent : null;
946
+ gapController.poll(this.lastCurrentTime, activeFrag);
940
947
  }
941
948
 
942
949
  this.lastCurrentTime = media.currentTime;
@@ -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.registerListeners();
57
+ this._registerListeners();
62
58
  }
63
59
 
64
60
  protected onHandlerDestroying() {
65
- this.unregisterListeners();
61
+ this._unregisterListeners();
66
62
  super.onHandlerDestroying();
67
63
  this.mainDetails = null;
68
64
  }
69
65
 
70
- protected registerListeners() {
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
- protected unregisterListeners() {
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
- isFullSegmentEncryption(decryptData.method)
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
- // @ts-ignore
55
- this.onTextTracksChanged = this.asyncPollTrackChange = null;
53
+ this.onTextTracksChanged = this.asyncPollTrackChange = null as any;
56
54
  super.destroy();
57
55
  }
58
56