diff --git a/src/core/events/CoreEvents.js b/src/core/events/CoreEvents.js index 079c8f0807..7ccf03bfc2 100644 --- a/src/core/events/CoreEvents.js +++ b/src/core/events/CoreEvents.js @@ -84,6 +84,7 @@ class CoreEvents extends EventsBase { this.SEGMENTBASE_INIT_REQUEST_NEEDED = 'segmentBaseInitRequestNeeded'; this.SEGMENTBASE_SEGMENTSLIST_REQUEST_NEEDED = 'segmentBaseSegmentsListRequestNeeded'; this.SEEK_TARGET = 'seekTarget'; + this.DYNAMIC_STREAM_COMPLETED = 'dynamicStreamCompleted'; } } diff --git a/src/dash/DashHandler.js b/src/dash/DashHandler.js index fd2db30e76..f6698d9eaf 100644 --- a/src/dash/DashHandler.js +++ b/src/dash/DashHandler.js @@ -64,6 +64,7 @@ function DashHandler(config) { requestedTime, currentTime, isDynamicManifest, + dynamicStreamCompleted, selectedMimeType, segmentsController; @@ -76,10 +77,12 @@ function DashHandler(config) { eventBus.on(events.INITIALIZATION_LOADED, onInitializationLoaded, instance); eventBus.on(events.SEGMENTS_LOADED, onSegmentsLoaded, instance); eventBus.on(events.REPRESENTATION_UPDATE_STARTED, onRepresentationUpdateStarted, instance); + eventBus.on(events.DYNAMIC_STREAM_COMPLETED, onDynamicStreamCompleted, instance); } function initialize(isDynamic) { isDynamicManifest = isDynamic; + dynamicStreamCompleted = false; segmentsController.initialize(isDynamic); } @@ -126,6 +129,7 @@ function DashHandler(config) { eventBus.off(events.INITIALIZATION_LOADED, onInitializationLoaded, instance); eventBus.off(events.SEGMENTS_LOADED, onSegmentsLoaded, instance); eventBus.off(events.REPRESENTATION_UPDATE_STARTED, onRepresentationUpdateStarted, instance); + eventBus.off(events.DYNAMIC_STREAM_COMPLETED, onDynamicStreamCompleted, instance); } function setRequestUrl(request, destination, representation) { @@ -255,7 +259,9 @@ function DashHandler(config) { isFinished = true; } } else { - if (lastSegment) { + if (dynamicStreamCompleted) { + isFinished = true; + } else if (lastSegment) { const time = parseFloat((lastSegment.presentationStartTime - representation.adaptation.period.start).toFixed(5)); const endTime = lastSegment.duration > 0 ? time + 1.5 * lastSegment.duration : time; const duration = representation.adaptation.period.duration; @@ -322,7 +328,7 @@ function DashHandler(config) { // check that there is a segment in this index const segment = segmentsController.getSegmentByIndex(representation, indexToRequest, lastSegment ? lastSegment.mediaStartTime : -1); - if (!segment && isEndlessMedia(representation)) { + if (!segment && isEndlessMedia(representation) && !dynamicStreamCompleted) { logger.debug('No segment found at index: ' + indexToRequest + '. Wait for next loop'); return null; } else { @@ -420,6 +426,11 @@ function DashHandler(config) { eventBus.trigger(events.REPRESENTATION_UPDATE_COMPLETED, {sender: this, representation: representation}); } + function onDynamicStreamCompleted() { + logger.debug('Dynamic stream complete'); + dynamicStreamCompleted = true; + } + instance = { initialize: initialize, getType: getType, //need to be public in order to be used by logger diff --git a/src/dash/constants/DashConstants.js b/src/dash/constants/DashConstants.js index 521ff5489b..7b8e793996 100644 --- a/src/dash/constants/DashConstants.js +++ b/src/dash/constants/DashConstants.js @@ -103,6 +103,7 @@ class DashConstants { this.CONTENTPROTECTION_ASARRAY = 'ContentProtection_asArray'; this.MAIN = 'main'; this.DYNAMIC = 'dynamic'; + this.STATIC = 'static'; this.MEDIA_PRESENTATION_DURATION = 'mediaPresentationDuration'; this.MINIMUM_UPDATE_PERIOD = 'minimumUpdatePeriod'; this.CODEC_PRIVATE_DATA = 'codecPrivateData'; diff --git a/src/streaming/ManifestUpdater.js b/src/streaming/ManifestUpdater.js index f98a2f214e..d77e577c24 100644 --- a/src/streaming/ManifestUpdater.js +++ b/src/streaming/ManifestUpdater.js @@ -33,6 +33,7 @@ import Events from '../core/events/Events'; import FactoryMaker from '../core/FactoryMaker'; import Debug from '../core/Debug'; import Errors from '../core/errors/Errors'; +import DashConstants from '../dash/constants/DashConstants'; function ManifestUpdater() { @@ -138,6 +139,13 @@ function ManifestUpdater() { function update(manifest) { + // See DASH-IF IOP v4.3 section 4.6.4 "Transition Phase between Live and On-Demand" + // Stop manifest update, ignore static manifest and signal end of dynamic stream to detect end of stream + if (manifestModel.getValue() && manifestModel.getValue().type === DashConstants.DYNAMIC && manifest.type === DashConstants.STATIC) { + eventBus.trigger(Events.DYNAMIC_STREAM_COMPLETED); + return; + } + manifestModel.setValue(manifest); const date = new Date();