hls.js 1.5.5-0.canary.9997 → 1.5.5

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 +20 -20
  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,15 +1,12 @@
1
1
  import TaskLoop from '../task-loop';
2
2
  import { FragmentState } from './fragment-tracker';
3
3
  import { Bufferable, BufferHelper, BufferInfo } from '../utils/buffer-helper';
4
+ import { logger } from '../utils/logger';
4
5
  import { Events } from '../events';
5
6
  import { ErrorDetails, ErrorTypes } from '../errors';
6
7
  import { ChunkMetadata } from '../types/transmuxer';
7
8
  import { appendUint8Array } from '../utils/mp4-tools';
8
9
  import { alignStream } from '../utils/discontinuities';
9
- import {
10
- isFullSegmentEncryption,
11
- getAesModeFromFullSegmentMethod,
12
- } from '../utils/encryption-methods-util';
13
10
  import {
14
11
  findFragmentByPDT,
15
12
  findFragmentByPTS,
@@ -100,8 +97,12 @@ export default class BaseStreamController
100
97
  protected startFragRequested: boolean = false;
101
98
  protected decrypter: Decrypter;
102
99
  protected initPTS: RationalTimestamp[] = [];
103
- protected buffering: boolean = true;
104
- private loadingParts: boolean = false;
100
+ protected onvseeking: EventListener | null = null;
101
+ protected onvended: EventListener | null = null;
102
+
103
+ private readonly logPrefix: string = '';
104
+ protected log: (msg: any) => void;
105
+ protected warn: (msg: any) => void;
105
106
 
106
107
  constructor(
107
108
  hls: Hls,
@@ -110,32 +111,18 @@ export default class BaseStreamController
110
111
  logPrefix: string,
111
112
  playlistType: PlaylistLevelType,
112
113
  ) {
113
- super(logPrefix, hls.logger);
114
+ super();
114
115
  this.playlistType = playlistType;
116
+ this.logPrefix = logPrefix;
117
+ this.log = logger.log.bind(logger, `${logPrefix}:`);
118
+ this.warn = logger.warn.bind(logger, `${logPrefix}:`);
115
119
  this.hls = hls;
116
120
  this.fragmentLoader = new FragmentLoader(hls.config);
117
121
  this.keyLoader = keyLoader;
118
122
  this.fragmentTracker = fragmentTracker;
119
123
  this.config = hls.config;
120
124
  this.decrypter = new Decrypter(hls.config);
121
- }
122
-
123
- protected registerListeners() {
124
- const { hls } = this;
125
- hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
126
- hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
127
- hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
128
125
  hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
129
- hls.on(Events.ERROR, this.onError, this);
130
- }
131
-
132
- protected unregisterListeners() {
133
- const { hls } = this;
134
- hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
135
- hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
136
- hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
137
- hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
138
- hls.off(Events.ERROR, this.onError, this);
139
126
  }
140
127
 
141
128
  protected doTick() {
@@ -163,14 +150,6 @@ export default class BaseStreamController
163
150
  this.state = State.STOPPED;
164
151
  }
165
152
 
166
- public pauseBuffering() {
167
- this.buffering = false;
168
- }
169
-
170
- public resumeBuffering() {
171
- this.buffering = true;
172
- }
173
-
174
153
  protected _streamEnded(
175
154
  bufferInfo: BufferInfo,
176
155
  levelDetails: LevelDetails,
@@ -218,8 +197,10 @@ export default class BaseStreamController
218
197
  data: MediaAttachedData,
219
198
  ) {
220
199
  const media = (this.media = this.mediaBuffer = data.media);
221
- media.addEventListener('seeking', this.onMediaSeeking);
222
- media.addEventListener('ended', this.onMediaEnded);
200
+ this.onvseeking = this.onMediaSeeking.bind(this) as EventListener;
201
+ this.onvended = this.onMediaEnded.bind(this) as EventListener;
202
+ media.addEventListener('seeking', this.onvseeking);
203
+ media.addEventListener('ended', this.onvended);
223
204
  const config = this.config;
224
205
  if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
225
206
  this.startLoad(config.startPosition);
@@ -234,9 +215,10 @@ export default class BaseStreamController
234
215
  }
235
216
 
236
217
  // remove video listeners
237
- if (media) {
238
- media.removeEventListener('seeking', this.onMediaSeeking);
239
- media.removeEventListener('ended', this.onMediaEnded);
218
+ if (media && this.onvseeking && this.onvended) {
219
+ media.removeEventListener('seeking', this.onvseeking);
220
+ media.removeEventListener('ended', this.onvended);
221
+ this.onvseeking = this.onvended = null;
240
222
  }
241
223
  if (this.keyLoader) {
242
224
  this.keyLoader.detach();
@@ -247,11 +229,7 @@ export default class BaseStreamController
247
229
  this.stopLoad();
248
230
  }
249
231
 
250
- protected onManifestLoading() {}
251
-
252
- protected onError(event: Events.ERROR, data: ErrorData) {}
253
-
254
- protected onMediaSeeking = () => {
232
+ protected onMediaSeeking() {
255
233
  const { config, fragCurrent, media, mediaBuffer, state } = this;
256
234
  const currentTime: number = media ? media.currentTime : 0;
257
235
  const bufferInfo = BufferHelper.bufferInfo(
@@ -305,21 +283,6 @@ export default class BaseStreamController
305
283
  );
306
284
 
307
285
  this.lastCurrentTime = currentTime;
308
- if (!this.loadingParts) {
309
- const bufferEnd = Math.max(bufferInfo.end, currentTime);
310
- const shouldLoadParts = this.shouldLoadParts(
311
- this.getLevelDetails(),
312
- bufferEnd,
313
- );
314
- if (shouldLoadParts) {
315
- this.log(
316
- `LL-Part loading ON after seeking to ${currentTime.toFixed(
317
- 2,
318
- )} with buffer @${bufferEnd.toFixed(2)}`,
319
- );
320
- this.loadingParts = shouldLoadParts;
321
- }
322
- }
323
286
  }
324
287
 
325
288
  // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
@@ -329,17 +292,12 @@ export default class BaseStreamController
329
292
 
330
293
  // Async tick to speed up processing
331
294
  this.tickImmediate();
332
- };
295
+ }
333
296
 
334
- protected onMediaEnded = () => {
297
+ protected onMediaEnded() {
335
298
  // reset startPosition and lastCurrentTime to restart playback @ stream beginning
336
299
  this.startPosition = this.lastCurrentTime = 0;
337
- if (this.playlistType === PlaylistLevelType.MAIN) {
338
- this.hls.trigger(Events.MEDIA_ENDED, {
339
- stalled: false,
340
- });
341
- }
342
- };
300
+ }
343
301
 
344
302
  protected onManifestLoaded(
345
303
  event: Events.MANIFEST_LOADED,
@@ -354,7 +312,7 @@ export default class BaseStreamController
354
312
  this.stopLoad();
355
313
  super.onHandlerDestroying();
356
314
  // @ts-ignore
357
- this.hls = this.onMediaSeeking = this.onMediaEnded = null;
315
+ this.hls = null;
358
316
  }
359
317
 
360
318
  protected onHandlerDestroyed() {
@@ -528,7 +486,7 @@ export default class BaseStreamController
528
486
  payload.byteLength > 0 &&
529
487
  decryptData?.key &&
530
488
  decryptData.iv &&
531
- isFullSegmentEncryption(decryptData.method)
489
+ decryptData.method === 'AES-128'
532
490
  ) {
533
491
  const startTime = self.performance.now();
534
492
  // decrypt init segment data
@@ -537,7 +495,6 @@ export default class BaseStreamController
537
495
  new Uint8Array(payload),
538
496
  decryptData.key.buffer,
539
497
  decryptData.iv.buffer,
540
- getAesModeFromFullSegmentMethod(decryptData.method),
541
498
  )
542
499
  .catch((err) => {
543
500
  hls.trigger(Events.ERROR, {
@@ -692,7 +649,7 @@ export default class BaseStreamController
692
649
  if (frag.encrypted && !frag.decryptdata?.key) {
693
650
  this.log(
694
651
  `Loading key for ${frag.sn} of [${details.startSN}-${details.endSN}], ${
695
- this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track'
652
+ this.logPrefix === '[stream-controller]' ? 'level' : 'track'
696
653
  } ${frag.level}`,
697
654
  );
698
655
  this.state = State.KEY_LOADING;
@@ -716,23 +673,8 @@ export default class BaseStreamController
716
673
  this.keyLoader.loadClear(frag, details.encryptedFragments);
717
674
  }
718
675
 
719
- const fragPrevious = this.fragPrevious;
720
- if (
721
- frag.sn !== 'initSegment' &&
722
- (!fragPrevious || frag.sn !== fragPrevious.sn)
723
- ) {
724
- const shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
725
- if (shouldLoadParts !== this.loadingParts) {
726
- this.log(
727
- `LL-Part loading ${
728
- shouldLoadParts ? 'ON' : 'OFF'
729
- } loading sn ${fragPrevious?.sn}->${frag.sn}`,
730
- );
731
- this.loadingParts = shouldLoadParts;
732
- }
733
- }
734
676
  targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
735
- if (this.loadingParts && frag.sn !== 'initSegment') {
677
+ if (this.config.lowLatencyMode && frag.sn !== 'initSegment') {
736
678
  const partList = details.partList;
737
679
  if (partList && progressCallback) {
738
680
  if (targetBufferTime > frag.end && details.fragmentHint) {
@@ -747,7 +689,7 @@ export default class BaseStreamController
747
689
  } of playlist [${details.startSN}-${
748
690
  details.endSN
749
691
  }] parts [0-${partIndex}-${partList.length - 1}] ${
750
- this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track'
692
+ this.logPrefix === '[stream-controller]' ? 'level' : 'track'
751
693
  }: ${frag.level}, target: ${parseFloat(
752
694
  targetBufferTime.toFixed(3),
753
695
  )}`,
@@ -803,22 +745,10 @@ export default class BaseStreamController
803
745
  }
804
746
  }
805
747
 
806
- if (frag.sn !== 'initSegment' && this.loadingParts) {
807
- this.log(
808
- `LL-Part loading OFF after next part miss @${targetBufferTime.toFixed(
809
- 2,
810
- )}`,
811
- );
812
- this.loadingParts = false;
813
- } else if (!frag.url) {
814
- // Selected fragment hint for part but not loading parts
815
- return Promise.resolve(null);
816
- }
817
-
818
748
  this.log(
819
749
  `Loading fragment ${frag.sn} cc: ${frag.cc} ${
820
750
  details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : ''
821
- }${this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track'}: ${
751
+ }${this.logPrefix === '[stream-controller]' ? 'level' : 'track'}: ${
822
752
  frag.level
823
753
  }, target: ${parseFloat(targetBufferTime.toFixed(3))}`,
824
754
  );
@@ -942,50 +872,9 @@ export default class BaseStreamController
942
872
  if (part) {
943
873
  part.stats.parsing.end = now;
944
874
  }
945
- // See if part loading should be disabled/enabled based on buffer and playback position.
946
- if (frag.sn !== 'initSegment') {
947
- const levelDetails = this.getLevelDetails();
948
- const loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
949
- const shouldLoadParts =
950
- loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
951
- if (shouldLoadParts !== this.loadingParts) {
952
- this.log(
953
- `LL-Part loading ${
954
- shouldLoadParts ? 'ON' : 'OFF'
955
- } after parsing segment ending @${frag.end.toFixed(2)}`,
956
- );
957
- this.loadingParts = shouldLoadParts;
958
- }
959
- }
960
-
961
875
  this.updateLevelTiming(frag, part, level, chunkMeta.partial);
962
876
  }
963
877
 
964
- private shouldLoadParts(
965
- details: LevelDetails | undefined,
966
- bufferEnd: number,
967
- ): boolean {
968
- if (this.config.lowLatencyMode) {
969
- if (!details) {
970
- return this.loadingParts;
971
- }
972
- if (details?.partList) {
973
- // Buffer must be ahead of first part + duration of parts after last segment
974
- // and playback must be at or past segment adjacent to part list
975
- const firstPart = details.partList[0];
976
- const safePartStart =
977
- firstPart.end + (details.fragmentHint?.duration || 0);
978
- if (
979
- bufferEnd >= safePartStart &&
980
- this.lastCurrentTime > firstPart.start - firstPart.fragment.duration
981
- ) {
982
- return true;
983
- }
984
- }
985
- }
986
- return false;
987
- }
988
-
989
878
  protected getCurrentContext(
990
879
  chunkMeta: ChunkMetadata,
991
880
  ): { frag: Fragment; part: Part | null; level: Level } | null {
@@ -1167,8 +1056,7 @@ export default class BaseStreamController
1167
1056
  // find fragment index, contiguous with end of buffer position
1168
1057
  const { config } = this;
1169
1058
  const start = fragments[0].start;
1170
- const canLoadParts = config.lowLatencyMode && !!levelDetails.partList;
1171
- let frag: Fragment | null = null;
1059
+ let frag;
1172
1060
 
1173
1061
  if (levelDetails.live) {
1174
1062
  const initialLiveManifestSize = config.initialLiveManifestSize;
@@ -1188,10 +1076,6 @@ export default class BaseStreamController
1188
1076
  this.startPosition === -1) ||
1189
1077
  pos < start
1190
1078
  ) {
1191
- if (canLoadParts && !this.loadingParts) {
1192
- this.log(`LL-Part loading ON for initial live fragment`);
1193
- this.loadingParts = true;
1194
- }
1195
1079
  frag = this.getInitialLiveFragment(levelDetails, fragments);
1196
1080
  this.startPosition = this.nextLoadPosition = frag
1197
1081
  ? this.hls.liveSyncPosition || frag.start
@@ -1204,7 +1088,7 @@ export default class BaseStreamController
1204
1088
 
1205
1089
  // If we haven't run into any special cases already, just load the fragment most closely matching the requested position
1206
1090
  if (!frag) {
1207
- const end = this.loadingParts
1091
+ const end = config.lowLatencyMode
1208
1092
  ? levelDetails.partEnd
1209
1093
  : levelDetails.fragmentEnd;
1210
1094
  frag = this.getFragmentAtPosition(pos, end, levelDetails);
@@ -1387,7 +1271,7 @@ export default class BaseStreamController
1387
1271
  const partList = levelDetails.partList;
1388
1272
 
1389
1273
  const loadingParts = !!(
1390
- this.loadingParts &&
1274
+ config.lowLatencyMode &&
1391
1275
  partList?.length &&
1392
1276
  fragmentHint
1393
1277
  );
@@ -1666,7 +1550,7 @@ export default class BaseStreamController
1666
1550
  errorAction.resolved = true;
1667
1551
  }
1668
1552
  } else {
1669
- this.warn(
1553
+ logger.warn(
1670
1554
  `${data.details} reached or exceeded max retry (${retryCount})`,
1671
1555
  );
1672
1556
  return;
@@ -1,5 +1,5 @@
1
1
  import { Events } from '../events';
2
- import { Logger } from '../utils/logger';
2
+ import { logger } from '../utils/logger';
3
3
  import { ErrorDetails, ErrorTypes } from '../errors';
4
4
  import { BufferHelper } from '../utils/buffer-helper';
5
5
  import {
@@ -42,7 +42,7 @@ interface BufferedChangeEvent extends Event {
42
42
  readonly removedRanges?: TimeRanges;
43
43
  }
44
44
 
45
- export default class BufferController extends Logger implements ComponentAPI {
45
+ export default class BufferController implements ComponentAPI {
46
46
  // The level details used to determine duration, target-duration and live
47
47
  private details: LevelDetails | null = null;
48
48
  // cache the self generated object url to detect hijack of video tag
@@ -82,10 +82,17 @@ export default class BufferController extends Logger implements ComponentAPI {
82
82
  public pendingTracks: TrackSet = {};
83
83
  public sourceBuffer!: SourceBuffers;
84
84
 
85
+ protected log: (msg: any) => void;
86
+ protected warn: (msg: any, obj?: any) => void;
87
+ protected error: (msg: any, obj?: any) => void;
88
+
85
89
  constructor(hls: Hls) {
86
- super('buffer-controller', hls.logger);
87
90
  this.hls = hls;
91
+ const logPrefix = '[buffer-controller]';
88
92
  this.appendSource = hls.config.preferManagedMediaSource;
93
+ this.log = logger.log.bind(logger, logPrefix);
94
+ this.warn = logger.warn.bind(logger, logPrefix);
95
+ this.error = logger.error.bind(logger, logPrefix);
89
96
  this._initSourceBuffer();
90
97
  this.registerListeners();
91
98
  }
@@ -103,12 +110,6 @@ export default class BufferController extends Logger implements ComponentAPI {
103
110
  this.lastMpegAudioChunk = null;
104
111
  // @ts-ignore
105
112
  this.hls = null;
106
- // @ts-ignore
107
- this._onMediaSourceOpen = this._onMediaSourceClose = null;
108
- // @ts-ignore
109
- this._onMediaSourceEnded = null;
110
- // @ts-ignore
111
- this._onStartStreaming = this._onEndStreaming = null;
112
113
  }
113
114
 
114
115
  protected registerListeners() {
@@ -295,7 +296,6 @@ export default class BufferController extends Logger implements ComponentAPI {
295
296
  this.resetBuffer(type);
296
297
  });
297
298
  this._initSourceBuffer();
298
- this.hls.resumeBuffering();
299
299
  }
300
300
 
301
301
  private resetBuffer(type: SourceBufferName) {
@@ -1004,7 +1004,7 @@ export default class BufferController extends Logger implements ComponentAPI {
1004
1004
  private _onMediaEmptied = () => {
1005
1005
  const { mediaSrc, _objectUrl } = this;
1006
1006
  if (mediaSrc !== _objectUrl) {
1007
- this.error(
1007
+ logger.error(
1008
1008
  `Media element src was set while attaching MediaSource (${_objectUrl} > ${mediaSrc})`,
1009
1009
  );
1010
1010
  }
@@ -12,6 +12,7 @@ import type {
12
12
  LevelsUpdatedData,
13
13
  } from '../types/events';
14
14
  import StreamController from './stream-controller';
15
+ import { logger } from '../utils/logger';
15
16
  import type { ComponentAPI } from '../types/component-api';
16
17
  import type Hls from '../hls';
17
18
 
@@ -151,7 +152,7 @@ class CapLevelController implements ComponentAPI {
151
152
  const hls = this.hls;
152
153
  const maxLevel = this.getMaxLevel(levels.length - 1);
153
154
  if (maxLevel !== this.autoLevelCapping) {
154
- hls.logger.log(
155
+ logger.log(
155
156
  `Setting autoLevelCapping to ${maxLevel}: ${levels[maxLevel].height}p@${levels[maxLevel].bitrate} for media ${this.mediaWidth}x${this.mediaHeight}`,
156
157
  );
157
158
  }
@@ -5,9 +5,9 @@ import { CmcdObjectType } from '@svta/common-media-library/cmcd/CmcdObjectType';
5
5
  import { CmcdStreamingFormat } from '@svta/common-media-library/cmcd/CmcdStreamingFormat';
6
6
  import { appendCmcdHeaders } from '@svta/common-media-library/cmcd/appendCmcdHeaders';
7
7
  import { appendCmcdQuery } from '@svta/common-media-library/cmcd/appendCmcdQuery';
8
- import type { CmcdEncodeOptions } from '@svta/common-media-library/cmcd/CmcdEncodeOptions';
9
8
  import { uuid } from '@svta/common-media-library/utils/uuid';
10
9
  import { BufferHelper } from '../utils/buffer-helper';
10
+ import { logger } from '../utils/logger';
11
11
  import type { ComponentAPI } from '../types/component-api';
12
12
  import type { Fragment } from '../loader/fragment';
13
13
  import type { BufferCreatedData, MediaAttachedData } from '../types/events';
@@ -165,7 +165,7 @@ export default class CMCDController implements ComponentAPI {
165
165
  data.su = this.buffering;
166
166
  }
167
167
 
168
- // TODO: Implement rtp, nrr, dl
168
+ // TODO: Implement rtp, nrr, nor, dl
169
169
 
170
170
  const { includeKeys } = this;
171
171
  if (includeKeys) {
@@ -175,18 +175,14 @@ export default class CMCDController implements ComponentAPI {
175
175
  }, {});
176
176
  }
177
177
 
178
- const options: CmcdEncodeOptions = {
179
- baseUrl: context.url,
180
- };
181
-
182
178
  if (this.useHeaders) {
183
179
  if (!context.headers) {
184
180
  context.headers = {};
185
181
  }
186
182
 
187
- appendCmcdHeaders(context.headers, data, options);
183
+ appendCmcdHeaders(context.headers, data);
188
184
  } else {
189
- context.url = appendCmcdQuery(context.url, data, options);
185
+ context.url = appendCmcdQuery(context.url, data);
190
186
  }
191
187
  }
192
188
 
@@ -200,7 +196,7 @@ export default class CMCDController implements ComponentAPI {
200
196
  su: !this.initialized,
201
197
  });
202
198
  } catch (error) {
203
- this.hls.logger.warn('Could not generate manifest CMCD data.', error);
199
+ logger.warn('Could not generate manifest CMCD data.', error);
204
200
  }
205
201
  };
206
202
 
@@ -227,29 +223,12 @@ export default class CMCDController implements ComponentAPI {
227
223
  data.bl = this.getBufferLength(ot);
228
224
  }
229
225
 
230
- const next = this.getNextFrag(fragment);
231
- if (next) {
232
- if (next.url && next.url !== fragment.url) {
233
- data.nor = next.url;
234
- }
235
- }
236
-
237
226
  this.apply(context, data);
238
227
  } catch (error) {
239
- this.hls.logger.warn('Could not generate segment CMCD data.', error);
228
+ logger.warn('Could not generate segment CMCD data.', error);
240
229
  }
241
230
  };
242
231
 
243
- private getNextFrag(fragment: Fragment): Fragment | undefined {
244
- const levelDetails = this.hls.levels[fragment.level]?.details;
245
- if (levelDetails) {
246
- const index = (fragment.sn as number) - levelDetails.startSN;
247
- return levelDetails.fragments[index + 1];
248
- }
249
-
250
- return undefined;
251
- }
252
-
253
232
  /**
254
233
  * The CMCD object type.
255
234
  */
@@ -3,7 +3,7 @@ import { Level } from '../types/level';
3
3
  import { reassignFragmentLevelIndexes } from '../utils/level-helper';
4
4
  import { AttrList } from '../utils/attr-list';
5
5
  import { ErrorActionFlags, NetworkErrorAction } from './error-controller';
6
- import { Logger } from '../utils/logger';
6
+ import { logger } from '../utils/logger';
7
7
  import {
8
8
  PlaylistContextType,
9
9
  type Loader,
@@ -48,11 +48,9 @@ export type UriReplacement = {
48
48
 
49
49
  const PATHWAY_PENALTY_DURATION_MS = 300000;
50
50
 
51
- export default class ContentSteeringController
52
- extends Logger
53
- implements NetworkComponentAPI
54
- {
51
+ export default class ContentSteeringController implements NetworkComponentAPI {
55
52
  private readonly hls: Hls;
53
+ private log: (msg: any) => void;
56
54
  private loader: Loader<LoaderContext> | null = null;
57
55
  private uri: string | null = null;
58
56
  private pathwayId: string = '.';
@@ -68,8 +66,8 @@ export default class ContentSteeringController
68
66
  private penalizedPathways: { [pathwayId: string]: number } = {};
69
67
 
70
68
  constructor(hls: Hls) {
71
- super('content-steering', hls.logger);
72
69
  this.hls = hls;
70
+ this.log = logger.log.bind(logger, `[content-steering]:`);
73
71
  this.registerListeners();
74
72
  }
75
73
 
@@ -205,7 +203,7 @@ export default class ContentSteeringController
205
203
  errorAction.resolved = this.pathwayId !== errorPathway;
206
204
  }
207
205
  if (!errorAction.resolved) {
208
- this.warn(
206
+ logger.warn(
209
207
  `Could not resolve ${data.details} ("${
210
208
  data.error.message
211
209
  }") with content-steering for Pathway: ${errorPathway} levels: ${
@@ -444,7 +442,7 @@ export default class ContentSteeringController
444
442
  ) => {
445
443
  this.log(`Loaded steering manifest: "${url}"`);
446
444
  const steeringData = response.data as SteeringManifest;
447
- if (steeringData?.VERSION !== 1) {
445
+ if (steeringData.VERSION !== 1) {
448
446
  this.log(`Steering VERSION ${steeringData.VERSION} not supported!`);
449
447
  return;
450
448
  }
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { Events } from '../events';
7
7
  import { ErrorTypes, ErrorDetails } from '../errors';
8
- import { Logger } from '../utils/logger';
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 extends Logger implements ComponentAPI {
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 = this.config = this.keyIdToKeySessionPromise = null;
116
+ this.hls =
117
+ this.onMediaEncrypted =
118
+ this.onWaitingForKey =
119
+ this.keyIdToKeySessionPromise =
120
+ null as any;
108
121
  // @ts-ignore
109
- this.onMediaEncrypted = this.onWaitingForKey = null;
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 onMediaEncrypted = (event: MediaEncryptedEvent) => {
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 onWaitingForKey = (event: Event) => {
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 { Logger } from '../utils/logger';
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