Home Reference Source

src/config.ts

  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 { SubtitleStreamController } from './controller/subtitle-stream-controller';
  5. import SubtitleTrackController from './controller/subtitle-track-controller';
  6. import BufferController from './controller/buffer-controller';
  7. import { TimelineController } from './controller/timeline-controller';
  8. import CapLevelController from './controller/cap-level-controller';
  9. import FPSController from './controller/fps-controller';
  10. import EMEController from './controller/eme-controller';
  11. import CMCDController from './controller/cmcd-controller';
  12. import XhrLoader from './utils/xhr-loader';
  13. import FetchLoader, { fetchSupported } from './utils/fetch-loader';
  14. import Cues from './utils/cues';
  15. import { requestMediaKeySystemAccess } from './utils/mediakeys-helper';
  16. import { ILogger, logger } from './utils/logger';
  17.  
  18. import type { CuesInterface } from './utils/cues';
  19. import type { MediaKeyFunc } from './utils/mediakeys-helper';
  20. import type {
  21. FragmentLoaderContext,
  22. Loader,
  23. LoaderContext,
  24. PlaylistLoaderContext,
  25. } from './types/loader';
  26.  
  27. export type ABRControllerConfig = {
  28. abrEwmaFastLive: number;
  29. abrEwmaSlowLive: number;
  30. abrEwmaFastVoD: number;
  31. abrEwmaSlowVoD: number;
  32. abrEwmaDefaultEstimate: number;
  33. abrBandWidthFactor: number;
  34. abrBandWidthUpFactor: number;
  35. abrMaxWithRealBitrate: boolean;
  36. maxStarvationDelay: number;
  37. maxLoadingDelay: number;
  38. };
  39.  
  40. export type BufferControllerConfig = {
  41. appendErrorMaxRetry: number;
  42. backBufferLength: number;
  43. liveDurationInfinity: boolean;
  44. liveBackBufferLength: number | null;
  45. };
  46.  
  47. export type CapLevelControllerConfig = {
  48. capLevelToPlayerSize: boolean;
  49. };
  50.  
  51. export type CMCDControllerConfig = {
  52. sessionId?: string;
  53. contentId?: string;
  54. useHeaders?: boolean;
  55. };
  56.  
  57. export type DRMSystemOptions = {
  58. audioRobustness?: string;
  59. videoRobustness?: string;
  60. };
  61.  
  62. export type EMEControllerConfig = {
  63. licenseXhrSetup?: (xhr: XMLHttpRequest, url: string) => void;
  64. licenseResponseCallback?: (xhr: XMLHttpRequest, url: string) => ArrayBuffer;
  65. emeEnabled: boolean;
  66. widevineLicenseUrl?: string;
  67. drmSystemOptions: DRMSystemOptions;
  68. requestMediaKeySystemAccessFunc: MediaKeyFunc | null;
  69. };
  70.  
  71. export interface FragmentLoaderConstructor {
  72. new (confg: HlsConfig): Loader<FragmentLoaderContext>;
  73. }
  74.  
  75. export type FragmentLoaderConfig = {
  76. fLoader?: FragmentLoaderConstructor;
  77.  
  78. fragLoadingTimeOut: number;
  79. fragLoadingMaxRetry: number;
  80. fragLoadingRetryDelay: number;
  81. fragLoadingMaxRetryTimeout: number;
  82. };
  83.  
  84. export type FPSControllerConfig = {
  85. capLevelOnFPSDrop: boolean;
  86. fpsDroppedMonitoringPeriod: number;
  87. fpsDroppedMonitoringThreshold: number;
  88. };
  89.  
  90. export type LevelControllerConfig = {
  91. startLevel?: number;
  92. };
  93.  
  94. export type MP4RemuxerConfig = {
  95. stretchShortVideoTrack: boolean;
  96. maxAudioFramesDrift: number;
  97. };
  98.  
  99. export interface PlaylistLoaderConstructor {
  100. new (confg: HlsConfig): Loader<PlaylistLoaderContext>;
  101. }
  102.  
  103. export type PlaylistLoaderConfig = {
  104. pLoader?: PlaylistLoaderConstructor;
  105.  
  106. manifestLoadingTimeOut: number;
  107. manifestLoadingMaxRetry: number;
  108. manifestLoadingRetryDelay: number;
  109. manifestLoadingMaxRetryTimeout: number;
  110.  
  111. levelLoadingTimeOut: number;
  112. levelLoadingMaxRetry: number;
  113. levelLoadingRetryDelay: number;
  114. levelLoadingMaxRetryTimeout: number;
  115. };
  116.  
  117. export type StreamControllerConfig = {
  118. autoStartLoad: boolean;
  119. startPosition: number;
  120. defaultAudioCodec?: string;
  121. initialLiveManifestSize: number;
  122. maxBufferLength: number;
  123. maxBufferSize: number;
  124. maxBufferHole: number;
  125. highBufferWatchdogPeriod: number;
  126. nudgeOffset: number;
  127. nudgeMaxRetry: number;
  128. maxFragLookUpTolerance: number;
  129. maxMaxBufferLength: number;
  130. startFragPrefetch: boolean;
  131. testBandwidth: boolean;
  132. };
  133.  
  134. export type LatencyControllerConfig = {
  135. liveSyncDurationCount: number;
  136. liveMaxLatencyDurationCount: number;
  137. liveSyncDuration?: number;
  138. liveMaxLatencyDuration?: number;
  139. maxLiveSyncPlaybackRate: number;
  140. };
  141.  
  142. export type MetadataControllerConfig = {
  143. enableDateRangeMetadataCues: boolean;
  144. enableEmsgMetadataCues: boolean;
  145. enableID3MetadataCues: boolean;
  146. };
  147.  
  148. export type TimelineControllerConfig = {
  149. cueHandler: CuesInterface;
  150. enableWebVTT: boolean;
  151. enableIMSC1: boolean;
  152. enableCEA708Captions: boolean;
  153. captionsTextTrack1Label: string;
  154. captionsTextTrack1LanguageCode: string;
  155. captionsTextTrack2Label: string;
  156. captionsTextTrack2LanguageCode: string;
  157. captionsTextTrack3Label: string;
  158. captionsTextTrack3LanguageCode: string;
  159. captionsTextTrack4Label: string;
  160. captionsTextTrack4LanguageCode: string;
  161. renderTextTracksNatively: boolean;
  162. };
  163.  
  164. export type TSDemuxerConfig = {
  165. forceKeyFrameOnDiscontinuity: boolean;
  166. };
  167.  
  168. export type HlsConfig = {
  169. debug: boolean | ILogger;
  170. enableWorker: boolean;
  171. enableSoftwareAES: boolean;
  172. minAutoBitrate: number;
  173. ignoreDevicePixelRatio: boolean;
  174. loader: { new (confg: HlsConfig): Loader<LoaderContext> };
  175. fetchSetup?: (context: LoaderContext, initParams: any) => Request;
  176. xhrSetup?: (xhr: XMLHttpRequest, url: string) => void;
  177.  
  178. // Alt Audio
  179. audioStreamController?: typeof AudioStreamController;
  180. audioTrackController?: typeof AudioTrackController;
  181. // Subtitle
  182. subtitleStreamController?: typeof SubtitleStreamController;
  183. subtitleTrackController?: typeof SubtitleTrackController;
  184. timelineController?: typeof TimelineController;
  185. // EME
  186. emeController?: typeof EMEController;
  187. // CMCD
  188. cmcd?: CMCDControllerConfig;
  189. cmcdController?: typeof CMCDController;
  190.  
  191. abrController: typeof AbrController;
  192. bufferController: typeof BufferController;
  193. capLevelController: typeof CapLevelController;
  194. fpsController: typeof FPSController;
  195. progressive: boolean;
  196. lowLatencyMode: boolean;
  197. } & ABRControllerConfig &
  198. BufferControllerConfig &
  199. CapLevelControllerConfig &
  200. EMEControllerConfig &
  201. FPSControllerConfig &
  202. FragmentLoaderConfig &
  203. LevelControllerConfig &
  204. MP4RemuxerConfig &
  205. PlaylistLoaderConfig &
  206. StreamControllerConfig &
  207. LatencyControllerConfig &
  208. MetadataControllerConfig &
  209. TimelineControllerConfig &
  210. TSDemuxerConfig;
  211.  
  212. // If possible, keep hlsDefaultConfig shallow
  213. // It is cloned whenever a new Hls instance is created, by keeping the config
  214. // shallow the properties are cloned, and we don't end up manipulating the default
  215. export const hlsDefaultConfig: HlsConfig = {
  216. autoStartLoad: true, // used by stream-controller
  217. startPosition: -1, // used by stream-controller
  218. defaultAudioCodec: undefined, // used by stream-controller
  219. debug: false, // used by logger
  220. capLevelOnFPSDrop: false, // used by fps-controller
  221. capLevelToPlayerSize: false, // used by cap-level-controller
  222. ignoreDevicePixelRatio: false, // used by cap-level-controller
  223. initialLiveManifestSize: 1, // used by stream-controller
  224. maxBufferLength: 30, // used by stream-controller
  225. backBufferLength: Infinity, // used by buffer-controller
  226. maxBufferSize: 60 * 1000 * 1000, // used by stream-controller
  227. maxBufferHole: 0.1, // used by stream-controller
  228. highBufferWatchdogPeriod: 2, // used by stream-controller
  229. nudgeOffset: 0.1, // used by stream-controller
  230. nudgeMaxRetry: 3, // used by stream-controller
  231. maxFragLookUpTolerance: 0.25, // used by stream-controller
  232. liveSyncDurationCount: 3, // used by latency-controller
  233. liveMaxLatencyDurationCount: Infinity, // used by latency-controller
  234. liveSyncDuration: undefined, // used by latency-controller
  235. liveMaxLatencyDuration: undefined, // used by latency-controller
  236. maxLiveSyncPlaybackRate: 1, // used by latency-controller
  237. liveDurationInfinity: false, // used by buffer-controller
  238. liveBackBufferLength: null, // used by buffer-controller
  239. maxMaxBufferLength: 600, // used by stream-controller
  240. enableWorker: true, // used by demuxer
  241. enableSoftwareAES: true, // used by decrypter
  242. manifestLoadingTimeOut: 10000, // used by playlist-loader
  243. manifestLoadingMaxRetry: 1, // used by playlist-loader
  244. manifestLoadingRetryDelay: 1000, // used by playlist-loader
  245. manifestLoadingMaxRetryTimeout: 64000, // used by playlist-loader
  246. startLevel: undefined, // used by level-controller
  247. levelLoadingTimeOut: 10000, // used by playlist-loader
  248. levelLoadingMaxRetry: 4, // used by playlist-loader
  249. levelLoadingRetryDelay: 1000, // used by playlist-loader
  250. levelLoadingMaxRetryTimeout: 64000, // used by playlist-loader
  251. fragLoadingTimeOut: 20000, // used by fragment-loader
  252. fragLoadingMaxRetry: 6, // used by fragment-loader
  253. fragLoadingRetryDelay: 1000, // used by fragment-loader
  254. fragLoadingMaxRetryTimeout: 64000, // used by fragment-loader
  255. startFragPrefetch: false, // used by stream-controller
  256. fpsDroppedMonitoringPeriod: 5000, // used by fps-controller
  257. fpsDroppedMonitoringThreshold: 0.2, // used by fps-controller
  258. appendErrorMaxRetry: 3, // used by buffer-controller
  259. loader: XhrLoader,
  260. // loader: FetchLoader,
  261. fLoader: undefined, // used by fragment-loader
  262. pLoader: undefined, // used by playlist-loader
  263. xhrSetup: undefined, // used by xhr-loader
  264. licenseXhrSetup: undefined, // used by eme-controller
  265. licenseResponseCallback: undefined, // used by eme-controller
  266. abrController: AbrController,
  267. bufferController: BufferController,
  268. capLevelController: CapLevelController,
  269. fpsController: FPSController,
  270. stretchShortVideoTrack: false, // used by mp4-remuxer
  271. maxAudioFramesDrift: 1, // used by mp4-remuxer
  272. forceKeyFrameOnDiscontinuity: true, // used by ts-demuxer
  273. abrEwmaFastLive: 3, // used by abr-controller
  274. abrEwmaSlowLive: 9, // used by abr-controller
  275. abrEwmaFastVoD: 3, // used by abr-controller
  276. abrEwmaSlowVoD: 9, // used by abr-controller
  277. abrEwmaDefaultEstimate: 5e5, // 500 kbps // used by abr-controller
  278. abrBandWidthFactor: 0.95, // used by abr-controller
  279. abrBandWidthUpFactor: 0.7, // used by abr-controller
  280. abrMaxWithRealBitrate: false, // used by abr-controller
  281. maxStarvationDelay: 4, // used by abr-controller
  282. maxLoadingDelay: 4, // used by abr-controller
  283. minAutoBitrate: 0, // used by hls
  284. emeEnabled: false, // used by eme-controller
  285. widevineLicenseUrl: undefined, // used by eme-controller
  286. drmSystemOptions: {}, // used by eme-controller
  287. requestMediaKeySystemAccessFunc: requestMediaKeySystemAccess, // used by eme-controller
  288. testBandwidth: true,
  289. progressive: false,
  290. lowLatencyMode: true,
  291. cmcd: undefined,
  292. enableDateRangeMetadataCues: true,
  293. enableEmsgMetadataCues: true,
  294. enableID3MetadataCues: true,
  295.  
  296. // Dynamic Modules
  297. ...timelineConfig(),
  298. subtitleStreamController: __USE_SUBTITLES__
  299. ? SubtitleStreamController
  300. : undefined,
  301. subtitleTrackController: __USE_SUBTITLES__
  302. ? SubtitleTrackController
  303. : undefined,
  304. timelineController: __USE_SUBTITLES__ ? TimelineController : undefined,
  305. audioStreamController: __USE_ALT_AUDIO__ ? AudioStreamController : undefined,
  306. audioTrackController: __USE_ALT_AUDIO__ ? AudioTrackController : undefined,
  307. emeController: __USE_EME_DRM__ ? EMEController : undefined,
  308. cmcdController: __USE_CMCD__ ? CMCDController : undefined,
  309. };
  310.  
  311. function timelineConfig(): TimelineControllerConfig {
  312. return {
  313. cueHandler: Cues, // used by timeline-controller
  314. enableWebVTT: __USE_SUBTITLES__, // used by timeline-controller
  315. enableIMSC1: __USE_SUBTITLES__, // used by timeline-controller
  316. enableCEA708Captions: __USE_SUBTITLES__, // used by timeline-controller
  317. captionsTextTrack1Label: 'English', // used by timeline-controller
  318. captionsTextTrack1LanguageCode: 'en', // used by timeline-controller
  319. captionsTextTrack2Label: 'Spanish', // used by timeline-controller
  320. captionsTextTrack2LanguageCode: 'es', // used by timeline-controller
  321. captionsTextTrack3Label: 'Unknown CC', // used by timeline-controller
  322. captionsTextTrack3LanguageCode: '', // used by timeline-controller
  323. captionsTextTrack4Label: 'Unknown CC', // used by timeline-controller
  324. captionsTextTrack4LanguageCode: '', // used by timeline-controller
  325. renderTextTracksNatively: true,
  326. };
  327. }
  328.  
  329. export function mergeConfig(
  330. defaultConfig: HlsConfig,
  331. userConfig: Partial<HlsConfig>
  332. ): HlsConfig {
  333. if (
  334. (userConfig.liveSyncDurationCount ||
  335. userConfig.liveMaxLatencyDurationCount) &&
  336. (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)
  337. ) {
  338. throw new Error(
  339. "Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration"
  340. );
  341. }
  342.  
  343. if (
  344. userConfig.liveMaxLatencyDurationCount !== undefined &&
  345. (userConfig.liveSyncDurationCount === undefined ||
  346. userConfig.liveMaxLatencyDurationCount <=
  347. userConfig.liveSyncDurationCount)
  348. ) {
  349. throw new Error(
  350. 'Illegal hls.js config: "liveMaxLatencyDurationCount" must be greater than "liveSyncDurationCount"'
  351. );
  352. }
  353.  
  354. if (
  355. userConfig.liveMaxLatencyDuration !== undefined &&
  356. (userConfig.liveSyncDuration === undefined ||
  357. userConfig.liveMaxLatencyDuration <= userConfig.liveSyncDuration)
  358. ) {
  359. throw new Error(
  360. 'Illegal hls.js config: "liveMaxLatencyDuration" must be greater than "liveSyncDuration"'
  361. );
  362. }
  363.  
  364. return Object.assign({}, defaultConfig, userConfig);
  365. }
  366.  
  367. export function enableStreamingMode(config) {
  368. const currentLoader = config.loader;
  369. if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
  370. // If a developer has configured their own loader, respect that choice
  371. logger.log(
  372. '[config]: Custom loader detected, cannot enable progressive streaming'
  373. );
  374. config.progressive = false;
  375. } else {
  376. const canStreamProgressively = fetchSupported();
  377. if (canStreamProgressively) {
  378. config.loader = FetchLoader;
  379. config.progressive = true;
  380. config.enableSoftwareAES = true;
  381. logger.log('[config]: Progressive streaming enabled, using FetchLoader');
  382. }
  383. }
  384. }