@zenvor/hls.js 1.0.0

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 (159) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +472 -0
  3. package/dist/hls-demo.js +26995 -0
  4. package/dist/hls-demo.js.map +1 -0
  5. package/dist/hls.d.mts +4204 -0
  6. package/dist/hls.d.ts +4204 -0
  7. package/dist/hls.js +40050 -0
  8. package/dist/hls.js.d.ts +4204 -0
  9. package/dist/hls.js.map +1 -0
  10. package/dist/hls.light.js +27145 -0
  11. package/dist/hls.light.js.map +1 -0
  12. package/dist/hls.light.min.js +2 -0
  13. package/dist/hls.light.min.js.map +1 -0
  14. package/dist/hls.light.mjs +26392 -0
  15. package/dist/hls.light.mjs.map +1 -0
  16. package/dist/hls.min.js +2 -0
  17. package/dist/hls.min.js.map +1 -0
  18. package/dist/hls.mjs +38956 -0
  19. package/dist/hls.mjs.map +1 -0
  20. package/dist/hls.worker.js +2 -0
  21. package/dist/hls.worker.js.map +1 -0
  22. package/package.json +143 -0
  23. package/src/config.ts +794 -0
  24. package/src/controller/abr-controller.ts +1019 -0
  25. package/src/controller/algo-data-controller.ts +794 -0
  26. package/src/controller/audio-stream-controller.ts +1099 -0
  27. package/src/controller/audio-track-controller.ts +454 -0
  28. package/src/controller/base-playlist-controller.ts +438 -0
  29. package/src/controller/base-stream-controller.ts +2526 -0
  30. package/src/controller/buffer-controller.ts +2015 -0
  31. package/src/controller/buffer-operation-queue.ts +159 -0
  32. package/src/controller/cap-level-controller.ts +367 -0
  33. package/src/controller/cmcd-controller.ts +422 -0
  34. package/src/controller/content-steering-controller.ts +622 -0
  35. package/src/controller/eme-controller.ts +1617 -0
  36. package/src/controller/error-controller.ts +627 -0
  37. package/src/controller/fps-controller.ts +146 -0
  38. package/src/controller/fragment-finders.ts +256 -0
  39. package/src/controller/fragment-tracker.ts +567 -0
  40. package/src/controller/gap-controller.ts +719 -0
  41. package/src/controller/id3-track-controller.ts +488 -0
  42. package/src/controller/interstitial-player.ts +302 -0
  43. package/src/controller/interstitials-controller.ts +2895 -0
  44. package/src/controller/interstitials-schedule.ts +698 -0
  45. package/src/controller/latency-controller.ts +294 -0
  46. package/src/controller/level-controller.ts +776 -0
  47. package/src/controller/stream-controller.ts +1597 -0
  48. package/src/controller/subtitle-stream-controller.ts +508 -0
  49. package/src/controller/subtitle-track-controller.ts +617 -0
  50. package/src/controller/timeline-controller.ts +677 -0
  51. package/src/crypt/aes-crypto.ts +36 -0
  52. package/src/crypt/aes-decryptor.ts +339 -0
  53. package/src/crypt/decrypter-aes-mode.ts +4 -0
  54. package/src/crypt/decrypter.ts +225 -0
  55. package/src/crypt/fast-aes-key.ts +39 -0
  56. package/src/define-plugin.d.ts +17 -0
  57. package/src/demux/audio/aacdemuxer.ts +126 -0
  58. package/src/demux/audio/ac3-demuxer.ts +170 -0
  59. package/src/demux/audio/adts.ts +249 -0
  60. package/src/demux/audio/base-audio-demuxer.ts +205 -0
  61. package/src/demux/audio/dolby.ts +21 -0
  62. package/src/demux/audio/mp3demuxer.ts +85 -0
  63. package/src/demux/audio/mpegaudio.ts +177 -0
  64. package/src/demux/chunk-cache.ts +42 -0
  65. package/src/demux/dummy-demuxed-track.ts +13 -0
  66. package/src/demux/inject-worker.ts +75 -0
  67. package/src/demux/mp4demuxer.ts +234 -0
  68. package/src/demux/sample-aes.ts +198 -0
  69. package/src/demux/transmuxer-interface.ts +449 -0
  70. package/src/demux/transmuxer-worker.ts +221 -0
  71. package/src/demux/transmuxer.ts +560 -0
  72. package/src/demux/tsdemuxer.ts +1256 -0
  73. package/src/demux/video/avc-video-parser.ts +401 -0
  74. package/src/demux/video/base-video-parser.ts +198 -0
  75. package/src/demux/video/exp-golomb.ts +153 -0
  76. package/src/demux/video/hevc-video-parser.ts +736 -0
  77. package/src/empty-es.js +5 -0
  78. package/src/empty.js +3 -0
  79. package/src/errors.ts +107 -0
  80. package/src/events.ts +548 -0
  81. package/src/exports-default.ts +3 -0
  82. package/src/exports-named.ts +81 -0
  83. package/src/hls.ts +1613 -0
  84. package/src/is-supported.ts +54 -0
  85. package/src/loader/date-range.ts +207 -0
  86. package/src/loader/fragment-loader.ts +403 -0
  87. package/src/loader/fragment.ts +487 -0
  88. package/src/loader/interstitial-asset-list.ts +162 -0
  89. package/src/loader/interstitial-event.ts +337 -0
  90. package/src/loader/key-loader.ts +439 -0
  91. package/src/loader/level-details.ts +203 -0
  92. package/src/loader/level-key.ts +259 -0
  93. package/src/loader/load-stats.ts +17 -0
  94. package/src/loader/m3u8-parser.ts +1072 -0
  95. package/src/loader/playlist-loader.ts +839 -0
  96. package/src/polyfills/number.ts +15 -0
  97. package/src/remux/aac-helper.ts +81 -0
  98. package/src/remux/mp4-generator.ts +1380 -0
  99. package/src/remux/mp4-remuxer.ts +1261 -0
  100. package/src/remux/passthrough-remuxer.ts +434 -0
  101. package/src/task-loop.ts +130 -0
  102. package/src/types/algo.ts +44 -0
  103. package/src/types/buffer.ts +105 -0
  104. package/src/types/component-api.ts +20 -0
  105. package/src/types/demuxer.ts +208 -0
  106. package/src/types/events.ts +574 -0
  107. package/src/types/fragment-tracker.ts +23 -0
  108. package/src/types/level.ts +268 -0
  109. package/src/types/loader.ts +198 -0
  110. package/src/types/media-playlist.ts +92 -0
  111. package/src/types/network-details.ts +3 -0
  112. package/src/types/remuxer.ts +104 -0
  113. package/src/types/track.ts +12 -0
  114. package/src/types/transmuxer.ts +46 -0
  115. package/src/types/tuples.ts +6 -0
  116. package/src/types/vtt.ts +11 -0
  117. package/src/utils/arrays.ts +22 -0
  118. package/src/utils/attr-list.ts +192 -0
  119. package/src/utils/binary-search.ts +46 -0
  120. package/src/utils/buffer-helper.ts +173 -0
  121. package/src/utils/cea-608-parser.ts +1413 -0
  122. package/src/utils/chunker.ts +41 -0
  123. package/src/utils/codecs.ts +314 -0
  124. package/src/utils/cues.ts +96 -0
  125. package/src/utils/discontinuities.ts +174 -0
  126. package/src/utils/encryption-methods-util.ts +21 -0
  127. package/src/utils/error-helper.ts +95 -0
  128. package/src/utils/event-listener-helper.ts +16 -0
  129. package/src/utils/ewma-bandwidth-estimator.ts +97 -0
  130. package/src/utils/ewma.ts +43 -0
  131. package/src/utils/fetch-loader.ts +331 -0
  132. package/src/utils/global.ts +2 -0
  133. package/src/utils/hash.ts +10 -0
  134. package/src/utils/hdr.ts +67 -0
  135. package/src/utils/hex.ts +32 -0
  136. package/src/utils/imsc1-ttml-parser.ts +261 -0
  137. package/src/utils/keysystem-util.ts +45 -0
  138. package/src/utils/level-helper.ts +629 -0
  139. package/src/utils/logger.ts +120 -0
  140. package/src/utils/media-option-attributes.ts +49 -0
  141. package/src/utils/mediacapabilities-helper.ts +301 -0
  142. package/src/utils/mediakeys-helper.ts +210 -0
  143. package/src/utils/mediasource-helper.ts +37 -0
  144. package/src/utils/mp4-tools.ts +1473 -0
  145. package/src/utils/number.ts +3 -0
  146. package/src/utils/numeric-encoding-utils.ts +26 -0
  147. package/src/utils/output-filter.ts +46 -0
  148. package/src/utils/rendition-helper.ts +505 -0
  149. package/src/utils/safe-json-stringify.ts +22 -0
  150. package/src/utils/texttrack-utils.ts +164 -0
  151. package/src/utils/time-ranges.ts +17 -0
  152. package/src/utils/timescale-conversion.ts +46 -0
  153. package/src/utils/utf8-utils.ts +18 -0
  154. package/src/utils/variable-substitution.ts +105 -0
  155. package/src/utils/vttcue.ts +384 -0
  156. package/src/utils/vttparser.ts +497 -0
  157. package/src/utils/webvtt-parser.ts +166 -0
  158. package/src/utils/xhr-loader.ts +337 -0
  159. package/src/version.ts +1 -0
package/src/config.ts ADDED
@@ -0,0 +1,794 @@
1
+ import AbrController from './controller/abr-controller';
2
+ import AudioStreamController from './controller/audio-stream-controller';
3
+ import AudioTrackController from './controller/audio-track-controller';
4
+ import BufferController from './controller/buffer-controller';
5
+ import CapLevelController from './controller/cap-level-controller';
6
+ import CMCDController from './controller/cmcd-controller';
7
+ import ContentSteeringController from './controller/content-steering-controller';
8
+ import EMEController from './controller/eme-controller';
9
+ import ErrorController from './controller/error-controller';
10
+ import FPSController from './controller/fps-controller';
11
+ import InterstitialsController from './controller/interstitials-controller';
12
+ import { SubtitleStreamController } from './controller/subtitle-stream-controller';
13
+ import SubtitleTrackController from './controller/subtitle-track-controller';
14
+ import { TimelineController } from './controller/timeline-controller';
15
+ import Cues from './utils/cues';
16
+ import FetchLoader, { fetchSupported } from './utils/fetch-loader';
17
+ import { requestMediaKeySystemAccess } from './utils/mediakeys-helper';
18
+ import { clamp } from './utils/number';
19
+ import { stringify } from './utils/safe-json-stringify';
20
+ import XhrLoader from './utils/xhr-loader';
21
+ import type { MediaKeySessionContext } from './controller/eme-controller';
22
+ import type Hls from './hls';
23
+ import type {
24
+ FragmentLoaderContext,
25
+ Loader,
26
+ LoaderContext,
27
+ LoaderResponse,
28
+ PlaylistLoaderContext,
29
+ } from './types/loader';
30
+ import type {
31
+ AudioSelectionOption,
32
+ SubtitleSelectionOption,
33
+ VideoSelectionOption,
34
+ } from './types/media-playlist';
35
+ import type { CuesInterface } from './utils/cues';
36
+ import type { ILogger } from './utils/logger';
37
+ import type { KeySystems, MediaKeyFunc } from './utils/mediakeys-helper';
38
+
39
+ export type ABRControllerConfig = {
40
+ abrEwmaFastLive: number;
41
+ abrEwmaSlowLive: number;
42
+ abrEwmaFastVoD: number;
43
+ abrEwmaSlowVoD: number;
44
+ /**
45
+ * Default bandwidth estimate in bits/s prior to collecting fragment bandwidth samples
46
+ */
47
+ abrEwmaDefaultEstimate: number;
48
+ abrEwmaDefaultEstimateMax: number;
49
+ abrBandWidthFactor: number;
50
+ abrBandWidthUpFactor: number;
51
+ abrMaxWithRealBitrate: boolean;
52
+ abrSwitchInterval: number;
53
+ maxStarvationDelay: number;
54
+ maxLoadingDelay: number;
55
+ };
56
+
57
+ export type BufferControllerConfig = {
58
+ appendErrorMaxRetry: number;
59
+ appendTimeout: number;
60
+ backBufferLength: number;
61
+ frontBufferFlushThreshold: number;
62
+ liveDurationInfinity: boolean;
63
+ /**
64
+ * @deprecated use backBufferLength
65
+ */
66
+ liveBackBufferLength: number | null;
67
+ };
68
+
69
+ export type CapLevelControllerConfig = {
70
+ capLevelToPlayerSize: boolean;
71
+ };
72
+
73
+ export type CMCDControllerConfig = {
74
+ sessionId?: string;
75
+ contentId?: string;
76
+ useHeaders?: boolean;
77
+ includeKeys?: string[];
78
+ };
79
+
80
+ export type DRMSystemOptions = {
81
+ audioRobustness?: string;
82
+ videoRobustness?: string;
83
+ audioEncryptionScheme?: string | null;
84
+ videoEncryptionScheme?: string | null;
85
+ persistentState?: MediaKeysRequirement;
86
+ distinctiveIdentifier?: MediaKeysRequirement;
87
+ sessionTypes?: string[];
88
+ sessionType?: string;
89
+ };
90
+
91
+ export type DRMSystemConfiguration = {
92
+ licenseUrl: string;
93
+ serverCertificateUrl?: string;
94
+ generateRequest?: (
95
+ this: Hls,
96
+ initDataType: string,
97
+ initData: ArrayBuffer | null,
98
+ keyContext: MediaKeySessionContext,
99
+ ) =>
100
+ | { initDataType: string; initData: ArrayBuffer | null }
101
+ | undefined
102
+ | never;
103
+ };
104
+
105
+ export type DRMSystemsConfiguration = Partial<
106
+ Record<KeySystems, DRMSystemConfiguration>
107
+ >;
108
+
109
+ export type EMEControllerConfig = {
110
+ licenseXhrSetup?: (
111
+ this: Hls,
112
+ xhr: XMLHttpRequest,
113
+ url: string,
114
+ keyContext: MediaKeySessionContext,
115
+ licenseChallenge: Uint8Array,
116
+ ) => void | Uint8Array | Promise<Uint8Array | void>;
117
+ licenseResponseCallback?: (
118
+ this: Hls,
119
+ xhr: XMLHttpRequest,
120
+ url: string,
121
+ keyContext: MediaKeySessionContext,
122
+ ) => ArrayBuffer;
123
+ emeEnabled: boolean;
124
+ widevineLicenseUrl?: string;
125
+ drmSystems: DRMSystemsConfiguration | undefined;
126
+ drmSystemOptions: DRMSystemOptions | undefined;
127
+ requestMediaKeySystemAccessFunc: MediaKeyFunc | null;
128
+ requireKeySystemAccessOnStart: boolean;
129
+ };
130
+
131
+ export interface FragmentLoaderConstructor {
132
+ new (confg: HlsConfig): Loader<FragmentLoaderContext>;
133
+ }
134
+
135
+ /**
136
+ * @deprecated use fragLoadPolicy.default
137
+ */
138
+ export type FragmentLoaderConfig = {
139
+ fragLoadingTimeOut: number;
140
+ fragLoadingMaxRetry: number;
141
+ fragLoadingRetryDelay: number;
142
+ fragLoadingMaxRetryTimeout: number;
143
+ };
144
+
145
+ export type FPSControllerConfig = {
146
+ capLevelOnFPSDrop: boolean;
147
+ fpsDroppedMonitoringPeriod: number;
148
+ fpsDroppedMonitoringThreshold: number;
149
+ };
150
+
151
+ export type LevelControllerConfig = {
152
+ startLevel?: number;
153
+ };
154
+
155
+ export type MP4RemuxerConfig = {
156
+ stretchShortVideoTrack: boolean;
157
+ maxAudioFramesDrift: number;
158
+ };
159
+
160
+ export interface PlaylistLoaderConstructor {
161
+ new (confg: HlsConfig): Loader<PlaylistLoaderContext>;
162
+ }
163
+
164
+ /**
165
+ * @deprecated use manifestLoadPolicy.default and playlistLoadPolicy.default
166
+ */
167
+ export type PlaylistLoaderConfig = {
168
+ manifestLoadingTimeOut: number;
169
+ manifestLoadingMaxRetry: number;
170
+ manifestLoadingRetryDelay: number;
171
+ manifestLoadingMaxRetryTimeout: number;
172
+
173
+ levelLoadingTimeOut: number;
174
+ levelLoadingMaxRetry: number;
175
+ levelLoadingRetryDelay: number;
176
+ levelLoadingMaxRetryTimeout: number;
177
+ };
178
+
179
+ export type HlsLoadPolicies = {
180
+ fragLoadPolicy: LoadPolicy;
181
+ keyLoadPolicy: LoadPolicy;
182
+ certLoadPolicy: LoadPolicy;
183
+ playlistLoadPolicy: LoadPolicy;
184
+ manifestLoadPolicy: LoadPolicy;
185
+ steeringManifestLoadPolicy: LoadPolicy;
186
+ interstitialAssetListLoadPolicy: LoadPolicy;
187
+ };
188
+
189
+ export type LoadPolicy = {
190
+ default: LoaderConfig;
191
+ };
192
+
193
+ export type LoaderConfig = {
194
+ maxTimeToFirstByteMs: number; // Max time to first byte
195
+ maxLoadTimeMs: number; // Max time for load completion
196
+ timeoutRetry: RetryConfig | null;
197
+ errorRetry: RetryConfig | null;
198
+ };
199
+
200
+ export type RetryConfig = {
201
+ maxNumRetry: number; // Maximum number of retries
202
+ retryDelayMs: number; // Retry delay = 2^retryCount * retryDelayMs (exponential) or retryCount * retryDelayMs (linear)
203
+ maxRetryDelayMs: number; // Maximum delay between retries
204
+ backoff?: 'exponential' | 'linear'; // used to determine retry backoff duration (see retryDelayMs)
205
+ shouldRetry?: (
206
+ retryConfig: RetryConfig | null | undefined,
207
+ retryCount: number,
208
+ isTimeout: boolean,
209
+ loaderResponse: LoaderResponse | undefined,
210
+ retry: boolean,
211
+ ) => boolean;
212
+ };
213
+
214
+ export type StreamControllerConfig = {
215
+ autoStartLoad: boolean;
216
+ startPosition: number;
217
+ defaultAudioCodec?: string;
218
+ initialLiveManifestSize: number;
219
+ maxBufferLength: number;
220
+ maxBufferSize: number;
221
+ maxBufferHole: number;
222
+ maxFragLookUpTolerance: number;
223
+ maxMaxBufferLength: number;
224
+ startFragPrefetch: boolean;
225
+ testBandwidth: boolean;
226
+ liveSyncMode?: 'edge' | 'buffered';
227
+ startOnSegmentBoundary: boolean;
228
+ nextAudioTrackBufferFlushForwardOffset: number;
229
+ };
230
+
231
+ export type GapControllerConfig = {
232
+ detectStallWithCurrentTimeMs: number;
233
+ highBufferWatchdogPeriod: number;
234
+ nudgeOffset: number;
235
+ nudgeMaxRetry: number;
236
+ nudgeOnVideoHole: boolean;
237
+ skipBufferHolePadding: number;
238
+ };
239
+
240
+ export type SelectionPreferences = {
241
+ videoPreference?: VideoSelectionOption;
242
+ audioPreference?: AudioSelectionOption;
243
+ subtitlePreference?: SubtitleSelectionOption;
244
+ };
245
+
246
+ export type LatencyControllerConfig = {
247
+ liveSyncDurationCount: number;
248
+ liveMaxLatencyDurationCount: number;
249
+ liveSyncDuration?: number;
250
+ liveMaxLatencyDuration?: number;
251
+ maxLiveSyncPlaybackRate: number;
252
+ liveSyncOnStallIncrease: number;
253
+ };
254
+
255
+ export type PlaylistControllerConfig = {
256
+ liveMaxUnchangedPlaylistRefresh: number;
257
+ };
258
+
259
+ export type MetadataControllerConfig = {
260
+ enableDateRangeMetadataCues: boolean;
261
+ enableEmsgMetadataCues: boolean;
262
+ enableEmsgKLVMetadata: boolean;
263
+ enableID3MetadataCues: boolean;
264
+ emsgKLVSchemaUri?: string;
265
+ };
266
+
267
+ export type TimelineControllerConfig = {
268
+ cueHandler: CuesInterface;
269
+ enableWebVTT: boolean;
270
+ enableIMSC1: boolean;
271
+ enableCEA708Captions: boolean;
272
+ captionsTextTrack1Label: string;
273
+ captionsTextTrack1LanguageCode: string;
274
+ captionsTextTrack2Label: string;
275
+ captionsTextTrack2LanguageCode: string;
276
+ captionsTextTrack3Label: string;
277
+ captionsTextTrack3LanguageCode: string;
278
+ captionsTextTrack4Label: string;
279
+ captionsTextTrack4LanguageCode: string;
280
+ renderTextTracksNatively: boolean;
281
+ };
282
+
283
+ export type TSDemuxerConfig = {
284
+ forceKeyFrameOnDiscontinuity: boolean;
285
+ handleMpegTsVideoIntegrityErrors: 'process' | 'skip';
286
+ };
287
+
288
+ export type HlsConfig = {
289
+ debug: boolean | ILogger;
290
+ enableWorker: boolean;
291
+ workerPath: null | string;
292
+ enableSoftwareAES: boolean;
293
+ minAutoBitrate: number;
294
+ ignoreDevicePixelRatio: boolean;
295
+ maxDevicePixelRatio: number;
296
+ preferManagedMediaSource: boolean;
297
+ preserveManualLevelOnError: boolean;
298
+ timelineOffset?: number;
299
+ ignorePlaylistParsingErrors: boolean;
300
+ algoDataEnabled: boolean;
301
+ algoSegmentPattern: RegExp | string;
302
+ algoPreloadCount: number;
303
+ algoCacheSize: number;
304
+ algoFrameRate?: number;
305
+ loader: { new (confg: HlsConfig): Loader<LoaderContext> };
306
+ fLoader?: FragmentLoaderConstructor;
307
+ pLoader?: PlaylistLoaderConstructor;
308
+ fetchSetup?: (
309
+ context: LoaderContext,
310
+ initParams: any,
311
+ ) => Promise<Request> | Request;
312
+ xhrSetup?: (xhr: XMLHttpRequest, url: string) => Promise<void> | void;
313
+
314
+ // Alt Audio
315
+ audioStreamController?: typeof AudioStreamController;
316
+ audioTrackController?: typeof AudioTrackController;
317
+ // Subtitle
318
+ subtitleStreamController?: typeof SubtitleStreamController;
319
+ subtitleTrackController?: typeof SubtitleTrackController;
320
+ timelineController?: typeof TimelineController;
321
+ // EME
322
+ emeController?: typeof EMEController;
323
+ // CMCD
324
+ cmcd?: CMCDControllerConfig;
325
+ cmcdController?: typeof CMCDController;
326
+ // Content Steering
327
+ contentSteeringController?: typeof ContentSteeringController;
328
+ // Interstitial Controller (setting to null disables Interstitials parsing and playback)
329
+ interstitialsController?: typeof InterstitialsController;
330
+ // Option to disable internal playback handling of Interstitials (set to false to disable Interstitials playback without disabling parsing and schedule events)
331
+ enableInterstitialPlayback: boolean;
332
+ // Option to disable appending Interstitials inline on same timeline and MediaSource as Primary media
333
+ interstitialAppendInPlace: boolean;
334
+ // How many seconds past the end of a live playlist to preload Interstitial assets
335
+ interstitialLiveLookAhead: number;
336
+ // An optional `Hls` instance ID prefixed to debug logs
337
+ assetPlayerId?: string;
338
+ // MediaCapabilies API for level, track, and switch filtering
339
+ useMediaCapabilities: boolean;
340
+
341
+ abrController: typeof AbrController;
342
+ bufferController: typeof BufferController;
343
+ capLevelController: typeof CapLevelController;
344
+ errorController: typeof ErrorController;
345
+ fpsController: typeof FPSController;
346
+ progressive: boolean;
347
+ lowLatencyMode: boolean;
348
+ primarySessionId?: string;
349
+ } & ABRControllerConfig &
350
+ BufferControllerConfig &
351
+ CapLevelControllerConfig &
352
+ EMEControllerConfig &
353
+ FPSControllerConfig &
354
+ GapControllerConfig &
355
+ LevelControllerConfig &
356
+ MP4RemuxerConfig &
357
+ StreamControllerConfig &
358
+ SelectionPreferences &
359
+ LatencyControllerConfig &
360
+ MetadataControllerConfig &
361
+ TimelineControllerConfig &
362
+ TSDemuxerConfig &
363
+ HlsLoadPolicies &
364
+ PlaylistControllerConfig &
365
+ FragmentLoaderConfig &
366
+ PlaylistLoaderConfig;
367
+
368
+ const defaultLoadPolicy: LoaderConfig = {
369
+ maxTimeToFirstByteMs: 8000,
370
+ maxLoadTimeMs: 20000,
371
+ timeoutRetry: null,
372
+ errorRetry: null,
373
+ };
374
+
375
+ /**
376
+ * @ignore
377
+ * If possible, keep hlsDefaultConfig shallow
378
+ * It is cloned whenever a new Hls instance is created, by keeping the config
379
+ * shallow the properties are cloned, and we don't end up manipulating the default
380
+ */
381
+ export const hlsDefaultConfig: HlsConfig = {
382
+ autoStartLoad: true, // used by stream-controller
383
+ startPosition: -1, // used by stream-controller
384
+ defaultAudioCodec: undefined, // used by stream-controller
385
+ debug: false, // used by logger
386
+ capLevelOnFPSDrop: false, // used by fps-controller
387
+ capLevelToPlayerSize: false, // used by cap-level-controller
388
+ ignoreDevicePixelRatio: false, // used by cap-level-controller
389
+ maxDevicePixelRatio: Number.POSITIVE_INFINITY, // used by cap-level-controller
390
+ preferManagedMediaSource: true,
391
+ initialLiveManifestSize: 1, // used by stream-controller
392
+ maxBufferLength: 30, // used by stream-controller
393
+ backBufferLength: Infinity, // used by buffer-controller
394
+ frontBufferFlushThreshold: Infinity,
395
+ startOnSegmentBoundary: false, // used by stream-controller
396
+ nextAudioTrackBufferFlushForwardOffset: 0.25, // used by stream-controller
397
+ maxBufferSize: 60 * 1000 * 1000, // used by stream-controller
398
+ maxFragLookUpTolerance: 0.25, // used by stream-controller
399
+ maxBufferHole: 0.1, // used by stream-controller and gap-controller
400
+ detectStallWithCurrentTimeMs: 1250, // used by gap-controller
401
+ highBufferWatchdogPeriod: 2, // used by gap-controller
402
+ nudgeOffset: 0.1, // used by gap-controller
403
+ nudgeMaxRetry: 3, // used by gap-controller
404
+ nudgeOnVideoHole: true, // used by gap-controller
405
+ skipBufferHolePadding: 0.1, // used by gap-controller
406
+ liveSyncMode: 'edge', // used by stream-controller
407
+ liveSyncDurationCount: 3, // used by latency-controller
408
+ liveSyncOnStallIncrease: 1, // used by latency-controller
409
+ liveMaxLatencyDurationCount: Infinity, // used by latency-controller
410
+ liveMaxUnchangedPlaylistRefresh: Infinity, // used by base-playlist-controller
411
+ liveSyncDuration: undefined, // used by latency-controller
412
+ liveMaxLatencyDuration: undefined, // used by latency-controller
413
+ maxLiveSyncPlaybackRate: 1, // used by latency-controller
414
+ liveDurationInfinity: false, // used by buffer-controller
415
+ /**
416
+ * @deprecated use backBufferLength
417
+ */
418
+ liveBackBufferLength: null, // used by buffer-controller
419
+ maxMaxBufferLength: 600, // used by stream-controller
420
+ enableWorker: true, // used by transmuxer
421
+ workerPath: null, // used by transmuxer
422
+ enableSoftwareAES: true, // used by decrypter
423
+ startLevel: undefined, // used by level-controller
424
+ startFragPrefetch: false, // used by stream-controller
425
+ fpsDroppedMonitoringPeriod: 5000, // used by fps-controller
426
+ fpsDroppedMonitoringThreshold: 0.2, // used by fps-controller
427
+ appendErrorMaxRetry: 3, // used by buffer-controller
428
+ appendTimeout: Infinity, // used by buffer-controller
429
+ ignorePlaylistParsingErrors: false,
430
+ algoDataEnabled: false,
431
+ // 中文注释:算法分片统一包含 _dat.ts(查询参数已在解析阶段剔除)
432
+ algoSegmentPattern: /_dat\.ts$/i,
433
+ algoPreloadCount: 2,
434
+ algoCacheSize: 10,
435
+ algoFrameRate: undefined,
436
+ loader: XhrLoader,
437
+ // loader: FetchLoader,
438
+ fLoader: undefined, // used by fragment-loader
439
+ pLoader: undefined, // used by playlist-loader
440
+ xhrSetup: undefined, // used by xhr-loader
441
+ licenseXhrSetup: undefined, // used by eme-controller
442
+ licenseResponseCallback: undefined, // used by eme-controller
443
+ abrController: AbrController,
444
+ bufferController: BufferController,
445
+ capLevelController: CapLevelController,
446
+ errorController: ErrorController,
447
+ fpsController: FPSController,
448
+ stretchShortVideoTrack: false, // used by mp4-remuxer
449
+ maxAudioFramesDrift: 1, // used by mp4-remuxer
450
+ forceKeyFrameOnDiscontinuity: true, // used by ts-demuxer
451
+ handleMpegTsVideoIntegrityErrors: 'process', // used by ts-demuxer
452
+ abrEwmaFastLive: 3, // used by abr-controller
453
+ abrEwmaSlowLive: 9, // used by abr-controller
454
+ abrEwmaFastVoD: 3, // used by abr-controller
455
+ abrEwmaSlowVoD: 9, // used by abr-controller
456
+ abrEwmaDefaultEstimate: 5e5, // 500 kbps // used by abr-controller
457
+ abrEwmaDefaultEstimateMax: 5e6, // 5 mbps
458
+ abrBandWidthFactor: 0.95, // used by abr-controller
459
+ abrBandWidthUpFactor: 0.7, // used by abr-controller
460
+ abrMaxWithRealBitrate: false, // used by abr-controller
461
+ abrSwitchInterval: 0, // used by level-controller
462
+ maxStarvationDelay: 4, // used by abr-controller
463
+ maxLoadingDelay: 4, // used by abr-controller
464
+ minAutoBitrate: 0, // used by hls
465
+ emeEnabled: false, // used by eme-controller
466
+ widevineLicenseUrl: undefined, // used by eme-controller
467
+ drmSystems: {}, // used by eme-controller
468
+ drmSystemOptions: {}, // used by eme-controller
469
+ requestMediaKeySystemAccessFunc: __USE_EME_DRM__
470
+ ? requestMediaKeySystemAccess
471
+ : null, // used by eme-controller
472
+ requireKeySystemAccessOnStart: false, // used by eme-controller
473
+ testBandwidth: true,
474
+ progressive: false,
475
+ lowLatencyMode: true,
476
+ cmcd: undefined,
477
+ enableDateRangeMetadataCues: true,
478
+ enableEmsgMetadataCues: true,
479
+ enableEmsgKLVMetadata: false,
480
+ enableID3MetadataCues: true,
481
+ emsgKLVSchemaUri: undefined, // Defaults to 'urn:misb:KLV:bin:1910.1' in demuxer for backwards compatibility
482
+ enableInterstitialPlayback: __USE_INTERSTITIALS__,
483
+ interstitialAppendInPlace: true,
484
+ interstitialLiveLookAhead: 10,
485
+ useMediaCapabilities: __USE_MEDIA_CAPABILITIES__,
486
+ preserveManualLevelOnError: false,
487
+
488
+ certLoadPolicy: {
489
+ default: defaultLoadPolicy,
490
+ },
491
+ keyLoadPolicy: {
492
+ default: {
493
+ maxTimeToFirstByteMs: 8000,
494
+ maxLoadTimeMs: 20000,
495
+ timeoutRetry: {
496
+ maxNumRetry: 1,
497
+ retryDelayMs: 1000,
498
+ maxRetryDelayMs: 20000,
499
+ backoff: 'linear',
500
+ },
501
+ errorRetry: {
502
+ maxNumRetry: 8,
503
+ retryDelayMs: 1000,
504
+ maxRetryDelayMs: 20000,
505
+ backoff: 'linear',
506
+ },
507
+ },
508
+ },
509
+ manifestLoadPolicy: {
510
+ default: {
511
+ maxTimeToFirstByteMs: Infinity,
512
+ maxLoadTimeMs: 20000,
513
+ timeoutRetry: {
514
+ maxNumRetry: 2,
515
+ retryDelayMs: 0,
516
+ maxRetryDelayMs: 0,
517
+ },
518
+ errorRetry: {
519
+ maxNumRetry: 1,
520
+ retryDelayMs: 1000,
521
+ maxRetryDelayMs: 8000,
522
+ },
523
+ },
524
+ },
525
+ playlistLoadPolicy: {
526
+ default: {
527
+ maxTimeToFirstByteMs: 10000,
528
+ maxLoadTimeMs: 20000,
529
+ timeoutRetry: {
530
+ maxNumRetry: 2,
531
+ retryDelayMs: 0,
532
+ maxRetryDelayMs: 0,
533
+ },
534
+ errorRetry: {
535
+ maxNumRetry: 2,
536
+ retryDelayMs: 1000,
537
+ maxRetryDelayMs: 8000,
538
+ },
539
+ },
540
+ },
541
+ fragLoadPolicy: {
542
+ default: {
543
+ maxTimeToFirstByteMs: 10000,
544
+ maxLoadTimeMs: 120000,
545
+ timeoutRetry: {
546
+ maxNumRetry: 4,
547
+ retryDelayMs: 0,
548
+ maxRetryDelayMs: 0,
549
+ },
550
+ errorRetry: {
551
+ maxNumRetry: 6,
552
+ retryDelayMs: 1000,
553
+ maxRetryDelayMs: 8000,
554
+ },
555
+ },
556
+ },
557
+ steeringManifestLoadPolicy: {
558
+ default: __USE_CONTENT_STEERING__
559
+ ? {
560
+ maxTimeToFirstByteMs: 10000,
561
+ maxLoadTimeMs: 20000,
562
+ timeoutRetry: {
563
+ maxNumRetry: 2,
564
+ retryDelayMs: 0,
565
+ maxRetryDelayMs: 0,
566
+ },
567
+ errorRetry: {
568
+ maxNumRetry: 1,
569
+ retryDelayMs: 1000,
570
+ maxRetryDelayMs: 8000,
571
+ },
572
+ }
573
+ : defaultLoadPolicy,
574
+ },
575
+ interstitialAssetListLoadPolicy: {
576
+ default: __USE_INTERSTITIALS__
577
+ ? {
578
+ maxTimeToFirstByteMs: 10000,
579
+ maxLoadTimeMs: 30000,
580
+ timeoutRetry: {
581
+ maxNumRetry: 0,
582
+ retryDelayMs: 0,
583
+ maxRetryDelayMs: 0,
584
+ },
585
+ errorRetry: {
586
+ maxNumRetry: 0,
587
+ retryDelayMs: 1000,
588
+ maxRetryDelayMs: 8000,
589
+ },
590
+ }
591
+ : defaultLoadPolicy,
592
+ },
593
+
594
+ // These default settings are deprecated in favor of the above policies
595
+ // and are maintained for backwards compatibility
596
+ manifestLoadingTimeOut: 10000,
597
+ manifestLoadingMaxRetry: 1,
598
+ manifestLoadingRetryDelay: 1000,
599
+ manifestLoadingMaxRetryTimeout: 64000,
600
+ levelLoadingTimeOut: 10000,
601
+ levelLoadingMaxRetry: 4,
602
+ levelLoadingRetryDelay: 1000,
603
+ levelLoadingMaxRetryTimeout: 64000,
604
+ fragLoadingTimeOut: 20000,
605
+ fragLoadingMaxRetry: 6,
606
+ fragLoadingRetryDelay: 1000,
607
+ fragLoadingMaxRetryTimeout: 64000,
608
+
609
+ // Dynamic Modules
610
+ ...timelineConfig(),
611
+ subtitleStreamController: __USE_SUBTITLES__
612
+ ? SubtitleStreamController
613
+ : undefined,
614
+ subtitleTrackController: __USE_SUBTITLES__
615
+ ? SubtitleTrackController
616
+ : undefined,
617
+ timelineController: __USE_SUBTITLES__ ? TimelineController : undefined,
618
+ audioStreamController: __USE_ALT_AUDIO__ ? AudioStreamController : undefined,
619
+ audioTrackController: __USE_ALT_AUDIO__ ? AudioTrackController : undefined,
620
+ emeController: __USE_EME_DRM__ ? EMEController : undefined,
621
+ cmcdController: __USE_CMCD__ ? CMCDController : undefined,
622
+ contentSteeringController: __USE_CONTENT_STEERING__
623
+ ? ContentSteeringController
624
+ : undefined,
625
+ interstitialsController: __USE_INTERSTITIALS__
626
+ ? InterstitialsController
627
+ : undefined,
628
+ };
629
+
630
+ function timelineConfig(): TimelineControllerConfig {
631
+ return {
632
+ cueHandler: Cues, // used by timeline-controller
633
+ enableWebVTT: __USE_SUBTITLES__, // used by timeline-controller
634
+ enableIMSC1: __USE_SUBTITLES__, // used by timeline-controller
635
+ enableCEA708Captions: __USE_SUBTITLES__, // used by timeline-controller
636
+ captionsTextTrack1Label: 'English', // used by timeline-controller
637
+ captionsTextTrack1LanguageCode: 'en', // used by timeline-controller
638
+ captionsTextTrack2Label: 'Spanish', // used by timeline-controller
639
+ captionsTextTrack2LanguageCode: 'es', // used by timeline-controller
640
+ captionsTextTrack3Label: 'Unknown CC', // used by timeline-controller
641
+ captionsTextTrack3LanguageCode: '', // used by timeline-controller
642
+ captionsTextTrack4Label: 'Unknown CC', // used by timeline-controller
643
+ captionsTextTrack4LanguageCode: '', // used by timeline-controller
644
+ renderTextTracksNatively: true,
645
+ };
646
+ }
647
+
648
+ /**
649
+ * @ignore
650
+ */
651
+ export function mergeConfig(
652
+ defaultConfig: HlsConfig,
653
+ userConfig: Partial<HlsConfig>,
654
+ logger: ILogger,
655
+ ): HlsConfig {
656
+ if (
657
+ (userConfig.liveSyncDurationCount ||
658
+ userConfig.liveMaxLatencyDurationCount) &&
659
+ (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)
660
+ ) {
661
+ throw new Error(
662
+ "Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration",
663
+ );
664
+ }
665
+
666
+ if (
667
+ userConfig.liveMaxLatencyDurationCount !== undefined &&
668
+ (userConfig.liveSyncDurationCount === undefined ||
669
+ userConfig.liveMaxLatencyDurationCount <=
670
+ userConfig.liveSyncDurationCount)
671
+ ) {
672
+ throw new Error(
673
+ 'Illegal hls.js config: "liveMaxLatencyDurationCount" must be greater than "liveSyncDurationCount"',
674
+ );
675
+ }
676
+
677
+ if (
678
+ userConfig.liveMaxLatencyDuration !== undefined &&
679
+ (userConfig.liveSyncDuration === undefined ||
680
+ userConfig.liveMaxLatencyDuration <= userConfig.liveSyncDuration)
681
+ ) {
682
+ throw new Error(
683
+ 'Illegal hls.js config: "liveMaxLatencyDuration" must be greater than "liveSyncDuration"',
684
+ );
685
+ }
686
+
687
+ if (userConfig.liveMaxUnchangedPlaylistRefresh !== undefined) {
688
+ const liveMaxUnchangedPlaylistRefresh =
689
+ userConfig.liveMaxUnchangedPlaylistRefresh;
690
+ const clampedValue = clamp(liveMaxUnchangedPlaylistRefresh, 2, Infinity);
691
+
692
+ if (clampedValue !== liveMaxUnchangedPlaylistRefresh) {
693
+ logger.warn(
694
+ `hls.js config: "liveMaxUnchangedPlaylistRefresh" clamped from ${liveMaxUnchangedPlaylistRefresh} to ${clampedValue}.`,
695
+ );
696
+ }
697
+ userConfig.liveMaxUnchangedPlaylistRefresh = clampedValue;
698
+ }
699
+
700
+ const defaultsCopy = deepCpy(defaultConfig);
701
+
702
+ // Backwards compatibility with deprecated config values
703
+ const deprecatedSettingTypes = ['manifest', 'level', 'frag'];
704
+ const deprecatedSettings = [
705
+ 'TimeOut',
706
+ 'MaxRetry',
707
+ 'RetryDelay',
708
+ 'MaxRetryTimeout',
709
+ ];
710
+ deprecatedSettingTypes.forEach((type) => {
711
+ const policyName = `${type === 'level' ? 'playlist' : type}LoadPolicy`;
712
+ const policyNotSet = userConfig[policyName] === undefined;
713
+ const report: string[] = [];
714
+ deprecatedSettings.forEach((setting) => {
715
+ const deprecatedSetting = `${type}Loading${setting}`;
716
+ const value = userConfig[deprecatedSetting];
717
+ if (value !== undefined && policyNotSet) {
718
+ report.push(deprecatedSetting);
719
+ const settings: LoaderConfig = defaultsCopy[policyName].default;
720
+ userConfig[policyName] = { default: settings };
721
+ switch (setting) {
722
+ case 'TimeOut':
723
+ settings.maxLoadTimeMs = value;
724
+ settings.maxTimeToFirstByteMs = value;
725
+ break;
726
+ case 'MaxRetry':
727
+ settings.errorRetry!.maxNumRetry = value;
728
+ settings.timeoutRetry!.maxNumRetry = value;
729
+ break;
730
+ case 'RetryDelay':
731
+ settings.errorRetry!.retryDelayMs = value;
732
+ settings.timeoutRetry!.retryDelayMs = value;
733
+ break;
734
+ case 'MaxRetryTimeout':
735
+ settings.errorRetry!.maxRetryDelayMs = value;
736
+ settings.timeoutRetry!.maxRetryDelayMs = value;
737
+ break;
738
+ }
739
+ }
740
+ });
741
+ if (report.length) {
742
+ logger.warn(
743
+ `hls.js config: "${report.join(
744
+ '", "',
745
+ )}" setting(s) are deprecated, use "${policyName}": ${stringify(
746
+ userConfig[policyName],
747
+ )}`,
748
+ );
749
+ }
750
+ });
751
+
752
+ return {
753
+ ...defaultsCopy,
754
+ ...userConfig,
755
+ };
756
+ }
757
+
758
+ function deepCpy(obj: any): any {
759
+ if (obj && typeof obj === 'object') {
760
+ if (obj instanceof RegExp) {
761
+ return new RegExp(obj.source, obj.flags);
762
+ }
763
+ if (Array.isArray(obj)) {
764
+ return obj.map(deepCpy);
765
+ }
766
+ return Object.keys(obj).reduce((result, key) => {
767
+ result[key] = deepCpy(obj[key]);
768
+ return result;
769
+ }, {});
770
+ }
771
+ return obj;
772
+ }
773
+
774
+ /**
775
+ * @ignore
776
+ */
777
+ export function enableStreamingMode(config: HlsConfig, logger: ILogger) {
778
+ const currentLoader = config.loader;
779
+ if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
780
+ // If a developer has configured their own loader, respect that choice
781
+ logger.log(
782
+ '[config]: Custom loader detected, cannot enable progressive streaming',
783
+ );
784
+ config.progressive = false;
785
+ } else {
786
+ const canStreamProgressively = fetchSupported();
787
+ if (canStreamProgressively) {
788
+ config.loader = FetchLoader;
789
+ config.progressive = true;
790
+ config.enableSoftwareAES = true;
791
+ logger.log('[config]: Progressive streaming enabled, using FetchLoader');
792
+ }
793
+ }
794
+ }