diff --git a/samples/alternative/index.html b/samples/alternative/index.html
index dc9eaf6942..de1f772cc1 100644
--- a/samples/alternative/index.html
+++ b/samples/alternative/index.html
@@ -35,7 +35,6 @@
video = document.getElementById('video-element');
alternativeVideo = document.getElementById('alternative-video-element');
player = dashjs.MediaPlayer().create();
- alternativeVideo = document.querySelector('#alternativeVideo');
player.initialize(video, url, false);
player.setAlternativeVideoElement(alternativeVideo);
}
diff --git a/src/streaming/MediaManager.js b/src/streaming/MediaManager.js
index 2700ae737c..17bba0389d 100644
--- a/src/streaming/MediaManager.js
+++ b/src/streaming/MediaManager.js
@@ -40,7 +40,6 @@ function MediaManager() {
isSwitching = false,
hideAlternativePlayerControls = false,
altPlayer,
- fullscreenDiv,
playbackController,
altVideoElement,
alternativeContext,
@@ -84,17 +83,6 @@ function MediaManager() {
logger = debug.getLogger(instance);
- if (!fullscreenDiv) {
- fullscreenDiv = document.createElement('div');
- fullscreenDiv.id = 'fullscreenDiv';
- const videoElement = videoModel.getElement();
- const parentNode = videoElement && videoElement.parentNode;
- if (parentNode) {
- parentNode.insertBefore(fullscreenDiv, videoElement);
- fullscreenDiv.appendChild(videoElement);
- }
- }
-
document.addEventListener('fullscreenchange', () => {
if (document.fullscreenElement === videoModel.getElement()) {
// TODO: Implement fullscreen
@@ -117,7 +105,9 @@ function MediaManager() {
const prebufferedPlayer = MediaPlayer().create();
prebufferedPlayer.initialize(null, alternativeMpdUrl, false, NaN);
prebufferedPlayer.updateSettings({
- streaming: {cacheInitSegments: true}
+ streaming: {
+ cacheInitSegments: true
+ }
});
prebufferedPlayer.preload();
prebufferedPlayer.setAutoPlay(false);
@@ -162,7 +152,6 @@ function MediaManager() {
if (altPlayer) {
altPlayer.off(Events.ERROR, onAlternativePlayerError, this);
}
-
altPlayer = MediaPlayer().create();
altPlayer.updateSettings({
streaming: {
@@ -201,14 +190,13 @@ function MediaManager() {
}
if (altPlayer && altVideoElement) {
+ altVideoElement.style.display = 'block';
altPlayer.attachView(altVideoElement);
}
videoModel.pause();
- logger.debug('Main video paused');
-
videoModel.getElement().style.display = 'none';
- altVideoElement.style.display = 'block';
+ logger.debug('Main video paused');
if (time) {
logger.debug(`Seeking alternative content to time: ${time}`);
@@ -242,7 +230,12 @@ function MediaManager() {
if (playbackController.getIsDynamic()) {
logger.debug('Seeking to original live point for dynamic manifest');
- playbackController.seekToOriginalLive(true, false, false);
+ if (seekTime > playbackController.getDvrWindowStart()) {
+ playbackController.seek(seekTime, false, false);
+ } else {
+ logger.warn('Seek time is before DVR window start, seeking to start of DVR window');
+ playbackController.seekToDvrWindowStart();
+ }
} else {
logger.debug(`Seeking main content to time: ${seekTime}`);
playbackController.seek(seekTime, false, false);
diff --git a/src/streaming/controllers/AlternativeMediaController.js b/src/streaming/controllers/AlternativeMediaController.js
index 894518d349..ff3abfa9bb 100644
--- a/src/streaming/controllers/AlternativeMediaController.js
+++ b/src/streaming/controllers/AlternativeMediaController.js
@@ -41,25 +41,6 @@ function AlternativeMediaController() {
const context = this.context;
const eventBus = EventBus(context).getInstance();
- function _calculateSeekTime(currentEvent, altPlayer) {
- let seekTime;
- if (currentEvent.mode === Constants.ALTERNATIVE_MPD.MODES.REPLACE) {
- if (currentEvent.returnOffset || currentEvent.returnOffset === 0) {
- seekTime = currentEvent.presentationTime + currentEvent.returnOffset;
- logger.debug(`Using return offset - seeking to: ${seekTime}`);
- } else {
- const alternativeDuration = altPlayer.duration()
- const alternativeEffectiveDuration = !isNaN(currentEvent.maxDuration) ? Math.min(currentEvent.maxDuration, alternativeDuration) : alternativeDuration
- seekTime = currentEvent.presentationTime + alternativeEffectiveDuration;
- logger.debug(`Using alternative duration - seeking to: ${seekTime}`);
- }
- } else if (currentEvent.mode === Constants.ALTERNATIVE_MPD.MODES.INSERT) {
- seekTime = currentEvent.presentationTime;
- logger.debug(`Insert mode - seeking to original presentation time: ${seekTime}`);
- }
- return seekTime;
- }
-
let instance,
debug,
logger,
@@ -314,6 +295,25 @@ function AlternativeMediaController() {
}
}
+ function _calculateSeekTime(currentEvent, altPlayer) {
+ let seekTime;
+ if (currentEvent.mode === Constants.ALTERNATIVE_MPD.MODES.REPLACE) {
+ if (currentEvent.returnOffset || currentEvent.returnOffset === 0) {
+ seekTime = currentEvent.presentationTime + currentEvent.returnOffset;
+ logger.debug(`Using return offset - seeking to: ${seekTime}`);
+ } else {
+ const alternativeDuration = altPlayer.duration()
+ const alternativeEffectiveDuration = !isNaN(currentEvent.maxDuration) ? Math.min(currentEvent.maxDuration, alternativeDuration) : alternativeDuration
+ seekTime = currentEvent.presentationTime + alternativeEffectiveDuration;
+ logger.debug(`Using alternative duration - seeking to: ${seekTime}`);
+ }
+ } else if (currentEvent.mode === Constants.ALTERNATIVE_MPD.MODES.INSERT) {
+ seekTime = currentEvent.presentationTime;
+ logger.debug(`Insert mode - seeking to original presentation time: ${seekTime}`);
+ }
+ return seekTime;
+ }
+
function _resetAlternativeSwitchStates() {
currentEvent = null;
actualEventPresentationTime = 0;
diff --git a/src/streaming/controllers/EventController.js b/src/streaming/controllers/EventController.js
index 2bb08f31c8..3a2abf9ec7 100644
--- a/src/streaming/controllers/EventController.js
+++ b/src/streaming/controllers/EventController.js
@@ -502,6 +502,29 @@ function EventController() {
}
}
+ /**
+ * Auxiliary method to check for earliest resolution time events and return alternative MPD
+ * @param {object} event
+ * @return {object|null} - Returns the alternative MPD if it exists and has earliestResolutionTimeOffset, null otherwise
+ * @private
+ */
+ function _checkForEarliestResolutionTimeEvents(event) {
+ try {
+ if (!event || !event.alternativeMpd) {
+ return null;
+ }
+
+ if (event.alternativeMpd.earliestResolutionTimeOffset !== undefined) {
+ return event.alternativeMpd;
+ }
+
+ return null;
+ } catch (e) {
+ logger.error(e);
+ return null;
+ }
+ }
+
/**
* Checks if the event has an earliestResolutionTimeOffset and if it's ready to resolve
* @param {object} event
@@ -511,11 +534,13 @@ function EventController() {
*/
function _checkEventReadyToResolve(event, currentVideoTime) {
try {
- if (!event.alternativeMpd.earliestResolutionTimeOffset || event.triggeredReadyToResolve) {
+ const earlyToResolveEvent = _checkForEarliestResolutionTimeEvents(event);
+
+ if (!earlyToResolveEvent || event.triggeredReadyToResolve) {
return false;
}
- const resolutionTime = event.calculatedPresentationTime - event.alternativeMpd .earliestResolutionTimeOffset;
+ const resolutionTime = event.calculatedPresentationTime - earlyToResolveEvent.earliestResolutionTimeOffset;
return currentVideoTime >= resolutionTime;
} catch (e) {
logger.error(e);
diff --git a/src/streaming/controllers/PlaybackController.js b/src/streaming/controllers/PlaybackController.js
index fad48959d5..f6b68cb2e6 100644
--- a/src/streaming/controllers/PlaybackController.js
+++ b/src/streaming/controllers/PlaybackController.js
@@ -267,6 +267,25 @@ function PlaybackController() {
seek(seektime, stickToBuffered, internal, adjustLiveDelay);
}
+ function seekToStartDvrWindow(stickToBuffered = false, internal = false, adjustLiveDelay = false) {
+ const dvrWindowStart = getDvrWindowStart();
+
+ if (dvrWindowStart === 0) {
+ return;
+ }
+
+ seek(dvrWindowStart, stickToBuffered, internal, adjustLiveDelay);
+ }
+
+ function getDvrWindowStart() {
+ if (!streamInfo || !videoModel || !isDynamic) {
+ return;
+ }
+ const type = streamController && streamController.hasVideoTrack() ? Constants.VIDEO : Constants.AUDIO;
+ const dvrInfo = dashMetrics.getCurrentDVRInfo(type);
+ return dvrInfo && dvrInfo.range ? dvrInfo.range.start : 0;
+ }
+
function _getDvrWindowEnd() {
if (!streamInfo || !videoModel || !isDynamic) {
return;
@@ -922,6 +941,7 @@ function PlaybackController() {
getAvailabilityStartTime,
getBufferLevel,
getCurrentLiveLatency,
+ getDvrWindowStart,
getEnded,
getInitialCatchupModeActivated,
getIsDynamic,
@@ -947,6 +967,7 @@ function PlaybackController() {
seek,
seekToCurrentLive,
seekToOriginalLive,
+ seekToStartDvrWindow,
setConfig,
updateCurrentTime,
};