Home Reference Source

src/loader/level-details.ts

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