Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not adjust initPTS without accurate playlist time offset #6922

Merged
merged 4 commits into from
Dec 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 27 additions & 18 deletions src/controller/audio-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
alignMediaPlaylistByPDT,
} from '../utils/discontinuities';
import { mediaAttributesIdentical } from '../utils/media-option-attributes';
import { useAlternateAudio } from '../utils/rendition-helper';
import type { FragmentTracker } from './fragment-tracker';
import type Hls from '../hls';
import type { Fragment, MediaFragment, Part } from '../loader/fragment';
Expand Down Expand Up @@ -519,7 +520,7 @@ class AudioStreamController
const cachedTrackLoadedData = this.cachedTrackLoadedData;
if (cachedTrackLoadedData) {
this.cachedTrackLoadedData = null;
this.hls.trigger(Events.AUDIO_TRACK_LOADED, cachedTrackLoadedData);
this.onAudioTrackLoaded(Events.AUDIO_TRACK_LOADED, cachedTrackLoadedData);
}
}

Expand All @@ -528,25 +529,28 @@ class AudioStreamController
data: TrackLoadedData,
) {
const { levels } = this;
const { details: newDetails, id: trackId } = data;
const { details: newDetails, id: trackId, groupId, track } = data;
if (!levels) {
this.warn(
`Audio tracks reset while loading track ${trackId} "${track.name}" of "${groupId}"`,
);
return;
}
const mainDetails = this.mainDetails;
if (
!mainDetails ||
mainDetails.expired ||
newDetails.endCC > mainDetails.endCC
newDetails.endCC > mainDetails.endCC ||
mainDetails.expired
) {
this.cachedTrackLoadedData = data;
if (this.state !== State.STOPPED) {
this.state = State.WAITING_TRACK;
}
return;
}
if (!levels) {
this.warn(`Audio tracks were reset while loading level ${trackId}`);
return;
}
this.cachedTrackLoadedData = null;
this.log(
`Audio track ${trackId} loaded [${newDetails.startSN},${
`Audio track ${trackId} "${track.name}" of "${groupId}" loaded [${newDetails.startSN},${
newDetails.endSN
}]${
newDetails.lastPartSn
Expand All @@ -555,18 +559,18 @@ class AudioStreamController
},duration:${newDetails.totalduration}`,
);

const track = levels[trackId];
const trackLevel = levels[trackId];
let sliding = 0;
if (newDetails.live || track.details?.live) {
if (newDetails.live || trackLevel.details?.live) {
this.checkLiveUpdate(newDetails);
if (newDetails.deltaUpdateFailed) {
return;
}

if (track.details) {
if (trackLevel.details) {
sliding = this.alignPlaylists(
newDetails,
track.details,
trackLevel.details,
this.levelLastLoaded?.details,
);
}
Expand All @@ -580,8 +584,8 @@ class AudioStreamController
sliding = newDetails.fragmentStart;
}
}
track.details = newDetails;
this.levelLastLoaded = track;
trackLevel.details = newDetails;
this.levelLastLoaded = trackLevel;

// compute start position if we are aligned with the main playlist
if (!this.startFragRequested) {
Expand Down Expand Up @@ -1026,9 +1030,14 @@ class AudioStreamController
bufferedTrack.name !== switchingTrack.name ||
bufferedTrack.lang !== switchingTrack.lang)
) {
this.log('Switching audio track : flushing all audio');
super.flushMainBuffer(0, Number.POSITIVE_INFINITY, 'audio');
this.bufferedTrack = null;
if (useAlternateAudio(switchingTrack.url, this.hls)) {
this.log('Switching audio track : flushing all audio');
super.flushMainBuffer(0, Number.POSITIVE_INFINITY, 'audio');
this.bufferedTrack = null;
} else {
// Main is being buffered. Set bufferedTrack so that it is flushed when switching back to alt-audio
this.bufferedTrack = switchingTrack;
}
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/controller/base-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1308,7 +1308,9 @@ export default class BaseStreamController
const mainStart = this.hls.startPosition;
const liveSyncPosition = this.hls.liveSyncPosition;
const startPosition = frag
? (mainStart !== -1 ? mainStart : liveSyncPosition) || frag.start
? (mainStart !== -1 && mainStart >= start
? mainStart
: liveSyncPosition) || frag.start
: pos;
this.log(
`Setting startPosition to ${startPosition} to match initial live edge. mainStart: ${mainStart} liveSyncPosition: ${liveSyncPosition} frag.start: ${frag?.start}`,
Expand Down
6 changes: 5 additions & 1 deletion src/controller/stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -882,12 +882,16 @@ export default class StreamController
}
// If switching from alt to main audio, flush all audio and trigger track switched
if (fromAltAudio) {
this.fragmentTracker.removeAllFragments();
hls.once(Events.BUFFER_FLUSHED, () => {
this.hls?.trigger(Events.AUDIO_TRACK_SWITCHED, data);
});
hls.trigger(Events.BUFFER_FLUSHING, {
startOffset: 0,
endOffset: Number.POSITIVE_INFINITY,
type: null,
});
this.fragmentTracker.removeAllFragments();
return;
}
hls.trigger(Events.AUDIO_TRACK_SWITCHED, data);
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/loader/level-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export class LevelDetails {
}

get expired(): boolean {
if (this.live && this.age) {
if (this.live && this.age && this.misses < 3) {
const playlistWindowDuration = this.partEnd - this.fragmentStart;
return (
this.age >
Expand Down
5 changes: 3 additions & 2 deletions src/remux/passthrough-remuxer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,9 @@ class PassThroughRemuxer implements Remuxer {
const startDTS = getStartDTS(initData, data);
const decodeTime = startDTS === null ? timeOffset : startDTS;
if (
isInvalidInitPts(initPTS, decodeTime, timeOffset, duration) ||
(initSegment.timescale !== initPTS.timescale && accurateTimeOffset)
(accurateTimeOffset || !initPTS) &&
(isInvalidInitPts(initPTS, decodeTime, timeOffset, duration) ||
initSegment.timescale !== initPTS.timescale)
) {
initSegment.initPTS = decodeTime - timeOffset;
if (initPTS && initPTS.timescale === 1) {
Expand Down
5 changes: 4 additions & 1 deletion src/utils/level-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ export function updateFragPTSDTS(
export function mergeDetails(
oldDetails: LevelDetails,
newDetails: LevelDetails,
): void {
) {
if (oldDetails === newDetails) {
return;
}
// Track the last initSegment processed. Initialize it to the last one on the timeline.
let currentInitSegment: Fragment | null = null;
const oldFragments = oldDetails.fragments;
Expand Down
5 changes: 4 additions & 1 deletion src/utils/rendition-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,9 @@ function searchDownAndUpList(
return -1;
}

export function useAlternateAudio(audioTrackUrl: string, hls: Hls): boolean {
export function useAlternateAudio(
audioTrackUrl: string | undefined,
hls: Hls,
): boolean {
return !!audioTrackUrl && audioTrackUrl !== hls.levels[hls.loadLevel]?.uri;
}
Loading
Loading