hls.js 1.5.14-0.canary.10515 → 1.5.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +3 -4
  2. package/dist/hls-demo.js +38 -41
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +2903 -4542
  5. package/dist/hls.js.d.ts +112 -186
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +2284 -3295
  8. package/dist/hls.light.js.map +1 -1
  9. package/dist/hls.light.min.js +1 -1
  10. package/dist/hls.light.min.js.map +1 -1
  11. package/dist/hls.light.mjs +1804 -2817
  12. package/dist/hls.light.mjs.map +1 -1
  13. package/dist/hls.min.js +1 -1
  14. package/dist/hls.min.js.map +1 -1
  15. package/dist/hls.mjs +4652 -6293
  16. package/dist/hls.mjs.map +1 -1
  17. package/dist/hls.worker.js +1 -1
  18. package/dist/hls.worker.js.map +1 -1
  19. package/package.json +38 -38
  20. package/src/config.ts +2 -5
  21. package/src/controller/abr-controller.ts +25 -39
  22. package/src/controller/audio-stream-controller.ts +136 -156
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +10 -27
  25. package/src/controller/base-stream-controller.ts +107 -263
  26. package/src/controller/buffer-controller.ts +98 -252
  27. package/src/controller/buffer-operation-queue.ts +19 -16
  28. package/src/controller/cap-level-controller.ts +2 -3
  29. package/src/controller/cmcd-controller.ts +14 -51
  30. package/src/controller/content-steering-controller.ts +15 -29
  31. package/src/controller/eme-controller.ts +23 -10
  32. package/src/controller/error-controller.ts +22 -28
  33. package/src/controller/fps-controller.ts +3 -8
  34. package/src/controller/fragment-finders.ts +16 -44
  35. package/src/controller/fragment-tracker.ts +25 -58
  36. package/src/controller/gap-controller.ts +16 -43
  37. package/src/controller/id3-track-controller.ts +35 -45
  38. package/src/controller/latency-controller.ts +13 -18
  39. package/src/controller/level-controller.ts +19 -37
  40. package/src/controller/stream-controller.ts +83 -100
  41. package/src/controller/subtitle-stream-controller.ts +47 -35
  42. package/src/controller/subtitle-track-controller.ts +3 -5
  43. package/src/controller/timeline-controller.ts +22 -20
  44. package/src/crypt/aes-crypto.ts +2 -21
  45. package/src/crypt/decrypter.ts +16 -32
  46. package/src/crypt/fast-aes-key.ts +5 -28
  47. package/src/demux/audio/aacdemuxer.ts +5 -5
  48. package/src/demux/audio/ac3-demuxer.ts +4 -5
  49. package/src/demux/audio/adts.ts +4 -9
  50. package/src/demux/audio/base-audio-demuxer.ts +14 -16
  51. package/src/demux/audio/mp3demuxer.ts +3 -4
  52. package/src/demux/audio/mpegaudio.ts +1 -1
  53. package/src/demux/id3.ts +411 -0
  54. package/src/demux/inject-worker.ts +4 -38
  55. package/src/demux/mp4demuxer.ts +7 -7
  56. package/src/demux/sample-aes.ts +0 -2
  57. package/src/demux/transmuxer-interface.ts +83 -106
  58. package/src/demux/transmuxer-worker.ts +77 -111
  59. package/src/demux/transmuxer.ts +22 -46
  60. package/src/demux/tsdemuxer.ts +62 -122
  61. package/src/demux/video/avc-video-parser.ts +121 -210
  62. package/src/demux/video/base-video-parser.ts +2 -135
  63. package/src/demux/video/exp-golomb.ts +208 -0
  64. package/src/errors.ts +0 -2
  65. package/src/events.ts +1 -8
  66. package/src/exports-named.ts +1 -1
  67. package/src/hls.ts +48 -97
  68. package/src/loader/date-range.ts +5 -71
  69. package/src/loader/fragment-loader.ts +21 -23
  70. package/src/loader/fragment.ts +4 -8
  71. package/src/loader/key-loader.ts +1 -3
  72. package/src/loader/level-details.ts +6 -6
  73. package/src/loader/level-key.ts +9 -10
  74. package/src/loader/m3u8-parser.ts +144 -138
  75. package/src/loader/playlist-loader.ts +7 -5
  76. package/src/remux/mp4-generator.ts +1 -196
  77. package/src/remux/mp4-remuxer.ts +84 -55
  78. package/src/remux/passthrough-remuxer.ts +8 -23
  79. package/src/task-loop.ts +2 -5
  80. package/src/types/component-api.ts +1 -3
  81. package/src/types/demuxer.ts +0 -3
  82. package/src/types/events.ts +6 -19
  83. package/src/types/fragment-tracker.ts +2 -2
  84. package/src/types/general.ts +6 -0
  85. package/src/types/media-playlist.ts +1 -9
  86. package/src/types/remuxer.ts +1 -1
  87. package/src/utils/attr-list.ts +9 -96
  88. package/src/utils/buffer-helper.ts +31 -12
  89. package/src/utils/cea-608-parser.ts +3 -1
  90. package/src/utils/codecs.ts +5 -34
  91. package/src/utils/discontinuities.ts +47 -21
  92. package/src/utils/fetch-loader.ts +1 -1
  93. package/src/utils/hdr.ts +7 -4
  94. package/src/utils/imsc1-ttml-parser.ts +1 -1
  95. package/src/utils/keysystem-util.ts +6 -1
  96. package/src/utils/level-helper.ts +44 -71
  97. package/src/utils/logger.ts +23 -58
  98. package/src/utils/mp4-tools.ts +3 -5
  99. package/src/utils/rendition-helper.ts +74 -100
  100. package/src/utils/variable-substitution.ts +19 -0
  101. package/src/utils/webvtt-parser.ts +12 -2
  102. package/src/crypt/decrypter-aes-mode.ts +0 -4
  103. package/src/demux/video/hevc-video-parser.ts +0 -749
  104. package/src/utils/encryption-methods-util.ts +0 -21
  105. package/src/utils/hash.ts +0 -10
  106. package/src/utils/utf8-utils.ts +0 -18
  107. package/src/version.ts +0 -1
@@ -1,4 +1,4 @@
1
- import type {
1
+ import {
2
2
  ManifestLoadedData,
3
3
  ManifestParsedData,
4
4
  LevelLoadedData,
@@ -27,6 +27,8 @@ import type Hls from '../hls';
27
27
  import type { HlsUrlParameters, LevelParsed } from '../types/level';
28
28
  import type { MediaPlaylist } from '../types/media-playlist';
29
29
 
30
+ let chromeOrFirefox: boolean;
31
+
30
32
  export default class LevelController extends BasePlaylistController {
31
33
  private _levels: Level[] = [];
32
34
  private _firstLevel: number = -1;
@@ -43,7 +45,7 @@ export default class LevelController extends BasePlaylistController {
43
45
  hls: Hls,
44
46
  contentSteeringController: ContentSteeringController | null,
45
47
  ) {
46
- super(hls, 'level-controller');
48
+ super(hls, '[level-controller]');
47
49
  this.steering = contentSteeringController;
48
50
  this._registerListeners();
49
51
  }
@@ -117,12 +119,22 @@ export default class LevelController extends BasePlaylistController {
117
119
 
118
120
  data.levels.forEach((levelParsed: LevelParsed) => {
119
121
  const attributes = levelParsed.attrs;
122
+
123
+ // erase audio codec info if browser does not support mp4a.40.34.
124
+ // demuxer will autodetect codec and fallback to mpeg/audio
120
125
  let { audioCodec, videoCodec } = levelParsed;
126
+ if (audioCodec?.indexOf('mp4a.40.34') !== -1) {
127
+ chromeOrFirefox ||= /chrome|firefox/i.test(navigator.userAgent);
128
+ if (chromeOrFirefox) {
129
+ levelParsed.audioCodec = audioCodec = undefined;
130
+ }
131
+ }
132
+
121
133
  if (audioCodec) {
122
- // Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
123
- levelParsed.audioCodec = audioCodec =
124
- getCodecCompatibleName(audioCodec, preferManagedMediaSource) ||
125
- undefined;
134
+ levelParsed.audioCodec = audioCodec = getCodecCompatibleName(
135
+ audioCodec,
136
+ preferManagedMediaSource,
137
+ );
126
138
  }
127
139
 
128
140
  if (videoCodec?.indexOf('avc1') === 0) {
@@ -509,30 +521,6 @@ export default class LevelController extends BasePlaylistController {
509
521
  this._startLevel = newLevel;
510
522
  }
511
523
 
512
- get pathwayPriority(): string[] | null {
513
- if (this.steering) {
514
- return this.steering.pathwayPriority;
515
- }
516
-
517
- return null;
518
- }
519
-
520
- set pathwayPriority(pathwayPriority: string[]) {
521
- if (this.steering) {
522
- const pathwaysList = this.steering.pathways();
523
- const filteredPathwayPriority = pathwayPriority.filter((pathwayId) => {
524
- return pathwaysList.indexOf(pathwayId) !== -1;
525
- });
526
- if (pathwayPriority.length < 1) {
527
- this.warn(
528
- `pathwayPriority ${pathwayPriority} should contain at least one pathway from list: ${pathwaysList}`,
529
- );
530
- return;
531
- }
532
- this.steering.pathwayPriority = filteredPathwayPriority;
533
- }
534
- }
535
-
536
524
  protected onError(event: Events.ERROR, data: ErrorData) {
537
525
  if (data.fatal || !data.context) {
538
526
  return;
@@ -584,13 +572,7 @@ export default class LevelController extends BasePlaylistController {
584
572
  if (curLevel.fragmentError === 0) {
585
573
  curLevel.loadError = 0;
586
574
  }
587
- // Ignore matching details populated by loading a Media Playlist directly
588
- let previousDetails = curLevel.details;
589
- if (previousDetails === data.details && previousDetails.advanced) {
590
- previousDetails = undefined;
591
- }
592
-
593
- this.playlistLoaded(level, data, previousDetails);
575
+ this.playlistLoaded(level, data, curLevel.details);
594
576
  } else if (data.deliveryDirectives?.skip) {
595
577
  // received a delta playlist update that cannot be merged
596
578
  details.deltaUpdateFailed = true;
@@ -2,14 +2,9 @@ import BaseStreamController, { State } from './base-stream-controller';
2
2
  import { changeTypeSupported } from '../is-supported';
3
3
  import { Events } from '../events';
4
4
  import { BufferHelper, BufferInfo } from '../utils/buffer-helper';
5
- import { findFragmentByPTS } from './fragment-finders';
6
5
  import { FragmentState } from './fragment-tracker';
7
6
  import { PlaylistContextType, PlaylistLevelType } from '../types/loader';
8
- import {
9
- ElementaryStreamTypes,
10
- Fragment,
11
- MediaFragment,
12
- } from '../loader/fragment';
7
+ import { ElementaryStreamTypes, Fragment } from '../loader/fragment';
13
8
  import TransmuxerInterface from '../demux/transmuxer-interface';
14
9
  import { ChunkMetadata } from '../types/transmuxer';
15
10
  import GapController, { MAX_START_GAP_JUMP } from './gap-controller';
@@ -17,15 +12,15 @@ import { ErrorDetails } from '../errors';
17
12
  import type { NetworkComponentAPI } from '../types/component-api';
18
13
  import type Hls from '../hls';
19
14
  import type { Level } from '../types/level';
15
+ import type { LevelDetails } from '../loader/level-details';
20
16
  import type { FragmentTracker } from './fragment-tracker';
21
17
  import type KeyLoader from '../loader/key-loader';
22
18
  import type { TransmuxerResult } from '../types/transmuxer';
23
- import type { Track, TrackSet } from '../types/track';
19
+ import type { TrackSet } from '../types/track';
24
20
  import type { SourceBufferName } from '../types/buffer';
25
21
  import type {
26
22
  AudioTrackSwitchedData,
27
23
  AudioTrackSwitchingData,
28
- BufferCodecsData,
29
24
  BufferCreatedData,
30
25
  BufferEOSData,
31
26
  BufferFlushedData,
@@ -54,6 +49,8 @@ export default class StreamController
54
49
  private altAudio: boolean = false;
55
50
  private audioOnly: boolean = false;
56
51
  private fragPlaying: Fragment | null = null;
52
+ private onvplaying: EventListener | null = null;
53
+ private onvseeked: EventListener | null = null;
57
54
  private fragLastKbps: number = 0;
58
55
  private couldBacktrack: boolean = false;
59
56
  private backtrackFragment: Fragment | null = null;
@@ -69,15 +66,17 @@ export default class StreamController
69
66
  hls,
70
67
  fragmentTracker,
71
68
  keyLoader,
72
- 'stream-controller',
69
+ '[stream-controller]',
73
70
  PlaylistLevelType.MAIN,
74
71
  );
75
- this.registerListeners();
72
+ this._registerListeners();
76
73
  }
77
74
 
78
- protected registerListeners() {
79
- super.registerListeners();
75
+ private _registerListeners() {
80
76
  const { hls } = this;
77
+ hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
78
+ hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
79
+ hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
81
80
  hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
82
81
  hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
83
82
  hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
@@ -86,6 +85,7 @@ export default class StreamController
86
85
  this.onFragLoadEmergencyAborted,
87
86
  this,
88
87
  );
88
+ hls.on(Events.ERROR, this.onError, this);
89
89
  hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
90
90
  hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
91
91
  hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -94,9 +94,11 @@ export default class StreamController
94
94
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
95
95
  }
96
96
 
97
- protected unregisterListeners() {
98
- super.unregisterListeners();
97
+ protected _unregisterListeners() {
99
98
  const { hls } = this;
99
+ hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
100
+ hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
101
+ hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
100
102
  hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
101
103
  hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
102
104
  hls.off(
@@ -104,6 +106,7 @@ export default class StreamController
104
106
  this.onFragLoadEmergencyAborted,
105
107
  this,
106
108
  );
109
+ hls.off(Events.ERROR, this.onError, this);
107
110
  hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
108
111
  hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
109
112
  hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -113,9 +116,7 @@ export default class StreamController
113
116
  }
114
117
 
115
118
  protected onHandlerDestroying() {
116
- // @ts-ignore
117
- this.onMediaPlaying = this.onMediaSeeked = null;
118
- this.unregisterListeners();
119
+ this._unregisterListeners();
119
120
  super.onHandlerDestroying();
120
121
  }
121
122
 
@@ -219,9 +220,6 @@ export default class StreamController
219
220
  }
220
221
 
221
222
  private doTickIdle() {
222
- if (!this.buffering) {
223
- return;
224
- }
225
223
  const { hls, levelLastLoaded, levels, media } = this;
226
224
 
227
225
  // if start level not parsed yet OR
@@ -365,6 +363,7 @@ export default class StreamController
365
363
  ) {
366
364
  // Check if fragment is not loaded
367
365
  const fragState = this.fragmentTracker.getState(frag);
366
+ this.fragCurrent = frag;
368
367
  if (
369
368
  fragState === FragmentState.NOT_LOADED ||
370
369
  fragState === FragmentState.PARTIAL
@@ -377,6 +376,7 @@ export default class StreamController
377
376
  );
378
377
  this._loadBitrateTestFrag(frag, level);
379
378
  } else {
379
+ this.startFragRequested = true;
380
380
  super.loadFragment(frag, level, targetBufferTime);
381
381
  }
382
382
  } else {
@@ -516,8 +516,10 @@ export default class StreamController
516
516
  ) {
517
517
  super.onMediaAttached(event, data);
518
518
  const media = data.media;
519
- media.addEventListener('playing', this.onMediaPlaying);
520
- media.addEventListener('seeked', this.onMediaSeeked);
519
+ this.onvplaying = this.onMediaPlaying.bind(this);
520
+ this.onvseeked = this.onMediaSeeked.bind(this);
521
+ media.addEventListener('playing', this.onvplaying as EventListener);
522
+ media.addEventListener('seeked', this.onvseeked as EventListener);
521
523
  this.gapController = new GapController(
522
524
  this.config,
523
525
  media,
@@ -528,11 +530,12 @@ export default class StreamController
528
530
 
529
531
  protected onMediaDetaching() {
530
532
  const { media } = this;
531
- if (media) {
532
- media.removeEventListener('playing', this.onMediaPlaying);
533
- media.removeEventListener('seeked', this.onMediaSeeked);
533
+ if (media && this.onvplaying && this.onvseeked) {
534
+ media.removeEventListener('playing', this.onvplaying);
535
+ media.removeEventListener('seeked', this.onvseeked);
536
+ this.onvplaying = this.onvseeked = null;
537
+ this.videoBuffer = null;
534
538
  }
535
- this.videoBuffer = null;
536
539
  this.fragPlaying = null;
537
540
  if (this.gapController) {
538
541
  this.gapController.destroy();
@@ -541,12 +544,12 @@ export default class StreamController
541
544
  super.onMediaDetaching();
542
545
  }
543
546
 
544
- private onMediaPlaying = () => {
547
+ private onMediaPlaying() {
545
548
  // tick to speed up FRAG_CHANGED triggering
546
549
  this.tick();
547
- };
550
+ }
548
551
 
549
- private onMediaSeeked = () => {
552
+ private onMediaSeeked() {
550
553
  const media = this.media;
551
554
  const currentTime = media ? media.currentTime : null;
552
555
  if (Number.isFinite(currentTime)) {
@@ -566,17 +569,21 @@ export default class StreamController
566
569
 
567
570
  // tick to speed up FRAG_CHANGED triggering
568
571
  this.tick();
569
- };
572
+ }
570
573
 
571
- protected onManifestLoading() {
572
- super.onManifestLoading();
574
+ private onManifestLoading() {
573
575
  // reset buffer on manifest loading
574
576
  this.log('Trigger BUFFER_RESET');
575
577
  this.hls.trigger(Events.BUFFER_RESET, undefined);
578
+ this.fragmentTracker.removeAllFragments();
576
579
  this.couldBacktrack = false;
577
- this.fragLastKbps = 0;
578
- this.fragPlaying = this.backtrackFragment = null;
579
- this.altAudio = this.audioOnly = false;
580
+ this.startPosition = this.lastCurrentTime = this.fragLastKbps = 0;
581
+ this.levels =
582
+ this.fragPlaying =
583
+ this.backtrackFragment =
584
+ this.levelLastLoaded =
585
+ null;
586
+ this.altAudio = this.audioOnly = this.startFragRequested = false;
580
587
  }
581
588
 
582
589
  private onManifestParsed(
@@ -690,8 +697,7 @@ export default class StreamController
690
697
  }
691
698
 
692
699
  protected _handleFragmentLoadProgress(data: FragLoadedData) {
693
- const frag = data.frag as MediaFragment;
694
- const { part, payload } = data;
700
+ const { frag, part, payload } = data;
695
701
  const { levels } = this;
696
702
  if (!levels) {
697
703
  this.warn(
@@ -700,7 +706,7 @@ export default class StreamController
700
706
  return;
701
707
  }
702
708
  const currentLevel = levels[frag.level];
703
- const details = currentLevel.details;
709
+ const details = currentLevel.details as LevelDetails;
704
710
  if (!details) {
705
711
  this.warn(
706
712
  `Dropping fragment ${frag.sn} of level ${frag.level} after level details were reset`,
@@ -729,7 +735,7 @@ export default class StreamController
729
735
  const partial = partIndex !== -1;
730
736
  const chunkMeta = new ChunkMetadata(
731
737
  frag.level,
732
- frag.sn,
738
+ frag.sn as number,
733
739
  frag.stats.chunkCount,
734
740
  payload.byteLength,
735
741
  partIndex,
@@ -873,12 +879,12 @@ export default class StreamController
873
879
  (8 * stats.total) / (stats.buffering.end - stats.loading.first),
874
880
  );
875
881
  if (frag.sn !== 'initSegment') {
876
- this.fragPrevious = frag as MediaFragment;
882
+ this.fragPrevious = frag;
877
883
  }
878
884
  this.fragBufferedComplete(frag, part);
879
885
  }
880
886
 
881
- protected onError(event: Events.ERROR, data: ErrorData) {
887
+ private onError(event: Events.ERROR, data: ErrorData) {
882
888
  if (data.fatal) {
883
889
  this.state = State.ERROR;
884
890
  return;
@@ -936,10 +942,8 @@ export default class StreamController
936
942
 
937
943
  if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
938
944
  // Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
939
- const state = this.state;
940
- const activeFrag = state !== State.IDLE ? this.fragCurrent : null;
941
- const levelDetails = this.getLevelDetails();
942
- gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
945
+ const activeFrag = this.state !== State.IDLE ? this.fragCurrent : null;
946
+ gapController.poll(this.lastCurrentTime, activeFrag);
943
947
  }
944
948
 
945
949
  this.lastCurrentTime = media.currentTime;
@@ -951,7 +955,7 @@ export default class StreamController
951
955
  // in that case, reset startFragRequested flag
952
956
  if (!this.loadedmetadata) {
953
957
  this.startFragRequested = false;
954
- this.nextLoadPosition = this.lastCurrentTime;
958
+ this.nextLoadPosition = this.startPosition;
955
959
  }
956
960
  this.tickImmediate();
957
961
  }
@@ -1063,7 +1067,7 @@ export default class StreamController
1063
1067
  }
1064
1068
 
1065
1069
  private _handleTransmuxComplete(transmuxResult: TransmuxerResult) {
1066
- const id = this.playlistType;
1070
+ const id = 'main';
1067
1071
  const { hls } = this;
1068
1072
  const { remuxResult, chunkMeta } = transmuxResult;
1069
1073
 
@@ -1113,7 +1117,7 @@ export default class StreamController
1113
1117
  }
1114
1118
 
1115
1119
  // Avoid buffering if backtracking this fragment
1116
- if (video && details) {
1120
+ if (video && details && frag.sn !== 'initSegment') {
1117
1121
  const prevFrag = details.fragments[frag.sn - 1 - details.startSN];
1118
1122
  const isFirstFragment = frag.sn === details.startSN;
1119
1123
  const isFirstInDiscontinuity = !prevFrag || frag.cc > prevFrag.cc;
@@ -1303,7 +1307,6 @@ export default class StreamController
1303
1307
  currentLevel.audioCodec || ''
1304
1308
  }/${audio.codec}]`,
1305
1309
  );
1306
- delete tracks.audiovideo;
1307
1310
  }
1308
1311
  if (video) {
1309
1312
  video.levelCodec = currentLevel.videoCodec;
@@ -1315,34 +1318,28 @@ export default class StreamController
1315
1318
  video.codec
1316
1319
  }]`,
1317
1320
  );
1318
- delete tracks.audiovideo;
1319
1321
  }
1320
1322
  if (audiovideo) {
1321
1323
  this.log(
1322
1324
  `Init audiovideo buffer, container:${audiovideo.container}, codecs[level/parsed]=[${currentLevel.codecs}/${audiovideo.codec}]`,
1323
1325
  );
1324
- delete tracks.video;
1325
- delete tracks.audio;
1326
- }
1327
- const trackTypes = Object.keys(tracks);
1328
- if (trackTypes.length) {
1329
- this.hls.trigger(Events.BUFFER_CODECS, tracks as BufferCodecsData);
1330
- // loop through tracks that are going to be provided to bufferController
1331
- trackTypes.forEach((trackName) => {
1332
- const track = tracks[trackName] as Track;
1333
- const initSegment = track.initSegment;
1334
- if (initSegment?.byteLength) {
1335
- this.hls.trigger(Events.BUFFER_APPENDING, {
1336
- type: trackName as SourceBufferName,
1337
- data: initSegment,
1338
- frag,
1339
- part: null,
1340
- chunkMeta,
1341
- parent: frag.type,
1342
- });
1343
- }
1344
- });
1345
1326
  }
1327
+ this.hls.trigger(Events.BUFFER_CODECS, tracks);
1328
+ // loop through tracks that are going to be provided to bufferController
1329
+ Object.keys(tracks).forEach((trackName) => {
1330
+ const track = tracks[trackName];
1331
+ const initSegment = track.initSegment;
1332
+ if (initSegment?.byteLength) {
1333
+ this.hls.trigger(Events.BUFFER_APPENDING, {
1334
+ type: trackName as SourceBufferName,
1335
+ data: initSegment,
1336
+ frag,
1337
+ part: null,
1338
+ chunkMeta,
1339
+ parent: frag.type,
1340
+ });
1341
+ }
1342
+ });
1346
1343
  // trigger handler right now
1347
1344
  this.tickImmediate();
1348
1345
  }
@@ -1354,15 +1351,6 @@ export default class StreamController
1354
1351
  );
1355
1352
  }
1356
1353
 
1357
- public get maxBufferLength(): number {
1358
- const { levels, level } = this;
1359
- const levelInfo = levels?.[level];
1360
- if (!levelInfo) {
1361
- return this.config.maxBufferLength;
1362
- }
1363
- return this.getMaxBufferLength(levelInfo.maxBitrate);
1364
- }
1365
-
1366
1354
  private backtrack(frag: Fragment) {
1367
1355
  this.couldBacktrack = true;
1368
1356
  // Causes findFragments to backtrack through fragments to find the keyframe
@@ -1427,31 +1415,26 @@ export default class StreamController
1427
1415
  }
1428
1416
 
1429
1417
  get currentFrag(): Fragment | null {
1430
- if (this.fragPlaying) {
1431
- return this.fragPlaying;
1432
- }
1433
- const currentTime = this.media?.currentTime || this.lastCurrentTime;
1434
- if (Number.isFinite(currentTime)) {
1435
- return this.getAppendedFrag(currentTime);
1418
+ const media = this.media;
1419
+ if (media) {
1420
+ return this.fragPlaying || this.getAppendedFrag(media.currentTime);
1436
1421
  }
1437
1422
  return null;
1438
1423
  }
1439
1424
 
1440
1425
  get currentProgramDateTime(): Date | null {
1441
- const currentTime = this.media?.currentTime || this.lastCurrentTime;
1442
- if (Number.isFinite(currentTime)) {
1443
- const details = this.getLevelDetails();
1444
- const frag =
1445
- this.currentFrag ||
1446
- (details
1447
- ? findFragmentByPTS(null, details.fragments, currentTime)
1448
- : null);
1449
- if (frag) {
1450
- const programDateTime = frag.programDateTime;
1451
- if (programDateTime !== null) {
1452
- const epocMs = programDateTime + (currentTime - frag.start) * 1000;
1453
- return new Date(epocMs);
1454
- }
1426
+ const media = this.media;
1427
+ if (media) {
1428
+ const currentTime = media.currentTime;
1429
+ const frag = this.currentFrag;
1430
+ if (
1431
+ frag &&
1432
+ Number.isFinite(currentTime) &&
1433
+ Number.isFinite(frag.programDateTime)
1434
+ ) {
1435
+ const epocMs =
1436
+ (frag.programDateTime as number) + (currentTime - frag.start) * 1000;
1437
+ return new Date(epocMs);
1455
1438
  }
1456
1439
  }
1457
1440
  return null;