Skip to content

Commit

Permalink
Re-align audio playlist with main when there is no overlap between au…
Browse files Browse the repository at this point in the history
…dio playlist updates (#6857)

* Attempt to realign audio with main when `alignPlaylists` finds no overlap in playlist updates
#6823
* Cache audio playlist responses until main playlist is alignable
* Align on starting discontinuity tag with discontinuity-sequence (startCC is discontinuity-sequence)
  • Loading branch information
robwalch authored Nov 22, 2024
1 parent e2bd637 commit ac4be62
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 28 deletions.
50 changes: 32 additions & 18 deletions src/controller/audio-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import { ElementaryStreamTypes, isMediaFragment } from '../loader/fragment';
import { Level } from '../types/level';
import { PlaylistContextType, PlaylistLevelType } from '../types/loader';
import { ChunkMetadata } from '../types/transmuxer';
import { alignMediaPlaylistByPDT } from '../utils/discontinuities';
import {
alignDiscontinuities,
alignMediaPlaylistByPDT,
} from '../utils/discontinuities';
import { mediaAttributesIdentical } from '../utils/media-option-attributes';
import type { FragmentTracker } from './fragment-tracker';
import type Hls from '../hls';
Expand Down Expand Up @@ -257,7 +260,7 @@ class AudioStreamController
this.nextLoadPosition = this.findSyncFrag(videoAnchor).start;
this.clearWaitingFragment();
}
} else if (this.state !== State.STOPPED) {
} else {
this.state = State.IDLE;
}
}
Expand Down Expand Up @@ -508,22 +511,30 @@ class AudioStreamController

private onLevelLoaded(event: Events.LEVEL_LOADED, data: LevelLoadedData) {
this.mainDetails = data.details;
if (this.cachedTrackLoadedData !== null) {
this.hls.trigger(Events.AUDIO_TRACK_LOADED, this.cachedTrackLoadedData);
const cachedTrackLoadedData = this.cachedTrackLoadedData;
if (cachedTrackLoadedData) {
this.cachedTrackLoadedData = null;
this.hls.trigger(Events.AUDIO_TRACK_LOADED, cachedTrackLoadedData);
}
}

private onAudioTrackLoaded(
event: Events.AUDIO_TRACK_LOADED,
data: TrackLoadedData,
) {
if (this.mainDetails == null) {
const { levels } = this;
const { details: newDetails, id: trackId } = data;
if (
this.mainDetails == null ||
this.mainDetails.expired ||
newDetails.endCC > this.mainDetails.endCC
) {
this.cachedTrackLoadedData = data;
if (this.state !== State.STOPPED) {
this.state = State.WAITING_TRACK;
}
return;
}
const { levels } = this;
const { details: newDetails, id: trackId } = data;
if (!levels) {
this.warn(`Audio tracks were reset while loading level ${trackId}`);
return;
Expand All @@ -546,22 +557,23 @@ class AudioStreamController
if (newDetails.deltaUpdateFailed || !mainDetails) {
return;
}
if (
!track.details &&
newDetails.hasProgramDateTime &&
mainDetails.hasProgramDateTime
) {
// Make sure our audio rendition is aligned with the "main" rendition, using
// pdt as our reference times.
alignMediaPlaylistByPDT(newDetails, mainDetails);
sliding = newDetails.fragmentStart;
} else {

if (track.details) {
sliding = this.alignPlaylists(
newDetails,
track.details,
this.levelLastLoaded?.details,
);
}
if (!newDetails.alignedSliding) {
// Align audio rendition with the "main" playlist on discontinuity change
// or program-date-time (PDT)
alignDiscontinuities(newDetails, mainDetails);
if (!newDetails.alignedSliding) {
alignMediaPlaylistByPDT(newDetails, mainDetails);
}
sliding = newDetails.fragmentStart;
}
}
track.details = newDetails;
this.levelLastLoaded = track;
Expand Down Expand Up @@ -665,7 +677,9 @@ class AudioStreamController
complete: false,
});
cache.push(new Uint8Array(payload));
this.state = State.WAITING_INIT_PTS;
if (this.state !== State.STOPPED) {
this.state = State.WAITING_INIT_PTS;
}
}
}

Expand Down
7 changes: 2 additions & 5 deletions src/controller/base-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1593,15 +1593,12 @@ export default class BaseStreamController
const firstLevelLoad = !previousDetails;
const aligned = details.alignedSliding && Number.isFinite(slidingStart);
if (firstLevelLoad || (!aligned && !slidingStart)) {
const { fragPrevious } = this;
alignStream(fragPrevious, switchDetails, details);
alignStream(switchDetails, details);
const alignedSlidingStart = details.fragmentStart;
this.log(
`Live playlist sliding: ${alignedSlidingStart.toFixed(2)} start-sn: ${
previousDetails ? previousDetails.startSN : 'na'
}->${details.startSN} prev-sn: ${
fragPrevious ? fragPrevious.sn : 'na'
} fragments: ${length}`,
}->${details.startSN} fragments: ${length}`,
);
return alignedSlidingStart;
}
Expand Down
4 changes: 2 additions & 2 deletions src/loader/m3u8-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ export default class M3U8Parser {
}

case 'DISCONTINUITY-SEQUENCE':
discontinuityCounter = parseInt(value1);
level.startCC = discontinuityCounter = parseInt(value1);
break;
case 'KEY': {
const levelKey = parseKey(value1, baseurl, level);
Expand Down Expand Up @@ -671,7 +671,7 @@ export default class M3U8Parser {
if (!level.live) {
lastFragment.endList = true;
}
if (firstFragment) {
if (firstFragment && !level.startCC) {
level.startCC = firstFragment.cc;
}
/**
Expand Down
2 changes: 0 additions & 2 deletions src/utils/discontinuities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,10 @@ export function adjustSlidingStart(sliding: number, details: LevelDetails) {
* The PTS of a fragment lets Hls.js know where it fits into a stream - by knowing every PTS, we know which fragment to
* download at any given time. PTS is normally computed when the fragment is demuxed, so taking this step saves us time
* and an extra download.
* @param lastFrag
* @param lastLevel
* @param details
*/
export function alignStream(
lastFrag: Fragment | null,
switchDetails: LevelDetails | undefined,
details: LevelDetails,
) {
Expand Down
4 changes: 3 additions & 1 deletion src/utils/level-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,9 @@ export function mergeDetails(
newDetails.fragments.shift();
}
newDetails.startSN = newDetails.fragments[0].sn;
newDetails.startCC = newDetails.fragments[0].cc;
if (!newDetails.startCC) {
newDetails.startCC = newDetails.fragments[0].cc;
}
} else {
if (newDetails.canSkipDateRanges) {
newDetails.dateRanges = mergeDateRanges(
Expand Down
Loading

0 comments on commit ac4be62

Please sign in to comment.