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

DVR Window Refactoring #3809

Merged
merged 2 commits into from
Nov 12, 2021
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
23 changes: 2 additions & 21 deletions src/streaming/StreamProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ function StreamProcessor(config) {
representationController,
shouldUseExplicitTimeForRequest,
qualityChangeInProgress,
manifestUpdateInProgress,
dashHandler,
segmentsController,
bufferingTime;
Expand All @@ -106,8 +105,6 @@ function StreamProcessor(config) {
eventBus.on(Events.QUOTA_EXCEEDED, _onQuotaExceeded, instance);
eventBus.on(Events.SET_FRAGMENTED_TEXT_AFTER_DISABLED, _onSetFragmentedTextAfterDisabled, instance);
eventBus.on(Events.SET_NON_FRAGMENTED_TEXT, _onSetNonFragmentedText, instance);
eventBus.on(Events.MANIFEST_UPDATED, _onManifestUpdated, instance);
eventBus.on(Events.STREAMS_COMPOSED, _onStreamsComposed, instance);
eventBus.on(Events.SOURCE_BUFFER_ERROR, _onSourceBufferError, instance);
}

Expand Down Expand Up @@ -209,7 +206,6 @@ function StreamProcessor(config) {
mediaInfo = null;
bufferingTime = 0;
shouldUseExplicitTimeForRequest = false;
manifestUpdateInProgress = false;
qualityChangeInProgress = false;
}

Expand Down Expand Up @@ -253,8 +249,6 @@ function StreamProcessor(config) {
eventBus.off(Events.SET_FRAGMENTED_TEXT_AFTER_DISABLED, _onSetFragmentedTextAfterDisabled, instance);
eventBus.off(Events.SET_NON_FRAGMENTED_TEXT, _onSetNonFragmentedText, instance);
eventBus.off(Events.QUOTA_EXCEEDED, _onQuotaExceeded, instance);
eventBus.off(Events.MANIFEST_UPDATED, _onManifestUpdated, instance);
eventBus.off(Events.STREAMS_COMPOSED, _onStreamsComposed, instance);
eventBus.off(Events.SOURCE_BUFFER_ERROR, _onSourceBufferError, instance);

resetInitialSettings();
Expand Down Expand Up @@ -364,7 +358,7 @@ function StreamProcessor(config) {
// Event propagation may have been stopped (see MssHandler)
if (!e.sender) return;

if (manifestUpdateInProgress) {
if (playbackController.getIsManifestUpdateInProgress()) {
_noValidRequest();
return;
}
Expand Down Expand Up @@ -398,7 +392,7 @@ function StreamProcessor(config) {
*/
function _onMediaFragmentNeeded(e, rescheduleIfNoRequest = true) {
// Don't schedule next fragments while updating manifest or pruning to avoid buffer inconsistencies
if (manifestUpdateInProgress || bufferController.getIsPruningInProgress()) {
if (playbackController.getIsManifestUpdateInProgress() || bufferController.getIsPruningInProgress()) {
_noValidRequest();
return;
}
Expand Down Expand Up @@ -520,19 +514,6 @@ function StreamProcessor(config) {
scheduleController.startScheduleTimer(settings.get().streaming.lowLatencyEnabled ? settings.get().streaming.scheduling.lowLatencyTimeout : settings.get().streaming.scheduling.defaultTimeout);
}

/**
* A new manifest has been loaded, updating is still in progress. Wait for the update to be finished before fetching new segments.
* Otherwise we end up in inconsistencies like wrong base urls especially if periods have been removed.
* @private
*/
function _onManifestUpdated() {
manifestUpdateInProgress = true;
}

function _onStreamsComposed() {
manifestUpdateInProgress = false;
}

function _onDataUpdateCompleted(e) {
if (!e.error) {
// Update representation if no error
Expand Down
62 changes: 45 additions & 17 deletions src/streaming/controllers/PlaybackController.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ function PlaybackController() {
isLowLatencySeekingInProgress,
playbackStalled,
minPlaybackRateChange,
manifestUpdateInProgress,
settings;

function setup() {
Expand Down Expand Up @@ -102,14 +103,16 @@ function PlaybackController() {
const isSafari = /safari/.test(ua) && !/chrome/.test(ua);
minPlaybackRateChange = isSafari ? 0.25 : 0.02;

eventBus.on(Events.DATA_UPDATE_COMPLETED, _onDataUpdateCompleted, this);
eventBus.on(Events.LOADING_PROGRESS, _onFragmentLoadProgress, this);
eventBus.on(MediaPlayerEvents.BUFFER_LEVEL_STATE_CHANGED, _onBufferLevelStateChanged, this);
eventBus.on(MediaPlayerEvents.PLAYBACK_PROGRESS, _onPlaybackProgression, this);
eventBus.on(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackProgression, this);
eventBus.on(MediaPlayerEvents.PLAYBACK_ENDED, _onPlaybackEnded, this, { priority: EventBus.EVENT_PRIORITY_HIGH });
eventBus.on(MediaPlayerEvents.STREAM_INITIALIZING, _onStreamInitializing, this);
eventBus.on(MediaPlayerEvents.REPRESENTATION_SWITCH, _onRepresentationSwitch, this);
eventBus.on(Events.DATA_UPDATE_COMPLETED, _onDataUpdateCompleted, instance);
eventBus.on(Events.LOADING_PROGRESS, _onFragmentLoadProgress, instance);
eventBus.on(Events.MANIFEST_UPDATED, _onManifestUpdated, instance);
eventBus.on(Events.STREAMS_COMPOSED, _onStreamsComposed, instance);
eventBus.on(MediaPlayerEvents.BUFFER_LEVEL_STATE_CHANGED, _onBufferLevelStateChanged, instance);
eventBus.on(MediaPlayerEvents.PLAYBACK_PROGRESS, _onPlaybackProgression, instance);
eventBus.on(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackProgression, instance);
eventBus.on(MediaPlayerEvents.PLAYBACK_ENDED, _onPlaybackEnded, instance, { priority: EventBus.EVENT_PRIORITY_HIGH });
eventBus.on(MediaPlayerEvents.STREAM_INITIALIZING, _onStreamInitializing, instance);
eventBus.on(MediaPlayerEvents.REPRESENTATION_SWITCH, _onRepresentationSwitch, instance);

if (playOnceInitialized) {
playOnceInitialized = false;
Expand Down Expand Up @@ -223,6 +226,10 @@ function PlaybackController() {
return streamController;
}

function getIsManifestUpdateInProgress() {
return manifestUpdateInProgress;
}

/**
* 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?
Expand Down Expand Up @@ -347,16 +354,19 @@ function PlaybackController() {
playOnceInitialized = false;
liveDelay = 0;
availabilityStartTime = 0;
manifestUpdateInProgress = false;
seekTarget = NaN;
if (videoModel) {
eventBus.off(Events.DATA_UPDATE_COMPLETED, _onDataUpdateCompleted, this);
eventBus.off(Events.LOADING_PROGRESS, _onFragmentLoadProgress, this);
eventBus.off(MediaPlayerEvents.BUFFER_LEVEL_STATE_CHANGED, _onBufferLevelStateChanged, this);
eventBus.off(MediaPlayerEvents.PLAYBACK_PROGRESS, _onPlaybackProgression, this);
eventBus.off(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackProgression, this);
eventBus.off(MediaPlayerEvents.PLAYBACK_ENDED, _onPlaybackEnded, this);
eventBus.off(MediaPlayerEvents.STREAM_INITIALIZING, _onStreamInitializing, this);
eventBus.off(MediaPlayerEvents.REPRESENTATION_SWITCH, _onRepresentationSwitch, this);
eventBus.off(Events.DATA_UPDATE_COMPLETED, _onDataUpdateCompleted, instance);
eventBus.off(Events.LOADING_PROGRESS, _onFragmentLoadProgress, instance);
eventBus.off(Events.MANIFEST_UPDATED, _onManifestUpdated, instance);
eventBus.off(Events.STREAMS_COMPOSED, _onStreamsComposed, instance);
eventBus.off(MediaPlayerEvents.BUFFER_LEVEL_STATE_CHANGED, _onBufferLevelStateChanged, instance);
eventBus.off(MediaPlayerEvents.PLAYBACK_PROGRESS, _onPlaybackProgression, instance);
eventBus.off(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onPlaybackProgression, instance);
eventBus.off(MediaPlayerEvents.PLAYBACK_ENDED, _onPlaybackEnded, instance);
eventBus.off(MediaPlayerEvents.STREAM_INITIALIZING, _onStreamInitializing, instance);
eventBus.off(MediaPlayerEvents.REPRESENTATION_SWITCH, _onRepresentationSwitch, instance);
videoModel.setPlaybackRate(1.0, true);
stopUpdatingWallclockTime();
removeAllListeners();
Expand Down Expand Up @@ -444,7 +454,7 @@ function PlaybackController() {
* @param {object} mediaType
*/
function updateCurrentTime(mediaType = null) {
if (isPaused() || !isDynamic || videoModel.getReadyState() === 0 || isSeeking()) return;
if (isPaused() || !isDynamic || videoModel.getReadyState() === 0 || isSeeking() || manifestUpdateInProgress) return;

// Note: In some cases we filter certain media types completely (for instance due to an unsupported video codec). This happens after the first entry to the DVR metric has been added.
// Now the DVR window for the filtered media type is not updated anymore. Consequently, always use a mediaType that is available to get a valid DVR window.
Expand Down Expand Up @@ -594,6 +604,7 @@ function PlaybackController() {
// Updates playback time for paused dynamic streams
// (video element doesn't call timeupdate when the playback is paused)
if (getIsDynamic()) {
streamController.addDVRMetric();
if (isPaused()) {
_updateLivePlaybackTime();
} else {
Expand Down Expand Up @@ -942,6 +953,22 @@ function PlaybackController() {
}
}

/**
* A new manifest has been loaded, updating is still in progress.
* @private
*/
function _onManifestUpdated() {
manifestUpdateInProgress = true;
}

/**
* Manifest update was completed
* @private
*/
function _onStreamsComposed() {
manifestUpdateInProgress = false;
}


function _checkEnableLowLatency(mediaInfo) {
if (mediaInfo && mediaInfo.supplementalProperties &&
Expand Down Expand Up @@ -1000,6 +1027,7 @@ function PlaybackController() {
getBufferLevel,
getTime,
getNormalizedTime,
getIsManifestUpdateInProgress,
getPlaybackRate,
getPlayedRanges,
getEnded,
Expand Down
18 changes: 4 additions & 14 deletions src/streaming/controllers/StreamController.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ function StreamController() {
eventBus.on(Events.MANIFEST_UPDATED, _onManifestUpdated, instance);
eventBus.on(Events.STREAM_BUFFERING_COMPLETED, _onStreamBufferingCompleted, instance);
eventBus.on(Events.TIME_SYNCHRONIZATION_COMPLETED, _onTimeSyncCompleted, instance);
eventBus.on(Events.WALLCLOCK_TIME_UPDATED, _onWallclockTimeUpdated, instance);
eventBus.on(Events.CURRENT_TRACK_CHANGED, _onCurrentTrackChanged, instance);
}

Expand All @@ -202,7 +201,6 @@ function StreamController() {
eventBus.off(Events.MANIFEST_UPDATED, _onManifestUpdated, instance);
eventBus.off(Events.STREAM_BUFFERING_COMPLETED, _onStreamBufferingCompleted, instance);
eventBus.off(Events.TIME_SYNCHRONIZATION_COMPLETED, _onTimeSyncCompleted, instance);
eventBus.off(Events.WALLCLOCK_TIME_UPDATED, _onWallclockTimeUpdated, instance);
eventBus.off(Events.CURRENT_TRACK_CHANGED, _onCurrentTrackChanged, instance);
}

Expand Down Expand Up @@ -260,6 +258,7 @@ function StreamController() {
if (!activeStream) {
_initializeForFirstStream(streamsInfo);
}

eventBus.trigger(Events.STREAMS_COMPOSED);
// Additional periods might have been added after an MPD update. Check again if we can start prebuffering.
_checkIfPrebufferingCanStart();
Expand Down Expand Up @@ -324,7 +323,7 @@ function StreamController() {
function _initializeForFirstStream(streamsInfo) {

// Add the DVR window so we can calculate the right starting point
_addDVRMetric();
addDVRMetric();

// If the start is in the future we need to wait
const dvrRange = dashMetrics.getCurrentDVRInfo().range;
Expand Down Expand Up @@ -660,7 +659,7 @@ function StreamController() {
/**
* Add the DVR window to the metric list. We need the DVR window to restrict the seeking and calculate the right start time.
*/
function _addDVRMetric() {
function addDVRMetric() {
try {
const isDynamic = adapter.getIsDynamic();
const streamsInfo = adapter.getStreamsInfo();
Expand Down Expand Up @@ -724,16 +723,6 @@ function StreamController() {
stream.prepareQualityChange(e);
}

/**
* Update the DVR window when the wallclock time has updated
* @private
*/
function _onWallclockTimeUpdated() {
if (adapter.getIsDynamic()) {
_addDVRMetric();
}
}

/**
* When the playback time is updated we add the droppedFrames metric to the dash metric object
* @private
Expand Down Expand Up @@ -1508,6 +1497,7 @@ function StreamController() {
instance = {
initialize,
getActiveStreamInfo,
addDVRMetric,
hasVideoTrack,
hasAudioTrack,
getStreamById,
Expand Down