Skip to content

Commit

Permalink
Fix audio and subtitle controller loading before player seeks to star…
Browse files Browse the repository at this point in the history
…tPosition (VOD) - v1.2.9 (#5098)

Fixes #5083
  • Loading branch information
robwalch committed Dec 8, 2022
1 parent fb7a4c5 commit fb0a574
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 24 deletions.
11 changes: 5 additions & 6 deletions src/controller/audio-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,6 @@ class AudioStreamController
// Exit early if we don't have media or if the media hasn't buffered anything yet (readyState 0)
return;
}
const mediaBuffer = this.mediaBuffer ? this.mediaBuffer : media;
const buffered = mediaBuffer.buffered;

if (!this.loadedmetadata && buffered.length) {
this.loadedmetadata = true;
}

this.lastCurrentTime = media.currentTime;
}
Expand Down Expand Up @@ -599,6 +593,11 @@ class AudioStreamController
onFragBuffered(event: Events.FRAG_BUFFERED, data: FragBufferedData) {
const { frag, part } = data;
if (frag.type !== PlaylistLevelType.AUDIO) {
if (!this.loadedmetadata && frag.type === PlaylistLevelType.MAIN) {
if ((this.videoBuffer || this.media)?.buffered.length) {
this.loadedmetadata = true;
}
}
return;
}
if (this.fragContextChanged(frag)) {
Expand Down
30 changes: 19 additions & 11 deletions src/controller/base-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,22 +225,29 @@ export default class BaseStreamController

if (state === State.ENDED) {
this.resetLoadingState();
} else if (fragCurrent && !bufferInfo.len) {
// check if we are seeking to a unbuffered area AND if frag loading is in progress
} else if (fragCurrent) {
// Seeking while frag load is in progress
const tolerance = config.maxFragLookUpTolerance;
const fragStartOffset = fragCurrent.start - tolerance;
const fragEndOffset =
fragCurrent.start + fragCurrent.duration + tolerance;
const pastFragment = currentTime > fragEndOffset;
// check if the seek position is past current fragment, and if so abort loading
if (currentTime < fragStartOffset || pastFragment) {
if (pastFragment && fragCurrent.loader) {
this.log(
'seeking outside of buffer while fragment load in progress, cancel fragment load'
);
fragCurrent.loader.abort();
// if seeking out of buffered range or into new one
if (
!bufferInfo.len ||
fragEndOffset < bufferInfo.start ||
fragStartOffset > bufferInfo.end
) {
const pastFragment = currentTime > fragEndOffset;
// if the seek position is outside the current fragment range
if (currentTime < fragStartOffset || pastFragment) {
if (pastFragment && fragCurrent.loader) {
this.log(
'seeking outside of buffer while fragment load in progress, cancel fragment load'
);
fragCurrent.loader.abort();
}
this.resetLoadingState();
}
this.resetLoadingState();
}
}

Expand Down Expand Up @@ -520,6 +527,7 @@ export default class BaseStreamController
}
if (
!this.loadedmetadata &&
frag.type == PlaylistLevelType.MAIN &&
media.buffered.length &&
this.fragCurrent?.sn === this.fragPrevious?.sn
) {
Expand Down
54 changes: 47 additions & 7 deletions src/controller/subtitle-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
TrackSwitchedData,
BufferFlushingData,
LevelLoadedData,
FragBufferedData,
} from '../types/events';

const TICK_INTERVAL = 500; // how often to tick in ms
Expand Down Expand Up @@ -62,6 +63,7 @@ export class SubtitleStreamController
hls.on(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this);
hls.on(Events.SUBTITLE_FRAG_PROCESSED, this.onSubtitleFragProcessed, this);
hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
}

private _unregisterListeners() {
Expand All @@ -76,13 +78,20 @@ export class SubtitleStreamController
hls.off(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this);
hls.off(Events.SUBTITLE_FRAG_PROCESSED, this.onSubtitleFragProcessed, this);
hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
}

startLoad() {
startLoad(startPosition: number) {
this.stopLoad();
this.state = State.IDLE;

this.setInterval(TICK_INTERVAL);

this.nextLoadPosition =
this.startPosition =
this.lastCurrentTime =
startPosition;

this.tick();
}

Expand Down Expand Up @@ -174,6 +183,14 @@ export class SubtitleStreamController
}
}

onFragBuffered(event: Events.FRAG_BUFFERED, data: FragBufferedData) {
if (!this.loadedmetadata && data.frag.type === PlaylistLevelType.MAIN) {
if (this.media?.buffered.length) {
this.loadedmetadata = true;
}
}
}

// If something goes wrong, proceed to next frag, if we were processing one.
onError(event: Events.ERROR, data: ErrorData) {
const frag = data.frag;
Expand Down Expand Up @@ -244,6 +261,7 @@ export class SubtitleStreamController
return;
}
this.mediaBuffer = this.mediaBufferTimeRanges;
let sliding = 0;
if (newDetails.live || track.details?.live) {
const mainDetails = this.mainDetails;
if (newDetails.deltaUpdateFailed || !mainDetails) {
Expand All @@ -253,21 +271,28 @@ export class SubtitleStreamController
if (!track.details) {
if (newDetails.hasProgramDateTime && mainDetails.hasProgramDateTime) {
alignMediaPlaylistByPDT(newDetails, mainDetails);
sliding = newDetails.fragments[0].start;
} else if (mainSlidingStartFragment) {
// line up live playlist with main so that fragments in range are loaded
addSliding(newDetails, mainSlidingStartFragment.start);
sliding = mainSlidingStartFragment.start;
addSliding(newDetails, sliding);
}
} else {
const sliding = this.alignPlaylists(newDetails, track.details);
sliding = this.alignPlaylists(newDetails, track.details);
if (sliding === 0 && mainSlidingStartFragment) {
// realign with main when there is no overlap with last refresh
addSliding(newDetails, mainSlidingStartFragment.start);
sliding = mainSlidingStartFragment.start;
addSliding(newDetails, sliding);
}
}
}
track.details = newDetails;
this.levelLastLoaded = trackId;

if (!this.startFragRequested && (this.mainDetails || !newDetails.live)) {
this.setStartPosition(track.details, sliding);
}

// trigger handler right now
this.tick();

Expand Down Expand Up @@ -349,15 +374,21 @@ export class SubtitleStreamController
// Expand range of subs loaded by one target-duration in either direction to make up for misaligned playlists
const trackDetails = levels[currentTrackId].details as LevelDetails;
const targetDuration = trackDetails.targetduration;
const { config, media } = this;
const { config } = this;
const currentTime = this.getLoadPosition();
const bufferedInfo = BufferHelper.bufferedInfo(
this.tracksBuffered[this.currentTrackId] || [],
media.currentTime - targetDuration,
currentTime - targetDuration,
config.maxBufferHole
);
const { end: targetBufferTime, len: bufferLen } = bufferedInfo;

const maxBufLen = this.getMaxBufferLength() + targetDuration;
const mainBufferInfo = this.getFwdBufferInfo(
this.media,
PlaylistLevelType.MAIN
);
const maxBufLen =
this.getMaxBufferLength(mainBufferInfo?.len) + targetDuration;

if (bufferLen > maxBufLen) {
return;
Expand Down Expand Up @@ -412,6 +443,14 @@ export class SubtitleStreamController
}
}

protected getMaxBufferLength(mainBufferLength?: number): number {
const maxConfigBuffer = super.getMaxBufferLength();
if (!mainBufferLength) {
return maxConfigBuffer;
}
return Math.max(maxConfigBuffer, mainBufferLength);
}

protected loadFragment(
frag: Fragment,
levelDetails: LevelDetails,
Expand All @@ -421,6 +460,7 @@ export class SubtitleStreamController
if (frag.sn === 'initSegment') {
this._loadInitSegment(frag);
} else {
this.startFragRequested = true;
super.loadFragment(frag, levelDetails, targetBufferTime);
}
}
Expand Down

0 comments on commit fb0a574

Please sign in to comment.