Skip to content

Commit

Permalink
Reset stream controller ENDED state after flushing the buffer
Browse files Browse the repository at this point in the history
Resumes streaming after level or track switch after the last segment has been appended
  • Loading branch information
Rob Walch committed Apr 14, 2021
1 parent e326e50 commit 4d98e18
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 30 deletions.
13 changes: 2 additions & 11 deletions src/controller/audio-stream-controller.ts
Expand Up @@ -648,12 +648,7 @@ class AudioStreamController
'Buffer full error also media.currentTime is not buffered, flush audio buffer'
);
this.fragCurrent = null;
// flush everything
this.hls.trigger(Events.BUFFER_FLUSHING, {
startOffset: 0,
endOffset: Number.POSITIVE_INFINITY,
type: 'audio',
});
super.flushMainBuffer(0, Number.POSITIVE_INFINITY, 'audio');
}
}
break;
Expand Down Expand Up @@ -824,11 +819,7 @@ class AudioStreamController
const { hls, media, trackId } = this;
if (media) {
this.log('Switching audio track : flushing all audio');
hls.trigger(Events.BUFFER_FLUSHING, {
startOffset: 0,
endOffset: Number.POSITIVE_INFINITY,
type: 'audio',
});
super.flushMainBuffer(0, Number.POSITIVE_INFINITY, 'audio');
}
this.audioSwitch = false;
hls.trigger(Events.AUDIO_TRACK_SWITCHED, { id: trackId });
Expand Down
30 changes: 14 additions & 16 deletions src/controller/base-stream-controller.ts
Expand Up @@ -184,7 +184,7 @@ export default class BaseStreamController

protected onMediaSeeking() {
const { config, fragCurrent, media, mediaBuffer, state } = this;
const currentTime = media ? media.currentTime : null;
const currentTime: number = media ? media.currentTime : 0;
const bufferInfo = BufferHelper.bufferInfo(
mediaBuffer || media,
currentTime,
Expand All @@ -198,13 +198,7 @@ export default class BaseStreamController
);

if (state === State.ENDED) {
// if seeking to unbuffered area, clean up fragPrevious
if (!bufferInfo.len) {
this.fragPrevious = null;
this.fragCurrent = null;
}
// switch to IDLE state to check for potential new fragment
this.state = State.IDLE;
this.resetLoadingState();
} else if (fragCurrent && !bufferInfo.len) {
// check if we are seeking to a unbuffered area AND if frag loading is in progress
const tolerance = config.maxFragLookUpTolerance;
Expand All @@ -219,10 +213,7 @@ export default class BaseStreamController
);
fragCurrent.loader.abort();
}
this.fragCurrent = null;
this.fragPrevious = null;
// switch to IDLE state to load new fragment
this.state = State.IDLE;
this.resetLoadingState();
}
}

Expand Down Expand Up @@ -1185,6 +1176,15 @@ export default class BaseStreamController
// (so that we will check against video.buffered ranges in case of alt audio track)
const bufferedTimeRanges = BufferHelper.getBuffered(media);
this.fragmentTracker.detectEvictedFragments(type, bufferedTimeRanges);
if (this.state === State.ENDED) {
this.resetLoadingState();
}
}

protected resetLoadingState() {
this.fragCurrent = null;
this.fragPrevious = null;
this.state = State.IDLE;
}

protected resetLiveStartWhenNotLoaded(level: number): boolean {
Expand All @@ -1197,7 +1197,7 @@ export default class BaseStreamController
// We can't afford to retry after a delay in a live scenario. Update the start position and return to IDLE.
this.startPosition = -1;
this.setStartPosition(details, 0);
this.state = State.IDLE;
this.resetLoadingState();
return true;
}
this.nextLoadPosition = this.startPosition;
Expand Down Expand Up @@ -1257,9 +1257,7 @@ export default class BaseStreamController
this.state = State.PARSED;
this.hls.trigger(Events.FRAG_PARSED, { frag, part });
} else {
this.fragCurrent = null;
this.fragPrevious = null;
this.state = State.IDLE;
this.resetLoadingState();
}
}

Expand Down
4 changes: 1 addition & 3 deletions src/controller/stream-controller.ts
Expand Up @@ -738,12 +738,10 @@ export default class StreamController
this.log('Switching to main audio track, cancel main fragment load');
fragCurrent.loader.abort();
}
this.fragCurrent = null;
this.fragPrevious = null;
// destroy transmuxer to force init segment generation (following audio switch)
this.resetTransmuxer();
// switch to IDLE state to load new fragment
this.state = State.IDLE;
this.resetLoadingState();
} else if (this.audioOnly) {
// Reset audio transmuxer so when switching back to main audio we're not still appending where we left off
this.resetTransmuxer();
Expand Down

0 comments on commit 4d98e18

Please sign in to comment.