hls.js 1.6.0-beta.2.0.canary.10844 → 1.6.0-beta.2.0.canary.10851

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.
package/package.json CHANGED
@@ -70,7 +70,7 @@
70
70
  "@babel/preset-env": "7.26.0",
71
71
  "@babel/preset-typescript": "7.26.0",
72
72
  "@babel/register": "7.25.9",
73
- "@microsoft/api-documenter": "7.26.2",
73
+ "@microsoft/api-documenter": "7.26.3",
74
74
  "@microsoft/api-extractor": "7.48.1",
75
75
  "@rollup/plugin-alias": "5.1.1",
76
76
  "@rollup/plugin-babel": "6.0.4",
@@ -130,5 +130,5 @@
130
130
  "url-toolkit": "2.2.5",
131
131
  "wrangler": "3.95.0"
132
132
  },
133
- "version": "1.6.0-beta.2.0.canary.10844"
133
+ "version": "1.6.0-beta.2.0.canary.10851"
134
134
  }
@@ -14,6 +14,7 @@ import {
14
14
  alignMediaPlaylistByPDT,
15
15
  } from '../utils/discontinuities';
16
16
  import { mediaAttributesIdentical } from '../utils/media-option-attributes';
17
+ import { useAlternateAudio } from '../utils/rendition-helper';
17
18
  import type { FragmentTracker } from './fragment-tracker';
18
19
  import type Hls from '../hls';
19
20
  import type { Fragment, MediaFragment, Part } from '../loader/fragment';
@@ -519,7 +520,7 @@ class AudioStreamController
519
520
  const cachedTrackLoadedData = this.cachedTrackLoadedData;
520
521
  if (cachedTrackLoadedData) {
521
522
  this.cachedTrackLoadedData = null;
522
- this.hls.trigger(Events.AUDIO_TRACK_LOADED, cachedTrackLoadedData);
523
+ this.onAudioTrackLoaded(Events.AUDIO_TRACK_LOADED, cachedTrackLoadedData);
523
524
  }
524
525
  }
525
526
 
@@ -528,12 +529,18 @@ class AudioStreamController
528
529
  data: TrackLoadedData,
529
530
  ) {
530
531
  const { levels } = this;
531
- const { details: newDetails, id: trackId } = data;
532
+ const { details: newDetails, id: trackId, groupId, track } = data;
533
+ if (!levels) {
534
+ this.warn(
535
+ `Audio tracks reset while loading track ${trackId} "${track.name}" of "${groupId}"`,
536
+ );
537
+ return;
538
+ }
532
539
  const mainDetails = this.mainDetails;
533
540
  if (
534
541
  !mainDetails ||
535
- mainDetails.expired ||
536
- newDetails.endCC > mainDetails.endCC
542
+ newDetails.endCC > mainDetails.endCC ||
543
+ mainDetails.expired
537
544
  ) {
538
545
  this.cachedTrackLoadedData = data;
539
546
  if (this.state !== State.STOPPED) {
@@ -541,12 +548,9 @@ class AudioStreamController
541
548
  }
542
549
  return;
543
550
  }
544
- if (!levels) {
545
- this.warn(`Audio tracks were reset while loading level ${trackId}`);
546
- return;
547
- }
551
+ this.cachedTrackLoadedData = null;
548
552
  this.log(
549
- `Audio track ${trackId} loaded [${newDetails.startSN},${
553
+ `Audio track ${trackId} "${track.name}" of "${groupId}" loaded [${newDetails.startSN},${
550
554
  newDetails.endSN
551
555
  }]${
552
556
  newDetails.lastPartSn
@@ -555,18 +559,18 @@ class AudioStreamController
555
559
  },duration:${newDetails.totalduration}`,
556
560
  );
557
561
 
558
- const track = levels[trackId];
562
+ const trackLevel = levels[trackId];
559
563
  let sliding = 0;
560
- if (newDetails.live || track.details?.live) {
564
+ if (newDetails.live || trackLevel.details?.live) {
561
565
  this.checkLiveUpdate(newDetails);
562
566
  if (newDetails.deltaUpdateFailed) {
563
567
  return;
564
568
  }
565
569
 
566
- if (track.details) {
570
+ if (trackLevel.details) {
567
571
  sliding = this.alignPlaylists(
568
572
  newDetails,
569
- track.details,
573
+ trackLevel.details,
570
574
  this.levelLastLoaded?.details,
571
575
  );
572
576
  }
@@ -580,8 +584,8 @@ class AudioStreamController
580
584
  sliding = newDetails.fragmentStart;
581
585
  }
582
586
  }
583
- track.details = newDetails;
584
- this.levelLastLoaded = track;
587
+ trackLevel.details = newDetails;
588
+ this.levelLastLoaded = trackLevel;
585
589
 
586
590
  // compute start position if we are aligned with the main playlist
587
591
  if (!this.startFragRequested) {
@@ -1026,9 +1030,14 @@ class AudioStreamController
1026
1030
  bufferedTrack.name !== switchingTrack.name ||
1027
1031
  bufferedTrack.lang !== switchingTrack.lang)
1028
1032
  ) {
1029
- this.log('Switching audio track : flushing all audio');
1030
- super.flushMainBuffer(0, Number.POSITIVE_INFINITY, 'audio');
1031
- this.bufferedTrack = null;
1033
+ if (useAlternateAudio(switchingTrack.url, this.hls)) {
1034
+ this.log('Switching audio track : flushing all audio');
1035
+ super.flushMainBuffer(0, Number.POSITIVE_INFINITY, 'audio');
1036
+ this.bufferedTrack = null;
1037
+ } else {
1038
+ // Main is being buffered. Set bufferedTrack so that it is flushed when switching back to alt-audio
1039
+ this.bufferedTrack = switchingTrack;
1040
+ }
1032
1041
  }
1033
1042
  }
1034
1043
 
@@ -1308,7 +1308,9 @@ export default class BaseStreamController
1308
1308
  const mainStart = this.hls.startPosition;
1309
1309
  const liveSyncPosition = this.hls.liveSyncPosition;
1310
1310
  const startPosition = frag
1311
- ? (mainStart !== -1 ? mainStart : liveSyncPosition) || frag.start
1311
+ ? (mainStart !== -1 && mainStart >= start
1312
+ ? mainStart
1313
+ : liveSyncPosition) || frag.start
1312
1314
  : pos;
1313
1315
  this.log(
1314
1316
  `Setting startPosition to ${startPosition} to match initial live edge. mainStart: ${mainStart} liveSyncPosition: ${liveSyncPosition} frag.start: ${frag?.start}`,
@@ -882,12 +882,16 @@ export default class StreamController
882
882
  }
883
883
  // If switching from alt to main audio, flush all audio and trigger track switched
884
884
  if (fromAltAudio) {
885
+ this.fragmentTracker.removeAllFragments();
886
+ hls.once(Events.BUFFER_FLUSHED, () => {
887
+ this.hls?.trigger(Events.AUDIO_TRACK_SWITCHED, data);
888
+ });
885
889
  hls.trigger(Events.BUFFER_FLUSHING, {
886
890
  startOffset: 0,
887
891
  endOffset: Number.POSITIVE_INFINITY,
888
892
  type: null,
889
893
  });
890
- this.fragmentTracker.removeAllFragments();
894
+ return;
891
895
  }
892
896
  hls.trigger(Events.AUDIO_TRACK_SWITCHED, data);
893
897
  } else {
@@ -179,7 +179,7 @@ export class LevelDetails {
179
179
  }
180
180
 
181
181
  get expired(): boolean {
182
- if (this.live && this.age) {
182
+ if (this.live && this.age && this.misses < 3) {
183
183
  const playlistWindowDuration = this.partEnd - this.fragmentStart;
184
184
  return (
185
185
  this.age >
@@ -184,8 +184,9 @@ class PassThroughRemuxer implements Remuxer {
184
184
  const startDTS = getStartDTS(initData, data);
185
185
  const decodeTime = startDTS === null ? timeOffset : startDTS;
186
186
  if (
187
- isInvalidInitPts(initPTS, decodeTime, timeOffset, duration) ||
188
- (initSegment.timescale !== initPTS.timescale && accurateTimeOffset)
187
+ (accurateTimeOffset || !initPTS) &&
188
+ (isInvalidInitPts(initPTS, decodeTime, timeOffset, duration) ||
189
+ initSegment.timescale !== initPTS.timescale)
189
190
  ) {
190
191
  initSegment.initPTS = decodeTime - timeOffset;
191
192
  if (initPTS && initPTS.timescale === 1) {
@@ -136,7 +136,10 @@ export function updateFragPTSDTS(
136
136
  export function mergeDetails(
137
137
  oldDetails: LevelDetails,
138
138
  newDetails: LevelDetails,
139
- ): void {
139
+ ) {
140
+ if (oldDetails === newDetails) {
141
+ return;
142
+ }
140
143
  // Track the last initSegment processed. Initialize it to the last one on the timeline.
141
144
  let currentInitSegment: Fragment | null = null;
142
145
  const oldFragments = oldDetails.fragments;
@@ -502,6 +502,9 @@ function searchDownAndUpList(
502
502
  return -1;
503
503
  }
504
504
 
505
- export function useAlternateAudio(audioTrackUrl: string, hls: Hls): boolean {
505
+ export function useAlternateAudio(
506
+ audioTrackUrl: string | undefined,
507
+ hls: Hls,
508
+ ): boolean {
506
509
  return !!audioTrackUrl && audioTrackUrl !== hls.levels[hls.loadLevel]?.uri;
507
510
  }