From d758cf3c684c54d4274cf75afddefe87239d6ef7 Mon Sep 17 00:00:00 2001 From: Sebastian Piquerez Date: Fri, 10 Oct 2025 12:18:33 -0300 Subject: [PATCH 1/3] Add Listen Mode sample and update samples.json with new entry --- samples/alternative/index.html | 5 + samples/alternative/listen-mode.html | 373 +++++++++++++++++++++++++++ samples/samples.json | 14 + 3 files changed, 392 insertions(+) create mode 100644 samples/alternative/listen-mode.html diff --git a/samples/alternative/index.html b/samples/alternative/index.html index de1f772cc1..1e2ae6eb3c 100644 --- a/samples/alternative/index.html +++ b/samples/alternative/index.html @@ -54,6 +54,11 @@

Alternative Media Presentations

A sample showing alternative media presentations with a dedicated alternative video element. The red-bordered video element will be used for alternative content.

+
Additional Samples:
+
diff --git a/samples/alternative/listen-mode.html b/samples/alternative/listen-mode.html new file mode 100644 index 0000000000..6340bd042b --- /dev/null +++ b/samples/alternative/listen-mode.html @@ -0,0 +1,373 @@ + + + + + Listen Mode - Alternative Media Presentations + + + + + + + + + + + +
+
+
+ +
+
+
+
+

Listen Mode - Alternative Media Presentations

+

A sample demonstrating listen mode where an alternative content can be replaced without maxDuration, and then a status update can add maxDuration to return to original content.

+ +
+
Stream Configuration
+
+ + +
+ +
+ + +
+ +
+ + + Time from now to trigger replace event +
+ +
+ + +
+ + +
+
+
+
+ + + +
+
Generated Manifest Events:
+
No events configured yet...
+
+
+
+
+ © DASH-IF +
+
+
+ + + + + diff --git a/samples/samples.json b/samples/samples.json index 4fd2686929..f1ca16ae9e 100644 --- a/samples/samples.json +++ b/samples/samples.json @@ -867,6 +867,20 @@ "Video", "Audio" ] + }, + { + "title": "Alternative MPD Listen Mode", + "description": "A sample demonstrating listen mode where alternative content can be inserted without maxDuration, and then a status update can add maxDuration to return to original content. Simplified interface with Insert and Return buttons.", + "href": "alternative/listen-mode.html", + "image": "lib/img/livesim-1.jpg", + "labels": [ + "Live", + "Alternative MPD", + "Insert Events", + "Status Update", + "Video", + "Audio" + ] } ] }, From f3931c80674d706ba93ff52b0d707a1bc3f019fd Mon Sep 17 00:00:00 2001 From: Sebastian Piquerez Date: Wed, 15 Oct 2025 13:56:12 -0300 Subject: [PATCH 2/3] Add setAlternativeVideoElement as optional and fix issue restarting the player --- samples/alternative/listen-mode.html | 1 - src/streaming/MediaManager.js | 11 ++++++++++- .../controllers/AlternativeMediaController.js | 11 ++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/samples/alternative/listen-mode.html b/samples/alternative/listen-mode.html index 6340bd042b..8a1a630611 100644 --- a/samples/alternative/listen-mode.html +++ b/samples/alternative/listen-mode.html @@ -122,7 +122,6 @@
Generated Manifest Events:
let eventId = 0; const DEFAULT_DURATION = 10000; // 10 seconds const DEFAULT_RETURN_OFFSET = 10000; // 10 seconds - const DEFAULT_MAX_DURATION = 10000; // 10 seconds const DEFAULT_EARLIEST_RESOLUTION_TIME_OFFSET = 3000; // 3 seconds function init() { diff --git a/src/streaming/MediaManager.js b/src/streaming/MediaManager.js index 17bba0389d..a5574f5ad7 100644 --- a/src/streaming/MediaManager.js +++ b/src/streaming/MediaManager.js @@ -189,7 +189,16 @@ function MediaManager() { initializeAlternativePlayer(alternativeMpdUrl); } - if (altPlayer && altVideoElement) { + if (!altVideoElement) { + altVideoElement = document.createElement('video'); + const videoElement = videoModel.getElement(); + const parentNode = videoElement && videoElement.parentNode; + if (parentNode) { + parentNode.insertBefore(altVideoElement, videoElement.nextSibling); + } + } + + if (altPlayer) { altVideoElement.style.display = 'block'; altPlayer.attachView(altVideoElement); } diff --git a/src/streaming/controllers/AlternativeMediaController.js b/src/streaming/controllers/AlternativeMediaController.js index fc71ec02bc..21158d2135 100644 --- a/src/streaming/controllers/AlternativeMediaController.js +++ b/src/streaming/controllers/AlternativeMediaController.js @@ -170,11 +170,6 @@ function AlternativeMediaController() { return; } - if (!alternativeVideoElement) { - logger.error('Cannot trigger alternative event. Alternative video element has not been set.'); - return; - } - // Only Alternative MPD replace events can be used for dynamic MPD if (manifestInfo.type === DashConstants.DYNAMIC && event.alternativeMpd.mode === Constants.ALTERNATIVE_MPD.MODES.INSERT) { logger.warn('Insert mode not supported for dynamic manifests - ignoring event'); @@ -335,6 +330,10 @@ function AlternativeMediaController() { } function _switchBackToMainContent(altPlayer, event) { + if (!event) { + return; + } + const seekTime = _calculateSeekTime(event, altPlayer); mediaManager.switchBackToMainContent(seekTime); @@ -375,9 +374,11 @@ function AlternativeMediaController() { } function reset() { + // Clean up alternative player event handlers before resetting media manager const altPlayer = mediaManager && mediaManager.getAlternativePlayer(); if (altPlayer) { + _switchBackToMainContent(altPlayer, currentEvent); altPlayer.off(MediaPlayerEvents.PLAYBACK_TIME_UPDATED, _onAlternativePlaybackTimeUpdated, this); } From 735ab9537596b4ca30bea2c794b59b76263d6a60 Mon Sep 17 00:00:00 2001 From: Sebastian Piquerez Date: Wed, 15 Oct 2025 14:06:51 -0300 Subject: [PATCH 3/3] remove unnecessary parameter in addManifestResponseInterceptor --- samples/alternative/listen-mode.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/alternative/listen-mode.html b/samples/alternative/listen-mode.html index 8a1a630611..9394489128 100644 --- a/samples/alternative/listen-mode.html +++ b/samples/alternative/listen-mode.html @@ -213,7 +213,7 @@
Generated Manifest Events:
showStatus(`Status update sent. Main content will return soon.`, 'warning'); } - function addManifestResponseInterceptor(manifestUrl) { + function addManifestResponseInterceptor() { const interceptor = (response) => { // Only intercept MPD manifest requests if (response.request?.customData?.request?.type === 'MPD' && replaceEvent) {