Skip to content

Commit 5e31f9f

Browse files
authored
Add track selection mode based on selectionPriority attribute (#3751)
* Add track selection mode based on selectionPriority attribute in the manifest. Make this the default mode and fallback to TRACK_SELECTION_MODE_HIGHEST_BITRATE and TRACK_SELECTION_MODE_WIDEST_RANGE in case no selectionPriority is given.
1 parent 283df6b commit 5e31f9f

File tree

9 files changed

+257
-95
lines changed

9 files changed

+257
-95
lines changed

index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1475,7 +1475,7 @@ declare namespace dashjs {
14751475

14761476
export type MetricType = 'ManifestUpdate' | 'RequestsQueue';
14771477
export type TrackSwitchMode = 'alwaysReplace' | 'neverReplace';
1478-
export type TrackSelectionMode = 'highestBitrate' | 'firstTrack' | 'highestEfficiency' | 'widestRange';
1478+
export type TrackSelectionMode = 'highestSelectionPriority' | 'highestBitrate' | 'firstTrack' | 'highestEfficiency' | 'widestRange';
14791479

14801480
export function supportsMediaSource(): boolean;
14811481

src/core/Settings.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
142142
* audio: Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE,
143143
* video: Constants.TRACK_SWITCH_MODE_NEVER_REPLACE
144144
* },
145-
* selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE,
145+
* selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY,
146146
* fragmentRequestTimeout: 0,
147147
* retryIntervals: {
148148
* [HTTPRequest.MPD_TYPE]: 500,
@@ -682,8 +682,11 @@ import {HTTPRequest} from '../streaming/vo/metrics/HTTPRequest';
682682
*
683683
* Possible values
684684
*
685+
* - Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY
686+
* This mode makes the player select the track with the highest selectionPriority as defined in the manifest. If not selectionPriority is given we fallback to TRACK_SELECTION_MODE_HIGHEST_BITRATE. This mode is a default mode.
687+
*
685688
* - Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE
686-
* This mode makes the player select the track with a highest bitrate. This mode is a default mode.
689+
* This mode makes the player select the track with a highest bitrate.
687690
*
688691
* - Constants.TRACK_SELECTION_MODE_FIRST_TRACK
689692
* This mode makes the player select the first track found in the manifest.
@@ -825,7 +828,7 @@ function Settings() {
825828
audio: Constants.TRACK_SWITCH_MODE_ALWAYS_REPLACE,
826829
video: Constants.TRACK_SWITCH_MODE_NEVER_REPLACE
827830
},
828-
selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE,
831+
selectionModeForInitialTrack: Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY,
829832
fragmentRequestTimeout: 0,
830833
retryIntervals: {
831834
[HTTPRequest.MPD_TYPE]: 500,

src/dash/DashAdapter.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,7 @@ function DashAdapter() {
10231023
mediaInfo.mimeType = dashManifestModel.getMimeType(realAdaptation);
10241024
mediaInfo.contentProtection = dashManifestModel.getContentProtectionData(realAdaptation);
10251025
mediaInfo.bitrateList = dashManifestModel.getBitrateListForAdaptation(realAdaptation);
1026+
mediaInfo.selectionPriority = dashManifestModel.getSelectionPriority(realAdaptation);
10261027

10271028
if (mediaInfo.contentProtection) {
10281029
mediaInfo.contentProtection.forEach(function (item) {

src/dash/models/DashManifestModel.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,16 @@ function DashManifestModel() {
406406
});
407407
}
408408

409+
function getSelectionPriority(realAdaption) {
410+
try {
411+
const priority = realAdaption && typeof realAdaption.selectionPriority !== 'undefined' ? parseInt(realAdaption.selectionPriority) : 1;
412+
413+
return isNaN(priority) ? 1 : priority;
414+
} catch (e) {
415+
return 1;
416+
}
417+
}
418+
409419
function getEssentialPropertiesForRepresentation(realRepresentation) {
410420
if (!realRepresentation || !realRepresentation.EssentialProperty_asArray || !realRepresentation.EssentialProperty_asArray.length) return null;
411421

@@ -1169,6 +1179,7 @@ function DashManifestModel() {
11691179
getRealPeriods,
11701180
getRealPeriodForIndex,
11711181
getCodec,
1182+
getSelectionPriority,
11721183
getMimeType,
11731184
getKID,
11741185
getLabelsForAdaptation,

src/dash/vo/MediaInfo.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class MediaInfo {
5252
this.bitrateList = null;
5353
this.isFragmented = null;
5454
this.isEmbedded = null;
55+
this.selectionPriority = 1;
5556
}
5657

5758
}

src/streaming/constants/Constants.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,13 @@ class Constants {
248248
*/
249249
this.TRACK_SELECTION_MODE_WIDEST_RANGE = 'widestRange';
250250

251+
/**
252+
* @constant {string} TRACK_SELECTION_MODE_WIDEST_RANGE makes the player select the track with the highest selectionPriority as defined in the manifest
253+
* @memberof Constants#
254+
* @static
255+
*/
256+
this.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY = 'highestSelectionPriority';
257+
251258
/**
252259
* @constant {string} CMCD_MODE_QUERY specifies to attach CMCD metrics as query parameters.
253260
* @memberof Constants#

src/streaming/controllers/MediaController.js

Lines changed: 83 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,28 @@ function MediaController() {
330330
};
331331
}
332332

333+
function getTracksWithHighestSelectionPriority(trackArr) {
334+
let max = 0;
335+
let result = [];
336+
337+
trackArr.forEach((track) => {
338+
if(!isNaN(track.selectionPriority)) {
339+
// Higher max value. Reset list and add new entry
340+
if (track.selectionPriority > max) {
341+
max = track.selectionPriority;
342+
result = [track];
343+
}
344+
// Same max value add to list
345+
else if (track.selectionPriority === max) {
346+
result.push(track);
347+
}
348+
349+
}
350+
})
351+
352+
return result;
353+
}
354+
333355
function getTracksWithHighestBitrate(trackArr) {
334356
let max = 0;
335357
let result = [];
@@ -402,45 +424,87 @@ function MediaController() {
402424
if (type === Constants.TEXT) return tracks[0];
403425

404426
let mode = settings.get().streaming.selectionModeForInitialTrack;
405-
let tmpArr = [];
427+
let tmpArr;
406428

407429
if (customInitialTrackSelectionFunction && typeof customInitialTrackSelectionFunction === 'function') {
408430
tmpArr = customInitialTrackSelectionFunction(tracks);
409431
} else {
410432
switch (mode) {
433+
case Constants.TRACK_SELECTION_MODE_HIGHEST_SELECTION_PRIORITY:
434+
tmpArr = _trackSelectionModeHighestSelectionPriority(tracks);
435+
break;
411436
case Constants.TRACK_SELECTION_MODE_HIGHEST_BITRATE:
412-
tmpArr = getTracksWithHighestBitrate(tracks);
413-
414-
if (tmpArr.length > 1) {
415-
tmpArr = getTracksWithWidestRange(tmpArr);
416-
}
437+
tmpArr = _trackSelectionModeHighestBitrate(tracks);
417438
break;
418439
case Constants.TRACK_SELECTION_MODE_FIRST_TRACK:
419-
tmpArr.push(tracks[0]);
440+
tmpArr = _trackSelectionModeFirstTrack(tracks);
420441
break;
421442
case Constants.TRACK_SELECTION_MODE_HIGHEST_EFFICIENCY:
422-
tmpArr = getTracksWithHighestEfficiency(tracks);
423-
424-
if (tmpArr.length > 1) {
425-
tmpArr = getTracksWithHighestBitrate(tmpArr);
426-
}
443+
tmpArr = _trackSelectionModeHighestEfficiency(tracks);
427444
break;
428445
case Constants.TRACK_SELECTION_MODE_WIDEST_RANGE:
429-
tmpArr = getTracksWithWidestRange(tracks);
430-
431-
if (tmpArr.length > 1) {
432-
tmpArr = getTracksWithHighestBitrate(tracks);
433-
}
446+
tmpArr = _trackSelectionModeWidestRange(tracks);
434447
break;
435448
default:
436-
logger.warn('Track selection mode is not supported: ' + mode);
449+
logger.warn(`Track selection mode ${mode} is not supported. Falling back to TRACK_SELECTION_MODE_FIRST_TRACK`);
450+
tmpArr = _trackSelectionModeFirstTrack(tracks);
437451
break;
438452
}
439453
}
440454

441-
return tmpArr[0];
455+
return tmpArr.length > 0 ? tmpArr[0] : tracks[0];
442456
}
443457

458+
459+
function _trackSelectionModeHighestSelectionPriority(tracks) {
460+
let tmpArr = getTracksWithHighestSelectionPriority(tracks);
461+
462+
if (tmpArr.length > 1) {
463+
tmpArr = getTracksWithHighestBitrate(tmpArr);
464+
}
465+
466+
if (tmpArr.length > 1) {
467+
tmpArr = getTracksWithWidestRange(tmpArr);
468+
}
469+
470+
return tmpArr;
471+
}
472+
473+
function _trackSelectionModeHighestBitrate(tracks) {
474+
let tmpArr = getTracksWithHighestBitrate(tracks);
475+
476+
if (tmpArr.length > 1) {
477+
tmpArr = getTracksWithWidestRange(tmpArr);
478+
}
479+
480+
return tmpArr;
481+
}
482+
483+
function _trackSelectionModeFirstTrack(tracks) {
484+
return tracks[0];
485+
}
486+
487+
function _trackSelectionModeHighestEfficiency(tracks) {
488+
let tmpArr = getTracksWithHighestEfficiency(tracks);
489+
490+
if (tmpArr.length > 1) {
491+
tmpArr = getTracksWithHighestBitrate(tmpArr);
492+
}
493+
494+
return tmpArr;
495+
}
496+
497+
function _trackSelectionModeWidestRange(tracks) {
498+
let tmpArr = getTracksWithWidestRange(tracks);
499+
500+
if (tmpArr.length > 1) {
501+
tmpArr = getTracksWithHighestBitrate(tracks);
502+
}
503+
504+
return tmpArr;
505+
}
506+
507+
444508
function createTrackInfo() {
445509
return {
446510
audio: {

0 commit comments

Comments
 (0)