Skip to content

Commit 0a2c2b1

Browse files
authoredApr 21, 2025··
Merge branch 'Dash-Industry-Forum:development' into task/segement-template-util
2 parents 17a1381 + ee5bf99 commit 0a2c2b1

22 files changed

+383
-112
lines changed
 

‎index.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,7 @@ declare namespace dashjs {
989989
startNumber: number;
990990
timescale: number;
991991
width: number;
992+
endNumber: number | null;
992993
}
993994

994995
export interface Segment {
@@ -1656,7 +1657,7 @@ declare namespace dashjs {
16561657
},
16571658
events?: {
16581659
eventControllerRefreshDelay?: number,
1659-
deleteEventMessageDataAfterEventStarted?: boolean
1660+
deleteEventMessageDataTimeout?: number
16601661
}
16611662
timeShiftBuffer?: {
16621663
calcFromSegmentTimeline?: boolean
@@ -4127,7 +4128,7 @@ declare namespace dashjs {
41274128

41284129
getSupportedKeySystemMetadataFromContentProtection(cps: object[], protDataSet: ProtectionDataSet, sessionType: string): object[];
41294130

4130-
getSupportedKeySystemsFromSegmentPssh(initData: ArrayBuffer, protDataSet: ProtectionDataSet, sessionType: string): object[];
4131+
getSupportedKeySystemMetadataFromSegmentPssh(initData: ArrayBuffer, protDataSet: ProtectionDataSet, sessionType: string): object[];
41314132

41324133
initDataEquals(initData1: ArrayBuffer, initData2: ArrayBuffer): boolean;
41334134

‎package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "dashjs",
3-
"version": "5.0.1",
3+
"version": "5.1.0",
44
"description": "A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.",
55
"author": "Dash Industry Forum",
66
"license": "BSD-3-Clause",

‎src/core/Settings.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ import Events from './events/Events.js';
8787
* },
8888
* events: {
8989
* eventControllerRefreshDelay: 100,
90-
* deleteEventMessageDataAfterEventStarted: true
90+
* deleteEventMessageDataTimeout: 10000
9191
* }
9292
* timeShiftBuffer: {
9393
* calcFromSegmentTimeline: false,
@@ -352,10 +352,12 @@ import Events from './events/Events.js';
352352
* @typedef {Object} EventSettings
353353
* @property {number} [eventControllerRefreshDelay=100]
354354
* Interval timer used by the EventController to check if events need to be triggered or removed.
355-
* @property {boolean} [deleteEventMessageDataAfterEventStarted=true]
356-
* If this flag is enabled the EventController will delete the message data of events after they have been started. This is to save memory in case events have a long duration and need to be persisted in the EventController.
357-
* Note: Applications will receive a copy of the original event data when they subscribe to an event. This copy contains the original message data and is not affected by this setting.
358-
* Only if an event is dispatched for the second time (e.g. when the user seeks back) the message data will not be included in the dispatched event.
355+
* @property {number} [deleteEventMessageDataTimeout=10000]
356+
* If this value is larger than -1 the EventController will delete the message data attributes of events after they have been started and dispatched to the application.
357+
* This is to save memory in case events have a long duration and need to be persisted in the EventController.
358+
* This parameter defines the time in milliseconds between the start of an event and when the message data is deleted.
359+
* If an event is dispatched for the second time (e.g. when the user seeks back) the message data will not be included in the dispatched event if it has been deleted already.
360+
* Set this value to -1 to not delete any message data.
359361
*/
360362

361363
/**
@@ -693,7 +695,7 @@ import Events from './events/Events.js';
693695
* @property {boolean} [detectPlayreadyMessageFormat=true]
694696
* If set to true the player will use the raw unwrapped message from the Playready CDM
695697
*
696-
* @property {boolean} [ignoreKeyStatusest=false]
698+
* @property {boolean} [ignoreKeyStatuses=false]
697699
* If set to true the player will ignore the status of a key and try to play the corresponding track regardless whether the key is usable or not.
698700
*/
699701

@@ -1118,7 +1120,7 @@ function Settings() {
11181120
},
11191121
events: {
11201122
eventControllerRefreshDelay: 100,
1121-
deleteEventMessageDataAfterEventStarted: true
1123+
deleteEventMessageDataTimeout: 10000
11221124
},
11231125
timeShiftBuffer: {
11241126
calcFromSegmentTimeline: false,

‎src/core/Utils.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,21 @@ class Utils {
108108
// Get the search parameters
109109
const params = new URLSearchParams(parsedUrl.search);
110110

111-
if (!params || params.size === 0) {
111+
if (!params || params.size === 0 || !params.has(queryParameter)) {
112112
return url;
113113
}
114114

115-
// Remove the CMCD parameter
115+
// Remove the queryParameter
116116
params.delete(queryParameter);
117117

118-
// Reconstruct the URL without the CMCD parameter
119-
parsedUrl.search = params.toString();
118+
// Manually reconstruct the query string without re-encoding
119+
const queryString = Array.from(params.entries())
120+
.map(([key, value]) => `${key}=${value}`)
121+
.join('&');
120122

121-
return parsedUrl.toString();
123+
// Reconstruct the URL
124+
const baseUrl = `${parsedUrl.origin}${parsedUrl.pathname}`;
125+
return queryString ? `${baseUrl}?${queryString}` : baseUrl;
122126
}
123127

124128
static parseHttpHeaders(headerStr) {

‎src/dash/DashHandler.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@ function DashHandler(config) {
279279
}
280280

281281
let indexToRequest = lastSegment ? lastSegment.index + 1 : 0;
282+
if (representation && lastSegment && representation.endNumber && lastSegment.replacementNumber && lastSegment.replacementNumber >= representation.endNumber) {
283+
mediaHasFinished = true;
284+
return null;
285+
}
282286

283287
return _getRequest(mediaInfo, representation, indexToRequest);
284288
}

‎src/dash/constants/DashConstants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export default {
8484
DVB_MIMETYPE : 'dvb:mimeType',
8585
DVB_FONTFAMILY : 'dvb:fontFamily',
8686
DYNAMIC: 'dynamic',
87+
END_NUMBER: 'endNumber',
8788
ESSENTIAL_PROPERTY: 'EssentialProperty',
8889
EVENT: 'Event',
8990
EVENT_STREAM: 'EventStream',

‎src/dash/models/DashManifestModel.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,9 @@ function DashManifestModel() {
842842
} else if (baseUrl && baseUrl.availabilityTimeComplete !== undefined) {
843843
voRepresentation.availabilityTimeComplete = baseUrl.availabilityTimeComplete;
844844
}
845+
if (segmentInfo.hasOwnProperty(DashConstants.END_NUMBER)) {
846+
voRepresentation.endNumber = segmentInfo[DashConstants.END_NUMBER];
847+
}
845848
}
846849

847850
voRepresentation.mseTimeOffset = calcMseTimeOffset(voRepresentation);

‎src/dash/utils/TemplateSegmentsGetter.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,12 @@ function TemplateSegmentsGetter(config, isDynamic) {
7474
index = Math.max(index, 0);
7575

7676
const seg = getIndexBasedSegment(timelineConverter, isDynamic, representation, index);
77+
7778
if (seg) {
79+
if (representation.endNumber && seg.replacementNumber > representation.endNumber) {
80+
return null;
81+
}
82+
7883
seg.replacementTime = Math.round(index * representation.segmentDuration * representation.timescale, 10);
7984
seg.media = processUriTemplate(
8085
template.media,

‎src/dash/vo/Representation.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class Representation {
7272
this.startNumber = 1;
7373
this.timescale = 1;
7474
this.width = NaN;
75+
this.endNumber = null;
7576
}
7677

7778
hasInitialization() {

‎src/streaming/MediaPlayer.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2709,6 +2709,7 @@ function MediaPlayer() {
27092709

27102710
function __sanitizeDescriptorType(name, val, defaultSchemeIdUri) {
27112711
let out = {};
2712+
// For an empty string, let's unset the descriptor, i.e. return null
27122713
if (val) {
27132714
if (val instanceof Array) {
27142715
throw ARRAY_NOT_SUPPORTED_ERROR;
@@ -2725,22 +2726,25 @@ function MediaPlayer() {
27252726
return null;
27262727
}
27272728

2728-
if (value.lang) {
2729+
if (value.id !== undefined) {
2730+
output.id = value.id;
2731+
}
2732+
if (value.lang !== undefined) {
27292733
output.lang = value.lang;
27302734
}
27312735
if (!isNaN(value.index)) {
27322736
output.index = value.index;
27332737
}
2734-
if (value.viewpoint) {
2738+
if (value.viewpoint !== undefined) {
27352739
output.viewpoint = __sanitizeDescriptorType('viewpoint', value.viewpoint, defaults.viewpoint);
27362740
}
2737-
if (value.audioChannelConfiguration) {
2741+
if (value.audioChannelConfiguration !== undefined) {
27382742
output.audioChannelConfiguration = __sanitizeDescriptorType('audioChannelConfiguration', value.audioChannelConfiguration, defaults.audioChannelConfiguration);
27392743
}
2740-
if (value.role) {
2744+
if (value.role !== undefined) {
27412745
output.role = __sanitizeDescriptorType('role', value.role, defaults.role);
27422746
}
2743-
if (value.accessibility) {
2747+
if (value.accessibility !== undefined) {
27442748
output.accessibility = __sanitizeDescriptorType('accessibility', value.accessibility, defaults.accessibility);
27452749
}
27462750

‎src/streaming/Stream.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,18 @@ function Stream(config) {
138138
* Register the streaming events
139139
*/
140140
function registerEvents() {
141-
eventBus.on(Events.BUFFERING_COMPLETED, onBufferingCompleted, instance);
142-
eventBus.on(Events.INBAND_EVENTS, onInbandEvents, instance);
141+
eventBus.on(Events.BUFFERING_COMPLETED, _onBufferingCompleted, instance);
142+
eventBus.on(Events.INBAND_EVENTS, _onInbandEvents, instance);
143+
eventBus.on(Events.DATA_UPDATE_COMPLETED, _onDataUpdateCompleted, instance);
143144
}
144145

145146
/**
146147
* Unregister the streaming events
147148
*/
148149
function unRegisterEvents() {
149-
eventBus.off(Events.BUFFERING_COMPLETED, onBufferingCompleted, instance);
150-
eventBus.off(Events.INBAND_EVENTS, onInbandEvents, instance);
150+
eventBus.off(Events.BUFFERING_COMPLETED, _onBufferingCompleted, instance);
151+
eventBus.off(Events.INBAND_EVENTS, _onInbandEvents, instance);
152+
eventBus.off(Events.DATA_UPDATE_COMPLETED, _onDataUpdateCompleted, instance);
151153
}
152154

153155
/**
@@ -862,7 +864,7 @@ function Stream(config) {
862864
})
863865
}
864866

865-
function onBufferingCompleted() {
867+
function _onBufferingCompleted() {
866868
let processors = getStreamProcessors();
867869
const ln = processors.length;
868870

@@ -885,12 +887,16 @@ function Stream(config) {
885887
eventBus.trigger(Events.STREAM_BUFFERING_COMPLETED, { streamInfo: streamInfo }, { streamInfo });
886888
}
887889

888-
function onInbandEvents(e) {
890+
function _onInbandEvents(e) {
889891
if (eventController) {
890892
eventController.addInbandEvents(e.events, streamInfo.id);
891893
}
892894
}
893895

896+
function _onDataUpdateCompleted() {
897+
_initializationCompleted();
898+
}
899+
894900
function getProcessorForMediaInfo(mediaInfo) {
895901
if (!mediaInfo || !mediaInfo.type) {
896902
return null;

‎src/streaming/controllers/EventController.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ function EventController() {
477477
if (mode === MediaPlayerEvents.EVENT_MODE_ON_RECEIVE && !event.triggeredReceivedEvent) {
478478
logger.debug(`Received event ${eventId}`);
479479
event.triggeredReceivedEvent = true;
480-
eventBus.trigger(event.eventStream.schemeIdUri, { event: JSON.parse(JSON.stringify(event)) }, { mode });
480+
eventBus.trigger(event.eventStream.schemeIdUri, { event }, { mode });
481481
return;
482482
}
483483

@@ -494,10 +494,12 @@ function EventController() {
494494
_sendCallbackRequest(url);
495495
} else {
496496
logger.debug(`Starting event ${eventId} from period ${event.eventStream.period.id} at ${currentVideoTime}`);
497-
eventBus.trigger(event.eventStream.schemeIdUri, { event: JSON.parse(JSON.stringify(event)) }, { mode });
498-
if (settings.get().streaming.events.deleteEventMessageDataAfterEventStarted) {
499-
delete event.messageData;
500-
delete event.parsedMessageData;
497+
eventBus.trigger(event.eventStream.schemeIdUri, { event }, { mode });
498+
if (settings.get().streaming.events.deleteEventMessageDataTimeout > -1) {
499+
setTimeout(() => {
500+
delete event.messageData;
501+
delete event.parsedMessageData;
502+
}, settings.get().streaming.events.deleteEventMessageDataTimeout);
501503
}
502504
}
503505
event.triggeredStartEvent = true;

‎src/streaming/net/HTTPLoader.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,9 @@ function HTTPLoader(cfg) {
334334
const _retriggerRequest = function () {
335335
if (remainingAttempts > 0) {
336336
remainingAttempts--;
337+
if (config && config.request) {
338+
config.request.retryAttempts += 1;
339+
}
337340
let retryRequest = { config: config };
338341
retryRequests.push(retryRequest);
339342
retryRequest.timeout = setTimeout(function () {
@@ -582,7 +585,9 @@ function HTTPLoader(cfg) {
582585
*/
583586
function _updateRequestUrlAndHeaders(request) {
584587
_updateRequestUrlAndHeadersWithCmcd(request);
585-
_addExtUrlQueryParameters(request);
588+
if (request.retryAttempts === 0) {
589+
_addExtUrlQueryParameters(request);
590+
}
586591
_addPathwayCloningParameters(request);
587592
_addCommonAccessToken(request);
588593
}

0 commit comments

Comments
 (0)
Please sign in to comment.