hls.js 1.5.6 → 1.5.7-0.canary.10015

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 (69) hide show
  1. package/README.md +1 -0
  2. package/dist/hls-demo.js +10 -0
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +2077 -1166
  5. package/dist/hls.js.d.ts +65 -50
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +1149 -858
  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 +985 -695
  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 +1758 -862
  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 +3 -2
  21. package/src/controller/abr-controller.ts +21 -20
  22. package/src/controller/audio-stream-controller.ts +15 -16
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +20 -8
  25. package/src/controller/base-stream-controller.ts +149 -33
  26. package/src/controller/buffer-controller.ts +11 -11
  27. package/src/controller/cap-level-controller.ts +1 -2
  28. package/src/controller/cmcd-controller.ts +27 -6
  29. package/src/controller/content-steering-controller.ts +8 -6
  30. package/src/controller/eme-controller.ts +9 -22
  31. package/src/controller/error-controller.ts +6 -8
  32. package/src/controller/fps-controller.ts +2 -3
  33. package/src/controller/gap-controller.ts +43 -16
  34. package/src/controller/latency-controller.ts +9 -11
  35. package/src/controller/level-controller.ts +12 -18
  36. package/src/controller/stream-controller.ts +24 -31
  37. package/src/controller/subtitle-stream-controller.ts +13 -14
  38. package/src/controller/subtitle-track-controller.ts +5 -3
  39. package/src/controller/timeline-controller.ts +23 -30
  40. package/src/crypt/aes-crypto.ts +21 -2
  41. package/src/crypt/decrypter-aes-mode.ts +4 -0
  42. package/src/crypt/decrypter.ts +32 -18
  43. package/src/crypt/fast-aes-key.ts +24 -5
  44. package/src/demux/audio/adts.ts +9 -4
  45. package/src/demux/sample-aes.ts +2 -0
  46. package/src/demux/transmuxer-interface.ts +4 -12
  47. package/src/demux/transmuxer-worker.ts +4 -4
  48. package/src/demux/transmuxer.ts +16 -3
  49. package/src/demux/tsdemuxer.ts +71 -37
  50. package/src/demux/video/avc-video-parser.ts +208 -119
  51. package/src/demux/video/base-video-parser.ts +134 -2
  52. package/src/demux/video/exp-golomb.ts +0 -208
  53. package/src/demux/video/hevc-video-parser.ts +746 -0
  54. package/src/events.ts +7 -0
  55. package/src/hls.ts +42 -34
  56. package/src/loader/fragment-loader.ts +9 -2
  57. package/src/loader/key-loader.ts +2 -0
  58. package/src/loader/level-key.ts +10 -9
  59. package/src/loader/playlist-loader.ts +4 -5
  60. package/src/remux/mp4-generator.ts +196 -1
  61. package/src/remux/mp4-remuxer.ts +23 -7
  62. package/src/task-loop.ts +5 -2
  63. package/src/types/component-api.ts +2 -0
  64. package/src/types/demuxer.ts +3 -0
  65. package/src/types/events.ts +4 -0
  66. package/src/utils/codecs.ts +33 -4
  67. package/src/utils/encryption-methods-util.ts +21 -0
  68. package/src/utils/logger.ts +54 -24
  69. package/src/utils/mp4-tools.ts +3 -1
package/src/task-loop.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { type ILogger, Logger } from './utils/logger';
2
+
1
3
  /**
2
4
  * @ignore
3
5
  * Sub-class specialization of EventHandler base class.
@@ -27,13 +29,14 @@
27
29
  * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
28
30
  * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
29
31
  */
30
- export default class TaskLoop {
32
+ export default class TaskLoop extends Logger {
31
33
  private readonly _boundTick: () => void;
32
34
  private _tickTimer: number | null = null;
33
35
  private _tickInterval: number | null = null;
34
36
  private _tickCallCount = 0;
35
37
 
36
- constructor() {
38
+ constructor(label: string, logger: ILogger) {
39
+ super(label, logger);
37
40
  this._boundTick = this.tick.bind(this);
38
41
  }
39
42
 
@@ -15,4 +15,6 @@ export interface AbrComponentAPI extends ComponentAPI {
15
15
  export interface NetworkComponentAPI extends ComponentAPI {
16
16
  startLoad(startPosition: number): void;
17
17
  stopLoad(): void;
18
+ pauseBuffering?(): void;
19
+ resumeBuffering?(): void;
18
20
  }
@@ -64,6 +64,7 @@ export interface DemuxedAudioTrack extends DemuxedTrack {
64
64
  segmentCodec?: string;
65
65
  channelCount?: number;
66
66
  manifestCodec?: string;
67
+ parsedCodec?: string;
67
68
  samples: AudioSample[];
68
69
  }
69
70
 
@@ -72,12 +73,14 @@ export interface DemuxedVideoTrackBase extends DemuxedTrack {
72
73
  height?: number;
73
74
  pixelRatio?: [number, number];
74
75
  audFound?: boolean;
76
+ vps?: Uint8Array[];
75
77
  pps?: Uint8Array[];
76
78
  sps?: Uint8Array[];
77
79
  naluState?: number;
78
80
  segmentCodec?: string;
79
81
  manifestCodec?: string;
80
82
  samples: VideoSample[] | Uint8Array;
83
+ params?: object;
81
84
  }
82
85
 
83
86
  export interface DemuxedVideoTrack extends DemuxedVideoTrackBase {
@@ -42,6 +42,10 @@ export interface MediaAttachedData {
42
42
  mediaSource?: MediaSource;
43
43
  }
44
44
 
45
+ export interface MediaEndedData {
46
+ stalled: boolean;
47
+ }
48
+
45
49
  export interface BufferCodecsData {
46
50
  video?: Track;
47
51
  audio?: Track;
@@ -147,12 +147,15 @@ function getCodecCompatibleNameLower(
147
147
  return CODEC_COMPATIBLE_NAMES[lowerCaseCodec]!;
148
148
  }
149
149
 
150
- // Idealy fLaC and Opus would be first (spec-compliant) but
151
- // some browsers will report that fLaC is supported then fail.
152
- // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
153
150
  const codecsToCheck = {
151
+ // Idealy fLaC and Opus would be first (spec-compliant) but
152
+ // some browsers will report that fLaC is supported then fail.
153
+ // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
154
154
  flac: ['flac', 'fLaC', 'FLAC'],
155
155
  opus: ['opus', 'Opus'],
156
+ // Replace audio codec info if browser does not support mp4a.40.34,
157
+ // and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
158
+ 'mp4a.40.34': ['mp3'],
156
159
  }[lowerCaseCodec];
157
160
 
158
161
  for (let i = 0; i < codecsToCheck.length; i++) {
@@ -165,13 +168,18 @@ function getCodecCompatibleNameLower(
165
168
  ) {
166
169
  CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
167
170
  return codecsToCheck[i];
171
+ } else if (
172
+ codecsToCheck[i] === 'mp3' &&
173
+ getMediaSource(preferManagedMediaSource)?.isTypeSupported('audio/mpeg')
174
+ ) {
175
+ return '';
168
176
  }
169
177
  }
170
178
 
171
179
  return lowerCaseCodec;
172
180
  }
173
181
 
174
- const AUDIO_CODEC_REGEXP = /flac|opus/i;
182
+ const AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
175
183
  export function getCodecCompatibleName(
176
184
  codec: string,
177
185
  preferManagedMediaSource = true,
@@ -209,3 +217,24 @@ export function convertAVC1ToAVCOTI(codec: string) {
209
217
  }
210
218
  return codec;
211
219
  }
220
+
221
+ export interface TypeSupported {
222
+ mpeg: boolean;
223
+ mp3: boolean;
224
+ ac3: boolean;
225
+ }
226
+
227
+ export function getM2TSSupportedAudioTypes(
228
+ preferManagedMediaSource: boolean,
229
+ ): TypeSupported {
230
+ const MediaSource = getMediaSource(preferManagedMediaSource) || {
231
+ isTypeSupported: () => false,
232
+ };
233
+ return {
234
+ mpeg: MediaSource.isTypeSupported('audio/mpeg'),
235
+ mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
236
+ ac3: __USE_M2TS_ADVANCED_CODECS__
237
+ ? MediaSource.isTypeSupported('audio/mp4; codecs="ac-3"')
238
+ : false,
239
+ };
240
+ }
@@ -0,0 +1,21 @@
1
+ import { DecrypterAesMode } from '../crypt/decrypter-aes-mode';
2
+
3
+ export function isFullSegmentEncryption(method: string): boolean {
4
+ return (
5
+ method === 'AES-128' || method === 'AES-256' || method === 'AES-256-CTR'
6
+ );
7
+ }
8
+
9
+ export function getAesModeFromFullSegmentMethod(
10
+ method: string,
11
+ ): DecrypterAesMode {
12
+ switch (method) {
13
+ case 'AES-128':
14
+ case 'AES-256':
15
+ return DecrypterAesMode.cbc;
16
+ case 'AES-256-CTR':
17
+ return DecrypterAesMode.ctr;
18
+ default:
19
+ throw new Error(`invalid full segment method ${method}`);
20
+ }
21
+ }
@@ -11,6 +11,25 @@ export interface ILogger {
11
11
  error: ILogFunction;
12
12
  }
13
13
 
14
+ export class Logger implements ILogger {
15
+ trace: ILogFunction;
16
+ debug: ILogFunction;
17
+ log: ILogFunction;
18
+ warn: ILogFunction;
19
+ info: ILogFunction;
20
+ error: ILogFunction;
21
+
22
+ constructor(label: string, logger: ILogger) {
23
+ const lb = `[${label}]:`;
24
+ this.trace = noop;
25
+ this.debug = logger.debug.bind(null, lb);
26
+ this.log = logger.log.bind(null, lb);
27
+ this.warn = logger.warn.bind(null, lb);
28
+ this.info = logger.info.bind(null, lb);
29
+ this.error = logger.error.bind(null, lb);
30
+ }
31
+ }
32
+
14
33
  const noop: ILogFunction = function () {};
15
34
 
16
35
  const fakeLogger: ILogger = {
@@ -22,7 +41,9 @@ const fakeLogger: ILogger = {
22
41
  error: noop,
23
42
  };
24
43
 
25
- let exportedLogger: ILogger = fakeLogger;
44
+ function createLogger() {
45
+ return Object.assign({}, fakeLogger);
46
+ }
26
47
 
27
48
  // let lastCallTime;
28
49
  // function formatMsgWithTimeInfo(type, msg) {
@@ -33,33 +54,37 @@ let exportedLogger: ILogger = fakeLogger;
33
54
  // return msg;
34
55
  // }
35
56
 
36
- function consolePrintFn(type: string): ILogFunction {
57
+ function consolePrintFn(type: string, id: string | undefined): ILogFunction {
37
58
  const func: ILogFunction = self.console[type];
38
- if (func) {
39
- return func.bind(self.console, `[${type}] >`);
40
- }
41
- return noop;
59
+ return func
60
+ ? func.bind(self.console, `${id ? '[' + id + '] ' : ''}[${type}] >`)
61
+ : noop;
42
62
  }
43
63
 
44
- function exportLoggerFunctions(
45
- debugConfig: boolean | ILogger,
46
- ...functions: string[]
47
- ): void {
48
- functions.forEach(function (type) {
49
- exportedLogger[type] = debugConfig[type]
50
- ? debugConfig[type].bind(debugConfig)
51
- : consolePrintFn(type);
52
- });
64
+ function getLoggerFn(
65
+ key: string,
66
+ debugConfig: boolean | Partial<ILogger>,
67
+ id: string | undefined,
68
+ ): ILogFunction {
69
+ return debugConfig[key]
70
+ ? debugConfig[key].bind(debugConfig)
71
+ : consolePrintFn(key, id);
53
72
  }
54
73
 
55
- export function enableLogs(debugConfig: boolean | ILogger, id: string): void {
74
+ const exportedLogger: ILogger = createLogger();
75
+
76
+ export function enableLogs(
77
+ debugConfig: boolean | ILogger,
78
+ context: string,
79
+ id?: string | undefined,
80
+ ): ILogger {
56
81
  // check that console is available
82
+ const newLogger = createLogger();
57
83
  if (
58
84
  (typeof console === 'object' && debugConfig === true) ||
59
85
  typeof debugConfig === 'object'
60
86
  ) {
61
- exportLoggerFunctions(
62
- debugConfig,
87
+ const keys: (keyof ILogger)[] = [
63
88
  // Remove out from list here to hard-disable a log-level
64
89
  // 'trace',
65
90
  'debug',
@@ -67,19 +92,24 @@ export function enableLogs(debugConfig: boolean | ILogger, id: string): void {
67
92
  'info',
68
93
  'warn',
69
94
  'error',
70
- );
95
+ ];
96
+ keys.forEach((key) => {
97
+ newLogger[key] = getLoggerFn(key, debugConfig, id);
98
+ });
71
99
  // Some browsers don't allow to use bind on console object anyway
72
100
  // fallback to default if needed
73
101
  try {
74
- exportedLogger.log(
75
- `Debug logs enabled for "${id}" in hls.js version ${__VERSION__}`,
102
+ newLogger.log(
103
+ `Debug logs enabled for "${context}" in hls.js version ${__VERSION__}`,
76
104
  );
77
105
  } catch (e) {
78
- exportedLogger = fakeLogger;
106
+ /* log fn threw an exception. All logger methods are no-ops. */
107
+ return createLogger();
79
108
  }
80
- } else {
81
- exportedLogger = fakeLogger;
82
109
  }
110
+ // global exported logger uses the log methods from last call to `enableLogs`
111
+ Object.assign(exportedLogger, newLogger);
112
+ return newLogger;
83
113
  }
84
114
 
85
115
  export const logger: ILogger = exportedLogger;
@@ -478,7 +478,9 @@ function parseStsd(stsd: Uint8Array): { codec: string; encrypted: boolean } {
478
478
 
479
479
  function skipBERInteger(bytes: Uint8Array, i: number): number {
480
480
  const limit = i + 5;
481
- while (bytes[i++] & 0x80 && i < limit) {}
481
+ while (bytes[i++] & 0x80 && i < limit) {
482
+ /* do nothing */
483
+ }
482
484
  return i;
483
485
  }
484
486