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