Skip to content
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
1 change: 1 addition & 0 deletions src/core/events/CoreEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import EventsBase from './EventsBase.js';
class CoreEvents extends EventsBase {
constructor () {
super();
this.ALTERNATIVE_EVENT_RECEIVED = 'alternativeEventReceived';
this.ATTEMPT_BACKGROUND_SYNC = 'attemptBackgroundSync';
this.BUFFERING_COMPLETED = 'bufferingCompleted';
this.BUFFER_CLEARED = 'bufferCleared';
Expand Down
6 changes: 5 additions & 1 deletion src/dash/constants/DashConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ export default {
ADAPTATION_SETS: 'adaptationSets',
ADAPTATION_SET_SWITCHING_SCHEME_ID_URI: 'urn:mpeg:dash:adaptation-set-switching:2016',
ADD: 'add',
ALTERNATIVE_MPD: 'AlternativeMPD',
ALTERNATIVE_MPD: {
INSERT: 'InsertPresentation',
REPLACE: 'ReplacePresentation',
},
ALTERNATIVE_MPD_SCHEME_ID: 'urn:mpeg:dash:event:alternativeMPD:2022',
ASSET_IDENTIFIER: 'AssetIdentifier',
AUDIO_CHANNEL_CONFIGURATION: 'AudioChannelConfiguration',
Expand Down Expand Up @@ -174,6 +177,7 @@ export default {
START_NUMBER: 'startNumber',
START_WITH_SAP: 'startWithSAP',
STATIC: 'static',
STATUS: 'status',
SUBSET: 'Subset',
SUBTITLE: 'subtitle',
SUB_REPRESENTATION: 'SubRepresentation',
Expand Down
48 changes: 39 additions & 9 deletions src/dash/models/DashManifestModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -1062,9 +1062,18 @@ function DashManifestModel() {
} else {
event.id = null;
}
if (currentMpdEvent.hasOwnProperty(DashConstants.STATUS)) {
event.status = currentMpdEvent.status;
} else {
event.status = null;
}

if (currentMpdEvent.hasOwnProperty(DashConstants.ALTERNATIVE_MPD)) {
event.alternativeMpd = getAlternativeMpd(currentMpdEvent.AlternativeMPD);
const alternativeMpdKey = Object.keys(DashConstants.ALTERNATIVE_MPD).find(key =>
currentMpdEvent.hasOwnProperty(DashConstants.ALTERNATIVE_MPD[key])
);

if (alternativeMpdKey) {
event.alternativeMpd = getAlternativeMpd(currentMpdEvent[DashConstants.ALTERNATIVE_MPD[alternativeMpdKey]], DashConstants.ALTERNATIVE_MPD[alternativeMpdKey]);
event.calculatedPresentationTime = 0;
} else {
event.alternativeMpd = null;
Expand Down Expand Up @@ -1092,16 +1101,37 @@ function DashManifestModel() {
return events;
}

function getAlternativeMpd(event) {
function getAlternativeMpd(event, mode) {
if (!mode) {
return
}
const alternativeMpd = new AlternativeMpd();
alternativeMpd.uri = event.uri ?? null;
alternativeMpd.duration = event.duration ?? null;
alternativeMpd.earliestResolutionTimeOffset = event.earliestResolutionTimeOffset / 1000 ?? null;
alternativeMpd.mode = event.mode ?? null;

getAlternativeMpdCommonData(alternativeMpd, event);

// Keep to avoid errors with the old signaling
alternativeMpd.disableJumpTimeOffest = event.disableJumpTimeOffest ?? null;
alternativeMpd.playTimes = event.playTimes ?? null;
alternativeMpd.returnOffset = event.returnOffset ?? null;
return alternativeMpd;

if (mode === DashConstants.ALTERNATIVE_MPD.INSERT) {
alternativeMpd.mode = Constants.ALTERNATIVE_MPD.MODES.INSERT;
return alternativeMpd;
}

if (mode === DashConstants.ALTERNATIVE_MPD.REPLACE) {
alternativeMpd.mode = Constants.ALTERNATIVE_MPD.MODES.REPLACE;
alternativeMpd.returnOffset = event.returnOffset ?? null;
alternativeMpd.clip = event.clip ?? null;
alternativeMpd.startAtPlayhead = event.startAtPlayhead ?? null;
return alternativeMpd;
}
}

function getAlternativeMpdCommonData(alternativeMpd, event) {
alternativeMpd.url = event.url ?? null;
alternativeMpd.earliestResolutionTimeOffset = event.earliestResolutionTimeOffset / 1000 ?? null;
alternativeMpd.serviceDescriptionId = event.serviceDescriptionId;
alternativeMpd.maxDuration = event.maxDuration;
}

function getEventStreams(inbandStreams, representation, period) {
Expand Down
15 changes: 11 additions & 4 deletions src/dash/vo/AlternativeMpd.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,21 @@

class AlternativeMpd {
constructor() {
this.uri = '';
this.url = '';
this.earliestResolutionTimeOffset = NaN;
this.mode = '';
this.maxDuration = '';
this.serviceDescriptionId = NaN;

// Replace
this.returnOffset = NaN;
this.returnOffset = NaN;
this.clip = true;
this.startAtPlayhead = false;

// Old attributes
this.disableJumpTimeOffest = NaN;
this.playTimes = '';
this.presentationTime = NaN;
this.duration = NaN;
this.returnOffset = NaN;
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/streaming/constants/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,11 @@ export default {
REPLACE: 'replace',
INSERT: 'insert'
},
URI: 'urn:mpeg:dash:event:alternativeMPD:2022'
URIS: {
REPLACE: 'urn:mpeg:dash:event:alternativeMPD:replace:2025',
INSERT: 'urn:mpeg:dash:event:alternativeMPD:insert:2025'
}

},

/**
Expand Down
102 changes: 43 additions & 59 deletions src/streaming/controllers/AlternativeMpdController.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import MediaPlayerEvents from '../MediaPlayerEvents.js';
import MediaPlayer from '../MediaPlayer.js';
import EventBus from './../../core/EventBus.js';
import FactoryMaker from '../../core/FactoryMaker.js';
import Constants from '../constants/Constants.js';

/*
TODOS:
Expand All @@ -49,7 +48,6 @@ function AlternativeMpdController() {
const eventBus = EventBus(context).getInstance();

let instance,
dashConstants,
scheduledEvents = [],
eventTimeouts = [],
videoModel,
Expand All @@ -64,7 +62,8 @@ function AlternativeMpdController() {
altVideoElement,
alternativeContext,
isMainDynamic = false,
lastTimestamp = 0;
lastTimestamp = 0,
manifestInfo = {};

function setConfig(config) {
if (!config) {
Expand All @@ -74,13 +73,6 @@ function AlternativeMpdController() {
if (!videoModel) {
videoModel = config.videoModel;
}
// manifestModel = config.manifestModel;
dashConstants = config.DashConstants;

// if (!altPlayer) {
// let mediaPlayerFactory = config.mediaPlayerFactory;
// altPlayer = mediaPlayerFactory.create();
// }

if (!!config.playbackController && !playbackController) {
playbackController = config.playbackController;
Expand Down Expand Up @@ -110,8 +102,11 @@ function AlternativeMpdController() {

function initialize() {
eventBus.on(MediaPlayerEvents.MANIFEST_LOADED, _onManifestLoaded, this);
eventBus.on(Events.ALTERNATIVE_EVENT_RECEIVED, _onAlternativeEventeReceived, this);

if (altPlayer) {
altPlayer.on(MediaPlayerEvents.MANIFEST_LOADED, _onManifestLoaded, this);
altPlayer.on(Events.ALTERNATIVE_EVENT_RECEIVED, _onAlternativeEventeReceived, this);
}

document.addEventListener('fullscreenchange', () => {
Expand All @@ -132,27 +127,29 @@ function AlternativeMpdController() {
videoModel.getElement().parentNode.insertBefore(fullscreenDiv, videoModel.getElement());
fullscreenDiv.appendChild(videoModel.getElement());
}

eventBus.on(Constants.ALTERNATIVE_MPD.URI, _onAlternativeLoad);
}

function _onAlternativeLoad(e) {
console.log(e);
console.log('I\'m coming from an alternative based event');
function _onManifestLoaded(e) {
const manifest = e.data
manifestInfo.type = manifest.type;
manifestInfo.originalUrl = manifest.originalUrl;

scheduledEvents.forEach((scheduledEvent) => {
if (scheduledEvent.alternativeMPD.url == manifestInfo.originalUrl) {
scheduledEvent.type = manifestInfo.type;
}
});
}

function _onManifestLoaded(e) {
const manifest = e.data;
const events = _parseAlternativeMPDEvents(manifest)
function _onAlternativeEventeReceived(event) {
const alternativeEvent = _parseAlternativeMPDEvent(event)
if (scheduledEvents && scheduledEvents.length > 0) {
scheduledEvents.push(...events)
scheduledEvents.push(alternativeEvent)
} else {
scheduledEvents = events
scheduledEvents = [alternativeEvent]
}

scheduledEvents.forEach((d) => { if (d.alternativeMPD.uri == e.data.originalUrl) { d.type = e.data.type } });

switch (manifest.type) {
switch (manifestInfo.type) {
case 'dynamic':
if (!currentEvent && !altPlayer) {
isMainDynamic = true;
Expand Down Expand Up @@ -234,49 +231,34 @@ function AlternativeMpdController() {
function _initializeAlternativePlayer(event) {
// Initialize alternative player
altPlayer = MediaPlayer().create();
altPlayer.initialize(altVideoElement, event.alternativeMPD.uri, false, NaN, alternativeContext);
altPlayer.initialize(altVideoElement, event.alternativeMPD.url, false, NaN, alternativeContext);
altPlayer.setAutoPlay(false);

altPlayer.on(Events.ERROR, (e) => {
console.error('Alternative player error:', e);
}, this);
}

function _parseAlternativeMPDEvents(manifest) {
const events = [];
const periods = manifest.Period || [];

periods.forEach(period => {
const eventStreams = period.EventStream || [];
eventStreams.forEach(eventStream => {
if (eventStream.schemeIdUri === dashConstants.ALTERNATIVE_MPD_SCHEME_ID) {
const timescale = eventStream.timescale || 1;
const eventsArray = eventStream.Event || [];
eventsArray.forEach(ev => {
if (ev && ev.AlternativeMPD) {
const alternativeMPDNode = ev.AlternativeMPD;
const mode = alternativeMPDNode.mode || 'insert';
const eventObj = { //This should be casted using an AlternativeMpdObject
presentationTime: ev.presentationTime / timescale,
duration: ev.duration / timescale,
alternativeMPD: {
uri: alternativeMPDNode.uri,
earliestResolutionTimeOffset: parseInt(alternativeMPDNode.earliestResolutionTimeOffset || '0', 10) / 1000,
},
mode: mode,
returnOffset: parseInt(alternativeMPDNode.returnOffset || '0', 10) / 1000,
triggered: false,
watched: false,
type: 'static'
};
events.push(eventObj);
}
});
}
});
});

return events;
function _parseAlternativeMPDEvent(event) {
if (event.alternativeMpd) {
const timescale = event.eventStream.timescale || 1;
const alternativeMpdNode = event.alternativeMpd;
const mode = alternativeMpdNode.mode || 'insert';

return {
presentationTime: event.presentationTime / timescale,
duration: event.duration,
alternativeMPD: {
url: alternativeMpdNode.url,
earliestResolutionTimeOffset: parseInt(alternativeMpdNode.earliestResolutionTimeOffset || '0', 10) / 1000,
},
mode: mode,
returnOffset: parseInt(alternativeMpdNode.returnOffset || '0', 10) / 1000,
triggered: false,
watched: false,
type: 'static'
};
}
}

function _scheduleAlternativeMPDEvents() {
Expand Down Expand Up @@ -437,6 +419,7 @@ function AlternativeMpdController() {

if (altPlayer) {
altPlayer.off(MediaPlayerEvents.MANIFEST_LOADED, _onManifestLoaded, this);
altPlayer.off(Events.ALTERNATIVE_EVENT_RECEIVED, _onAlternativeEventeReceived, this);
altPlayer.reset();
altPlayer = null;
}
Expand All @@ -454,6 +437,7 @@ function AlternativeMpdController() {
currentEvent = null;

eventBus.off(MediaPlayerEvents.MANIFEST_LOADED, _onManifestLoaded, this);
eventBus.off(Events.ALTERNATIVE_EVENT_RECEIVED, _onAlternativeEventeReceived, this);
}

instance = {
Expand Down
13 changes: 13 additions & 0 deletions src/streaming/controllers/EventController.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import Debug from '../../core/Debug.js';
import EventBus from '../../core/EventBus.js';
import MediaPlayerEvents from '../../streaming/MediaPlayerEvents.js';
import XHRLoader from '../net/XHRLoader.js';
import Constants from '../constants/Constants.js';
import Events from '../../core/events/Events.js'

function EventController() {

Expand Down Expand Up @@ -296,6 +298,17 @@ function EventController() {
events[schemeIdUri] = [];
}

if (
schemeIdUri === Constants.ALTERNATIVE_MPD.URIS.REPLACE ||
schemeIdUri === Constants.ALTERNATIVE_MPD.URIS.INSERT
) {
// "type" is reserved for the eventBus
delete event.type
eventBus.trigger(Events.ALTERNATIVE_EVENT_RECEIVED, event);
eventState = EVENT_HANDLED_STATES.DISCARDED;
return eventState;
}

const indexOfExistingEvent = events[schemeIdUri].findIndex((e) => {
return ((!value || (e.eventStream.value && e.eventStream.value === value)) && (e.id === id));
});
Expand Down
Loading