Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/development' into feature/multiB…
Browse files Browse the repository at this point in the history
…uild
  • Loading branch information
dsilhavy committed Jan 21, 2025
2 parents d2a47b3 + a8f3da5 commit 30d0f84
Show file tree
Hide file tree
Showing 20 changed files with 617 additions and 443 deletions.
35 changes: 31 additions & 4 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,14 @@ declare namespace dashjs {
value: string;
}

export interface ThroughputDictValue {
downloadTimeInMs: number,
downloadedBytes: number,
latencyInMs: number
serviceLocation: string,
value: number,
}

/**
* Dash
**/
Expand Down Expand Up @@ -1630,7 +1638,6 @@ declare namespace dashjs {
applyServiceDescription?: boolean,
applyProducerReferenceTime?: boolean,
applyContentSteering?: boolean,
eventControllerRefreshDelay?: number,
enableManifestDurationMismatchFix?: boolean,
parseInbandPrft?: boolean,
enableManifestTimescaleMismatchFix?: boolean,
Expand All @@ -1643,6 +1650,10 @@ declare namespace dashjs {
filterHDRMetadataFormatEssentialProperties?: boolean,
filterVideoColometryEssentialProperties?: boolean
},
events?: {
eventControllerRefreshDelay?: number,
deleteEventMessageDataAfterEventStarted?: boolean
}
timeShiftBuffer?: {
calcFromSegmentTimeline?: boolean
fallbackToSegmentTimeline?: boolean
Expand Down Expand Up @@ -2049,6 +2060,8 @@ declare namespace dashjs {

getAvailableLocations(): MpdLocation[];

getAverageLatency(type: MediaType, calculationMode?: string | null, sampleSize?: number): number;

getAverageThroughput(type: MediaType, calculationMode?: string | null, sampleSize?: number): number;

getBufferLength(type: MediaType): number;
Expand Down Expand Up @@ -2085,8 +2098,12 @@ declare namespace dashjs {

getProtectionController(): ProtectionController;

getRawThroughputData(type: MediaType): ThroughputDictValue[];

getRepresentationsByType(type: MediaType, streamId?: string | null): Representation[];

getSafeAverageThroughput(type: MediaType, calculationMode?: string | null, sampleSize?: number): number;

getSettings(): MediaPlayerSettingClass;

getSource(): string | object;
Expand Down Expand Up @@ -5499,11 +5516,21 @@ declare namespace dashjs {
}

export class IsoBoxSearchInfo {
constructor(lastCompletedOffset: number, found: boolean, size: number);
constructor(found: boolean,
sizeOfLastCompletedBox: number,
sizeOfLastFoundTargetBox: number,
startOffsetOfLastCompletedBox: number,
startOffsetOfLastFoundTargetBox: number,
typeOfLastCompletedBox: string,
typeOfLastTargetBox: string);

found: boolean;
lastCompletedOffset: number;
size: number;
sizeOfLastCompletedBox: number;
sizeOfLastFoundTargetBox: number;
startOffsetOfLastCompletedBox: number;
startOffsetOfLastFoundTargetBox: number;
typeOfLastCompletedBox: string | null;
typeOfLastTargetBox: string | null;
}

export class MetricsList {
Expand Down
2 changes: 1 addition & 1 deletion samples/advanced/ext-url-query-info.html
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ <h3>Flexible Insertion of URL Parameters Sample</h3>
<div class="row mt-2">
<div class="col-md-6">
<label for="manifestSelect">Manifest:</label>
<input id="manifestSelect" type="text" class="form-control">
<input id="manifestSelect" value="https://livesim.dashif.org/livesim2/annexI_dashjs=rocks/testpic_6s/Manifest.mpd?dashjs=rocks" type="text" class="form-control">
<label for="queryParamsInput" class="mt-2">Add Query Parameters to Manifest Request:</label>
<input id="queryParamsInput" type="text" class="form-control" value="token=1234">
<button id="loadButton" class="btn btn-primary mt-2">Load</button>
Expand Down
5 changes: 5 additions & 0 deletions samples/dash-if-reference-player/app/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,11 @@
"name": "SCTE35 events",
"provider": "dashif"
},
{
"url": "https://livesim.dashif.org/livesim2/annexI_dashjs=rocks/testpic_6s/Manifest.mpd?dashjs=rocks",
"name": "Annex I query parameters in the Video AdaptationSet",
"provider": "dashif"
},
{
"url": "https://demo.unified-streaming.com/k8s/live/scte35.isml/.mpd",
"name": "Unified Streaming reference stream with scte35 markers",
Expand Down
35 changes: 26 additions & 9 deletions src/core/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ import Events from './events/Events.js';
* applyServiceDescription: true,
* applyProducerReferenceTime: true,
* applyContentSteering: true,
* eventControllerRefreshDelay: 100,
* enableManifestDurationMismatchFix: true,
* parseInbandPrft: false,
* enableManifestTimescaleMismatchFix: false,
Expand All @@ -86,6 +85,10 @@ import Events from './events/Events.js';
* filterVideoColorimetryEssentialProperties: false,
* filterHDRMetadataFormatEssentialProperties: false
* },
* events: {
* eventControllerRefreshDelay: 100,
* deleteEventMessageDataAfterEventStarted: true
* }
* timeShiftBuffer: {
* calcFromSegmentTimeline: false,
* fallbackToSegmentTimeline: true
Expand Down Expand Up @@ -264,7 +267,7 @@ import Events from './events/Events.js';
* useResourceTimingApi: true,
* useNetworkInformationApi: {
* xhr: false,
* fetch: true
* fetch: false
* },
* useDeadTimeLatency: true,
* bandwidthSafetyFactor: 0.9,
Expand All @@ -281,7 +284,8 @@ import Events from './events/Events.js';
* throughputSlowHalfLifeSeconds: 8,
* throughputFastHalfLifeSeconds: 3,
* latencySlowHalfLifeCount: 2,
* latencyFastHalfLifeCount: 1
* latencyFastHalfLifeCount: 1,
* weightDownloadTimeMultiplicationFactor: 0.0015
* }
* },
* maxBitrate: {
Expand Down Expand Up @@ -342,6 +346,16 @@ import Events from './events/Events.js';
* In case the MPD uses \<SegmentTimeline\ and no segment is found within the DVR window the DVR window is calculated based on the entries in \<SegmentTimeline\>.
*/

/**
* @typedef {Object} EventSettings
* @property {number} [eventControllerRefreshDelay=100]
* Interval timer used by the EventController to check if events need to be triggered or removed.
* @property {boolean} [deleteEventMessageDataAfterEventStarted=true]
* 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.
* 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.
* 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.
*/

/**
* @typedef {Object} LiveDelay
* @property {number} [liveDelayFragmentCount=NaN]
Expand Down Expand Up @@ -827,7 +841,7 @@ import Events from './events/Events.js';
* @property {boolean} [useResourceTimingApi=true]
* If set to true the ResourceTimingApi is used to derive the download time and the number of downloaded bytes.
* This option has no effect for low latency streaming as the download time equals the segment duration in most of the cases and therefor does not provide reliable values
* @property {object} [useNetworkInformationApi = { xhr=false, fetch=true}]
* @property {object} [useNetworkInformationApi = { xhr=false, fetch=false}]
* If set to true the NetworkInformationApi is used to derive the current throughput. Browser support is limited, only available in Chrome and Edge.
* Applies to standard (XHR requests) and/or low latency streaming (Fetch API requests).
* @property {boolean} [useDeadTimeLatency=true]
Expand All @@ -847,12 +861,13 @@ import Events from './events/Events.js';
* - `increaseScale`: Increase sample size by one if the ratio of current and previous sample is higher or equal this value
* - `maxMeasurementsToKeep`: Number of samples to keep before sliding samples out of the window
* - `averageLatencySampleAmount`: Number of latency samples to use (sample size)
* @property {object} [ewma={throughputSlowHalfLifeSeconds=8,throughputFastHalfLifeSeconds=3,latencySlowHalfLifeCount=2,latencyFastHalfLifeCount=1}]
* @property {object} [ewma={throughputSlowHalfLifeSeconds=8,throughputFastHalfLifeSeconds=3,latencySlowHalfLifeCount=2,latencyFastHalfLifeCount=1, weightDownloadTimeMultiplicationFactor=0.0015}]
* When deriving the throughput based on the exponential weighted moving average these settings define:
* - `throughputSlowHalfLifeSeconds`: Number by which the weight of the current throughput measurement is divided, see ThroughputModel._updateEwmaValues
* - `throughputFastHalfLifeSeconds`: Number by which the weight of the current throughput measurement is divided, see ThroughputModel._updateEwmaValues
* - `latencySlowHalfLifeCount`: Number by which the weight of the current latency is divided, see ThroughputModel._updateEwmaValues
* - `latencyFastHalfLifeCount`: Number by which the weight of the current latency is divided, see ThroughputModel._updateEwmaValues
* - `weightDownloadTimeMultiplicationFactor`: This value is multiplied with the download time in milliseconds to derive the weight for the EWMA calculation.
*/

/**
Expand Down Expand Up @@ -937,8 +952,6 @@ import Events from './events/Events.js';
* Set to true if dash.js should use the parameters defined in ProducerReferenceTime elements in combination with ServiceDescription elements.
* @property {boolean} [applyContentSteering=true]
* Set to true if dash.js should apply content steering during playback.
* @property {number} [eventControllerRefreshDelay=100]
* For multi-period streams, overwrite the manifest mediaPresentationDuration attribute with the sum of period durations if the manifest mediaPresentationDuration is greater than the sum of period durations
* @property {boolean} [enableManifestDurationMismatchFix=true]
* Overwrite the manifest segments base information timescale attributes with the timescale set in initialization segments
* @property {boolean} [enableManifestTimescaleMismatchFix=false]
Expand All @@ -947,6 +960,7 @@ import Events from './events/Events.js';
* Set to true if dash.js should parse inband prft boxes (ProducerReferenceTime) and trigger events.
* @property {module:Settings~Metrics} metrics Metric settings
* @property {module:Settings~LiveDelay} delay Live Delay settings
* @property {module:Settings~EventSettings} events Event settings
* @property {module:Settings~TimeShiftBuffer} timeShiftBuffer TimeShiftBuffer settings
* @property {module:Settings~Protection} protection DRM related settings
* @property {module:Settings~Capabilities} capabilities Capability related settings
Expand Down Expand Up @@ -1078,7 +1092,6 @@ function Settings() {
applyServiceDescription: true,
applyProducerReferenceTime: true,
applyContentSteering: true,
eventControllerRefreshDelay: 100,
enableManifestDurationMismatchFix: true,
parseInbandPrft: false,
enableManifestTimescaleMismatchFix: false,
Expand All @@ -1099,6 +1112,10 @@ function Settings() {
filterVideoColorimetryEssentialProperties: false,
filterHDRMetadataFormatEssentialProperties: false
},
events: {
eventControllerRefreshDelay: 100,
deleteEventMessageDataAfterEventStarted: true
},
timeShiftBuffer: {
calcFromSegmentTimeline: false,
fallbackToSegmentTimeline: true
Expand Down Expand Up @@ -1290,7 +1307,7 @@ function Settings() {
useResourceTimingApi: true,
useNetworkInformationApi: {
xhr: false,
fetch: true
fetch: false
},
useDeadTimeLatency: true,
bandwidthSafetyFactor: 0.9,
Expand Down
43 changes: 43 additions & 0 deletions src/streaming/MediaPlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,20 @@ function MediaPlayer() {
customParametersModel.restoreDefaultUTCTimingSources();
}

/**
* Returns the average latency computed in the ThroughputController in milliseconds
*
* @param {MediaType} type
* @param {string} calculationMode
* @param {number} sampleSize
* @return {number} value
* @memberof module:MediaPlayer
* @instance
*/
function getAverageLatency(type, calculationMode = null, sampleSize = NaN) {
return throughputController ? throughputController.getAverageLatency(type, calculationMode, sampleSize) : 0;
}

/**
* Returns the average throughput computed in the ThroughputController in kbit/s
*
Expand All @@ -1246,6 +1260,32 @@ function MediaPlayer() {
return throughputController ? throughputController.getAverageThroughput(type, calculationMode, sampleSize) : 0;
}

/**
* Returns the safe average throughput computed in the ThroughputController in kbit/s. The safe average throughput is the average throughput multiplied by bandwidthSafetyFactor
*
* @param {MediaType} type
* @param {string} calculationMode
* @param {number} sampleSize
* @return {number} value
* @memberof module:MediaPlayer
* @instance
*/
function getSafeAverageThroughput(type, calculationMode = null, sampleSize = NaN) {
return throughputController ? throughputController.getSafeAverageThroughput(type, calculationMode, sampleSize) : 0;
}

/**
* Returns the raw throughput data without calculating the average. This can be used to calculate the current throughput yourself.
*
* @param {MediaType} type
* @return {Array} value
* @memberof module:MediaPlayer
* @instance
*/
function getRawThroughputData(type) {
return throughputController ? throughputController.getRawThroughputData(type) : [];
}

/**
* Sets whether withCredentials on XHR requests for a particular request
* type is true or false
Expand Down Expand Up @@ -2759,6 +2799,7 @@ function MediaPlayer() {
getAutoPlay,
getAvailableBaseUrls,
getAvailableLocations,
getAverageLatency,
getAverageThroughput,
getBufferLength,
getCurrentLiveLatency,
Expand All @@ -2777,7 +2818,9 @@ function MediaPlayer() {
getOfflineController,
getPlaybackRate,
getProtectionController,
getRawThroughputData,
getRepresentationsByType,
getSafeAverageThroughput,
getSettings,
getSource,
getStreamsFromManifest,
Expand Down
8 changes: 8 additions & 0 deletions src/streaming/Stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,10 @@ function Stream(config) {
if (textController) {
textController.deactivateStream(streamInfo);
}
if (thumbnailController) {
thumbnailController.reset();
thumbnailController = null;
}
streamProcessors = [];
isActive = false;
hasFinishedBuffering = false;
Expand Down Expand Up @@ -624,6 +628,10 @@ function Stream(config) {
segmentBlacklistController = null;
}

if (textController && streamInfo) {
textController.clearDataForStream(streamInfo.id);
}

resetInitialSettings(keepBuffers);

streamInfo = null;
Expand Down
3 changes: 3 additions & 0 deletions src/streaming/controllers/BlacklistController.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ function BlackListController(config) {
}

function reset() {
if (addBlacklistEventName) {
eventBus.off(addBlacklistEventName, onAddBlackList, instance);
}
blacklist = [];
}

Expand Down
10 changes: 7 additions & 3 deletions src/streaming/controllers/EventController.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ function EventController() {
try {
checkConfig();
logger.debug('Start Event Controller');
const refreshDelay = settings.get().streaming.eventControllerRefreshDelay;
const refreshDelay = settings.get().streaming.events.eventControllerRefreshDelay;
if (!isStarted && !isNaN(refreshDelay)) {
isStarted = true;
eventInterval = setInterval(_onEventTimer, refreshDelay);
Expand Down Expand Up @@ -474,7 +474,7 @@ function EventController() {
if (mode === MediaPlayerEvents.EVENT_MODE_ON_RECEIVE && !event.triggeredReceivedEvent) {
logger.debug(`Received event ${eventId}`);
event.triggeredReceivedEvent = true;
eventBus.trigger(event.eventStream.schemeIdUri, { event: event }, { mode });
eventBus.trigger(event.eventStream.schemeIdUri, { event: JSON.parse(JSON.stringify(event)) }, { mode });
return;
}

Expand All @@ -490,7 +490,11 @@ function EventController() {
_sendCallbackRequest(event.messageData);
} else {
logger.debug(`Starting event ${eventId} from period ${event.eventStream.period.id} at ${currentVideoTime}`);
eventBus.trigger(event.eventStream.schemeIdUri, { event: event }, { mode });
eventBus.trigger(event.eventStream.schemeIdUri, { event: JSON.parse(JSON.stringify(event)) }, { mode });
if (settings.get().streaming.events.deleteEventMessageDataAfterEventStarted) {
delete event.messageData;
delete event.parsedMessageData;
}
}
event.triggeredStartEvent = true;
}
Expand Down
Loading

0 comments on commit 30d0f84

Please sign in to comment.