Home Reference Source

src/types/level.ts

  1. import { LevelDetails } from '../loader/level-details';
  2. import { AttrList } from '../utils/attr-list';
  3.  
  4. export interface LevelParsed {
  5. attrs: LevelAttributes;
  6. audioCodec?: string;
  7. bitrate: number;
  8. details?: LevelDetails;
  9. height?: number;
  10. id?: number;
  11. level?: number;
  12. name: string;
  13. textCodec?: string;
  14. unknownCodecs?: string[];
  15. url: string;
  16. videoCodec?: string;
  17. width?: number;
  18. }
  19.  
  20. export interface LevelAttributes extends AttrList {
  21. AUDIO?: string;
  22. AUTOSELECT?: string;
  23. 'AVERAGE-BANDWIDTH'?: string;
  24. BANDWIDTH?: string;
  25. BYTERANGE?: string;
  26. 'CLOSED-CAPTIONS'?: string;
  27. CHARACTERISTICS?: string;
  28. CODECS?: string;
  29. DEFAULT?: string;
  30. FORCED?: string;
  31. 'FRAME-RATE'?: string;
  32. LANGUAGE?: string;
  33. NAME?: string;
  34. 'PROGRAM-ID'?: string;
  35. RESOLUTION?: string;
  36. SUBTITLES?: string;
  37. TYPE?: string;
  38. URI?: string;
  39. }
  40.  
  41. export enum HlsSkip {
  42. No = '',
  43. Yes = 'YES',
  44. v2 = 'v2',
  45. }
  46.  
  47. export function getSkipValue(details: LevelDetails, msn?: number): HlsSkip {
  48. const { canSkipUntil, canSkipDateRanges, endSN } = details;
  49. const snChangeGoal = msn !== undefined ? msn - endSN : 0;
  50. if (canSkipUntil && snChangeGoal < canSkipUntil) {
  51. if (canSkipDateRanges) {
  52. return HlsSkip.v2;
  53. }
  54. return HlsSkip.Yes;
  55. }
  56. return HlsSkip.No;
  57. }
  58.  
  59. export class HlsUrlParameters {
  60. msn?: number;
  61. part?: number;
  62. skip?: HlsSkip;
  63.  
  64. constructor(msn?: number, part?: number, skip?: HlsSkip) {
  65. this.msn = msn;
  66. this.part = part;
  67. this.skip = skip;
  68. }
  69.  
  70. addDirectives(uri: string): string | never {
  71. const url: URL = new self.URL(uri);
  72. if (this.msn !== undefined) {
  73. url.searchParams.set('_HLS_msn', this.msn.toString());
  74. }
  75. if (this.part !== undefined) {
  76. url.searchParams.set('_HLS_part', this.part.toString());
  77. }
  78. if (this.skip) {
  79. url.searchParams.set('_HLS_skip', this.skip);
  80. }
  81. return url.toString();
  82. }
  83. }
  84.  
  85. export class Level {
  86. public readonly attrs: LevelAttributes;
  87. public readonly audioCodec: string | undefined;
  88. public readonly bitrate: number;
  89. public readonly codecSet: string;
  90. public readonly height: number;
  91. public readonly id: number;
  92. public readonly name: string | undefined;
  93. public readonly videoCodec: string | undefined;
  94. public readonly width: number;
  95. public readonly unknownCodecs: string[] | undefined;
  96. public audioGroupIds?: string[];
  97. public details?: LevelDetails;
  98. public fragmentError: number = 0;
  99. public loadError: number = 0;
  100. public loaded?: { bytes: number; duration: number };
  101. public realBitrate: number = 0;
  102. public textGroupIds?: string[];
  103. public url: string[];
  104. private _urlId: number = 0;
  105.  
  106. constructor(data: LevelParsed) {
  107. this.url = [data.url];
  108. this.attrs = data.attrs;
  109. this.bitrate = data.bitrate;
  110. if (data.details) {
  111. this.details = data.details;
  112. }
  113. this.id = data.id || 0;
  114. this.name = data.name;
  115. this.width = data.width || 0;
  116. this.height = data.height || 0;
  117. this.audioCodec = data.audioCodec;
  118. this.videoCodec = data.videoCodec;
  119. this.unknownCodecs = data.unknownCodecs;
  120. this.codecSet = [data.videoCodec, data.audioCodec]
  121. .filter((c) => c)
  122. .join(',')
  123. .replace(/\.[^.,]+/g, '');
  124. }
  125.  
  126. get maxBitrate(): number {
  127. return Math.max(this.realBitrate, this.bitrate);
  128. }
  129.  
  130. get uri(): string {
  131. return this.url[this._urlId] || '';
  132. }
  133.  
  134. get urlId(): number {
  135. return this._urlId;
  136. }
  137.  
  138. set urlId(value: number) {
  139. const newValue = value % this.url.length;
  140. if (this._urlId !== newValue) {
  141. this.details = undefined;
  142. this._urlId = newValue;
  143. }
  144. }
  145. }