Home Reference Source

src/loader/level-details.ts

  1. import { Part } from './fragment';
  2. import type { Fragment } from './fragment';
  3. import type { AttrList } from '../utils/attr-list';
  4. import type { DateRange } from './date-range';
  5.  
  6. const DEFAULT_TARGET_DURATION = 10;
  7.  
  8. export class LevelDetails {
  9. public PTSKnown: boolean = false;
  10. public alignedSliding: boolean = false;
  11. public averagetargetduration?: number;
  12. public endCC: number = 0;
  13. public endSN: number = 0;
  14. public fragments: Fragment[];
  15. public fragmentHint?: Fragment;
  16. public partList: Part[] | null = null;
  17. public dateRanges: Record<string, DateRange>;
  18. public live: boolean = true;
  19. public ageHeader: number = 0;
  20. public advancedDateTime?: number;
  21. public updated: boolean = true;
  22. public advanced: boolean = true;
  23. public availabilityDelay?: number; // Manifest reload synchronization
  24. public misses: number = 0;
  25. public needSidxRanges: boolean = false;
  26. public startCC: number = 0;
  27. public startSN: number = 0;
  28. public startTimeOffset: number | null = null;
  29. public targetduration: number = 0;
  30. public totalduration: number = 0;
  31. public type: string | null = null;
  32. public url: string;
  33. public m3u8: string = '';
  34. public version: number | null = null;
  35. public canBlockReload: boolean = false;
  36. public canSkipUntil: number = 0;
  37. public canSkipDateRanges: boolean = false;
  38. public skippedSegments: number = 0;
  39. public recentlyRemovedDateranges?: string[];
  40. public partHoldBack: number = 0;
  41. public holdBack: number = 0;
  42. public partTarget: number = 0;
  43. public preloadHint?: AttrList;
  44. public renditionReports?: AttrList[];
  45. public tuneInGoal: number = 0;
  46. public deltaUpdateFailed?: boolean;
  47. public driftStartTime: number = 0;
  48. public driftEndTime: number = 0;
  49. public driftStart: number = 0;
  50. public driftEnd: number = 0;
  51.  
  52. constructor(baseUrl) {
  53. this.fragments = [];
  54. this.dateRanges = {};
  55. this.url = baseUrl;
  56. }
  57.  
  58. reloaded(previous: LevelDetails | undefined) {
  59. if (!previous) {
  60. this.advanced = true;
  61. this.updated = true;
  62. return;
  63. }
  64. const partSnDiff = this.lastPartSn - previous.lastPartSn;
  65. const partIndexDiff = this.lastPartIndex - previous.lastPartIndex;
  66. this.updated =
  67. this.endSN !== previous.endSN || !!partIndexDiff || !!partSnDiff;
  68. this.advanced =
  69. this.endSN > previous.endSN ||
  70. partSnDiff > 0 ||
  71. (partSnDiff === 0 && partIndexDiff > 0);
  72. if (this.updated || this.advanced) {
  73. this.misses = Math.floor(previous.misses * 0.6);
  74. } else {
  75. this.misses = previous.misses + 1;
  76. }
  77. this.availabilityDelay = previous.availabilityDelay;
  78. }
  79.  
  80. get hasProgramDateTime(): boolean {
  81. if (this.fragments.length) {
  82. return Number.isFinite(
  83. this.fragments[this.fragments.length - 1].programDateTime as number
  84. );
  85. }
  86. return false;
  87. }
  88.  
  89. get levelTargetDuration(): number {
  90. return (
  91. this.averagetargetduration ||
  92. this.targetduration ||
  93. DEFAULT_TARGET_DURATION
  94. );
  95. }
  96.  
  97. get drift(): number {
  98. const runTime = this.driftEndTime - this.driftStartTime;
  99. if (runTime > 0) {
  100. const runDuration = this.driftEnd - this.driftStart;
  101. return (runDuration * 1000) / runTime;
  102. }
  103. return 1;
  104. }
  105.  
  106. get edge(): number {
  107. return this.partEnd || this.fragmentEnd;
  108. }
  109.  
  110. get partEnd(): number {
  111. if (this.partList?.length) {
  112. return this.partList[this.partList.length - 1].end;
  113. }
  114. return this.fragmentEnd;
  115. }
  116.  
  117. get fragmentEnd(): number {
  118. if (this.fragments?.length) {
  119. return this.fragments[this.fragments.length - 1].end;
  120. }
  121. return 0;
  122. }
  123.  
  124. get age(): number {
  125. if (this.advancedDateTime) {
  126. return Math.max(Date.now() - this.advancedDateTime, 0) / 1000;
  127. }
  128. return 0;
  129. }
  130.  
  131. get lastPartIndex(): number {
  132. if (this.partList?.length) {
  133. return this.partList[this.partList.length - 1].index;
  134. }
  135. return -1;
  136. }
  137.  
  138. get lastPartSn(): number {
  139. if (this.partList?.length) {
  140. return this.partList[this.partList.length - 1].fragment.sn as number;
  141. }
  142. return this.endSN;
  143. }
  144. }