Skip to content

Commit

Permalink
Use last discontinuity bounds when aligning playlists on PDT
Browse files Browse the repository at this point in the history
Realign audio playlist when waiting for initPTS
Deprecate redundant align PDT method
  • Loading branch information
robwalch committed Jul 21, 2023
1 parent 0cb2781 commit 3f9cbf4
Show file tree
Hide file tree
Showing 3 changed files with 282 additions and 126 deletions.
7 changes: 7 additions & 0 deletions src/controller/audio-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,13 @@ class AudioStreamController
`Waiting for video PTS in continuity counter ${frag.cc} of live stream before loading audio fragment ${frag.sn} of level ${this.trackId}`
);
this.state = State.WAITING_INIT_PTS;
const mainDetails = this.mainDetails;
if (
mainDetails &&
mainDetails.fragments[0].start !== track.details.fragments[0].start
) {
alignMediaPlaylistByPDT(track.details, mainDetails);
}
} else {
this.startFragRequested = true;
super.loadFragment(frag, track, targetBufferTime);
Expand Down
79 changes: 26 additions & 53 deletions src/utils/discontinuities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@ import type { LevelDetails } from '../loader/level-details';
import type { Level } from '../types/level';
import type { RequiredProperties } from '../types/general';

export function findFirstFragWithCC(fragments: Fragment[], cc: number) {
let firstFrag: Fragment | null = null;

export function findFirstFragWithCC(
fragments: Fragment[],
cc: number
): Fragment | null {
for (let i = 0, len = fragments.length; i < len; i++) {
const currentFrag = fragments[i];
if (currentFrag && currentFrag.cc === cc) {
firstFrag = currentFrag;
break;
if (fragments[i]?.cc === cc) {
return fragments[i];
}
}

return firstFrag;
return null;
}

export function shouldAlignOnDiscontinuities(
Expand All @@ -39,8 +37,7 @@ export function shouldAlignOnDiscontinuities(
// Find the first frag in the previous level which matches the CC of the first frag of the new level
export function findDiscontinuousReferenceFrag(
prevDetails: LevelDetails,
curDetails: LevelDetails,
referenceIndex: number = 0
curDetails: LevelDetails
) {
const prevFrags = prevDetails.fragments;
const curFrags = curDetails.fragments;
Expand Down Expand Up @@ -104,7 +101,7 @@ export function alignStream(
// If the PTS wasn't figured out via discontinuity sequence that means there was no CC increase within the level.
// Aligning via Program Date Time should therefore be reliable, since PDT should be the same within the same
// discontinuity sequence.
alignPDT(details, lastLevel.details);
alignMediaPlaylistByPDT(details, lastLevel.details);
}
if (
!details.alignedSliding &&
Expand Down Expand Up @@ -145,40 +142,9 @@ function alignDiscontinuities(
}

/**
* Computes the PTS of a new level's fragments using the difference in Program Date Time from the last level.
* @param details - The details of the new level
* @param lastDetails - The details of the last loaded level
*/
export function alignPDT(details: LevelDetails, lastDetails: LevelDetails) {
// This check protects the unsafe "!" usage below for null program date time access.
if (
!lastDetails.fragments.length ||
!details.hasProgramDateTime ||
!lastDetails.hasProgramDateTime
) {
return;
}
// if last level sliding is 1000 and its first frag PROGRAM-DATE-TIME is 2017-08-20 1:10:00 AM
// and if new details first frag PROGRAM DATE-TIME is 2017-08-20 1:10:08 AM
// then we can deduce that playlist B sliding is 1000+8 = 1008s
const lastPDT = lastDetails.fragments[0].programDateTime!; // hasProgramDateTime check above makes this safe.
const newPDT = details.fragments[0].programDateTime!;
// date diff is in ms. frag.start is in seconds
const sliding = (newPDT - lastPDT) / 1000 + lastDetails.fragments[0].start;
if (sliding && Number.isFinite(sliding)) {
logger.log(
`Adjusting PTS using programDateTime delta ${
newPDT - lastPDT
}ms, sliding:${sliding.toFixed(3)} ${details.url} `
);
adjustSlidingStart(sliding, details);
}
}

/**
* Ensures appropriate time-alignment between renditions based on PDT. Unlike `alignPDT`, which adjusts
* the timeline based on the delta between PDTs of the 0th fragment of two playlists/`LevelDetails`,
* this function assumes the timelines represented in `refDetails` are accurate, including the PDTs,
* Ensures appropriate time-alignment between renditions based on PDT.
* This function assumes the timelines represented in `refDetails` are accurate, including the PDTs
* for the last discontinuity sequence number shared by both playlists when present,
* and uses the "wallclock"/PDT timeline as a cross-reference to `details`, adjusting the presentation
* times/timelines of `details` accordingly.
* Given the asynchronous nature of fetches and initial loads of live `main` and audio/subtitle tracks,
Expand All @@ -205,15 +171,22 @@ export function alignMediaPlaylistByPDT(
// Calculate a delta to apply to all fragments according to the delta in PDT times and start times
// of a fragment in the reference details, and a fragment in the target details of the same discontinuity.
// If a fragment of the same discontinuity was not found use the middle fragment of both.
const middleFrag = Math.round(refFragments.length / 2) - 1;
const refFrag = refFragments[middleFrag];
const frag =
findFirstFragWithCC(fragments, refFrag.cc) ||
fragments[Math.round(fragments.length / 2) - 1];

let refFrag: Fragment | null | undefined;
let frag: Fragment | null | undefined;
const targetCC = Math.min(refDetails.endCC, details.endCC);
if (refDetails.startCC < targetCC && details.startCC < targetCC) {
refFrag = findFirstFragWithCC(refFragments, targetCC);
frag = findFirstFragWithCC(fragments, targetCC);
}
if (!refFrag || !frag) {
refFrag = refFragments[Math.floor(refFragments.length / 2)];
frag =
findFirstFragWithCC(fragments, refFrag.cc) ||
fragments[Math.floor(fragments.length / 2)];
}
const refPDT = refFrag.programDateTime;
const targetPDT = frag.programDateTime;
if (refPDT === null || targetPDT === null) {
if (!refPDT || !targetPDT) {
return;
}

Expand Down
Loading

0 comments on commit 3f9cbf4

Please sign in to comment.