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

Fix a bug in the calculation of the start period which lead to a stal… #3211

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
11 changes: 6 additions & 5 deletions src/streaming/controllers/PlaybackController.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ function PlaybackController() {
t -= timeOffset;
}
}

return t;
}

Expand Down Expand Up @@ -222,15 +221,18 @@ function PlaybackController() {
* Computes the desirable delay for the live edge to avoid a risk of getting 404 when playing at the bleeding edge
* @param {number} fragmentDuration - seconds?
* @param {number} dvrWindowSize - seconds?
* @param {number} minBufferTime - seconds?
* @returns {number} object
* @memberof PlaybackController#
*/
function computeLiveDelay(fragmentDuration, dvrWindowSize) {
function computeLiveDelay(fragmentDuration, dvrWindowSize, minBufferTime = NaN) {
let delay,
ret,
r,
startTime;
const END_OF_PLAYLIST_PADDING = 10;
const MIN_BUFFER_TIME_FACTOR = 4;
const FRAGMENT_DURATION_FACTOR = 4;

let uriParameters = uriFragmentModel.getURIFragmentData();

Expand All @@ -251,9 +253,9 @@ function PlaybackController() {
} else if (settings.get().streaming.useSuggestedPresentationDelay === true && suggestedPresentationDelay !== null && !isNaN(suggestedPresentationDelay) && suggestedPresentationDelay > 0) {
delay = suggestedPresentationDelay;
} else if (!isNaN(fragmentDuration)) {
delay = fragmentDuration * 4;
delay = fragmentDuration * FRAGMENT_DURATION_FACTOR;
} else {
delay = streamInfo.manifestInfo.minBufferTime * 4;
delay = !isNaN(minBufferTime) ? minBufferTime * MIN_BUFFER_TIME_FACTOR : streamInfo.manifestInfo.minBufferTime * MIN_BUFFER_TIME_FACTOR;
}

startTime = adapter.getAvailabilityStartTime();
Expand Down Expand Up @@ -453,7 +455,6 @@ function PlaybackController() {
if (isPaused() || !isDynamic || videoModel.getReadyState() === 0) return;
const currentTime = getNormalizedTime();
const actualTime = getActualPresentationTime(currentTime);

const timeChanged = (!isNaN(actualTime) && actualTime !== currentTime);
if (timeChanged) {
seek(actualTime);
Expand Down
32 changes: 18 additions & 14 deletions src/streaming/controllers/StreamController.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ function StreamController() {

// Find out what is the right time position to jump to taking
// into account state of buffer
for (let i = 0; i < streamProcessors.length; i ++) {
for (let i = 0; i < streamProcessors.length; i++) {
const mediaBuffer = streamProcessors[i].getBuffer();
const ranges = mediaBuffer.getAllBufferRanges();
let nextRangeStartTime;
Expand Down Expand Up @@ -262,7 +262,7 @@ function StreamController() {
stopPreloadTimer();
}

if ( seekingStream === activeStream && preloading ) {
if (seekingStream === activeStream && preloading) {
// Seeking to the current period was requested while preloading the next one, deactivate preloading one
preloading.deactivate(true);
}
Expand All @@ -278,7 +278,7 @@ function StreamController() {
createPlaylistMetrics(PlayList.SEEK_START_REASON);
}

function onPlaybackStarted( /*e*/ ) {
function onPlaybackStarted( /*e*/) {
logger.debug('[onPlaybackStarted]');
if (initialPlayback) {
initialPlayback = false;
Expand Down Expand Up @@ -324,9 +324,11 @@ function StreamController() {
const delayPlaybackEnded = timeToEnd > 0 ? timeToEnd * 1000 : 0;
const prefetchDelay = delayPlaybackEnded < PERIOD_PREFETCH_TIME ? delayPlaybackEnded / 4 : delayPlaybackEnded - PERIOD_PREFETCH_TIME;
logger.debug('[toggleEndPeriodTimer] Going to fire preload in', prefetchDelay, 'milliseconds');
prefetchTimerId = setTimeout(onStreamCanLoadNext, prefetchDelay);
logger.debug('[toggleEndPeriodTimer] start-up of timer to notify PLAYBACK_ENDED event. It will be triggered in',delayPlaybackEnded, 'milliseconds');
playbackEndedTimerId = setTimeout(function () {eventBus.trigger(Events.PLAYBACK_ENDED, {'isLast': getActiveStreamInfo().isLast});}, delayPlaybackEnded);
prefetchTimerId = setTimeout(onStreamCanLoadNext, prefetchDelay);
logger.debug('[toggleEndPeriodTimer] start-up of timer to notify PLAYBACK_ENDED event. It will be triggered in', delayPlaybackEnded, 'milliseconds');
playbackEndedTimerId = setTimeout(function () {
eventBus.trigger(Events.PLAYBACK_ENDED, {'isLast': getActiveStreamInfo().isLast});
}, delayPlaybackEnded);
}
}
}
Expand Down Expand Up @@ -452,8 +454,7 @@ function StreamController() {
audioTrackDetected = undefined;
videoTrackDetected = undefined;
switchStream(activeStream, nextStream, NaN);
}
else {
} else {
logger.debug('StreamController no next stream found');
}
flushPlaylistMetrics(nextStream ? PlayListTrace.END_OF_PERIOD_STOP_REASON : PlayListTrace.END_OF_CONTENT_STOP_REASON);
Expand Down Expand Up @@ -667,10 +668,13 @@ function StreamController() {
const initialTime = !isNaN(startTimeFormUriParameters.fragS) ? startTimeFormUriParameters.fragS : startTimeFormUriParameters.fragT;
initialStream = getStreamForTime(initialTime);
}
// For multiperiod streams we should avoid a switch of streams after the seek to the live edge. So we do a rough calculation of the expected seek time to find the right stream object.
// For multiperiod streams we should avoid a switch of streams after the seek to the live edge. So we do a calculation of the expected seek time to find the right stream object.
if (!initialStream && adapter.getIsDynamic() && streams.length) {
logger.debug('Dynamic multi-period stream: Trying to find the correct starting period');
const targetTime = timelineConverter.calcPresentationTimeFromWallTime(new Date(), adapter.getRegularPeriods()[0]);
const manifestInfo = adapter.getStreamsInfo(undefined, 1)[0].manifestInfo;
const liveEdge = timelineConverter.calcPresentationTimeFromWallTime(new Date(), adapter.getRegularPeriods()[0]);
const targetDelay = playbackController.computeLiveDelay(NaN, manifestInfo.DVRWindowSize, manifestInfo.minBufferTime);
const targetTime = liveEdge - targetDelay;
initialStream = getStreamForTime(targetTime);
}
switchStream(null, initialStream !== null ? initialStream : streams[0], NaN);
Expand All @@ -685,7 +689,7 @@ function StreamController() {
}
}

function onTimeSyncCompleted( /*e*/ ) {
function onTimeSyncCompleted( /*e*/) {
const manifest = manifestModel.getValue();
//TODO check if we can move this to initialize??
if (protectionController) {
Expand Down Expand Up @@ -719,7 +723,7 @@ function StreamController() {
useCalculatedLiveEdgeTime = adapter.getUseCalculatedLiveEdgeTimeForMediaInfo(mediaInfo);
if (useCalculatedLiveEdgeTime) {
logger.debug('SegmentTimeline detected using calculated Live Edge Time');
const s = { streaming: { useManifestDateHeaderTimeSource: false } };
const s = {streaming: {useManifestDateHeaderTimeSource: false}};
settings.update(s);
}
}
Expand Down Expand Up @@ -956,8 +960,8 @@ function StreamController() {

flushPlaylistMetrics(
hasMediaError || hasInitialisationError ?
PlayListTrace.FAILURE_STOP_REASON :
PlayListTrace.USER_REQUEST_STOP_REASON
PlayListTrace.FAILURE_STOP_REASON :
PlayListTrace.USER_REQUEST_STOP_REASON
);

for (let i = 0, ln = streams ? streams.length : 0; i < ln; i++) {
Expand Down