Skip to content

Commit 904443d

Browse files
authored
Feature/return unfiltered representations (Dash-Industry-Forum#4963)
* Add a new method getUnfilteredRepresentationsByType * Add a new method getRepresentationsByTypeUnfiltered. This allows applications to get all Representations regardless of any filter settings * Fix wrong JSDoc
1 parent 1067ff1 commit 904443d

File tree

6 files changed

+145
-14
lines changed

6 files changed

+145
-14
lines changed

index.d.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,7 +2021,7 @@ export interface MediaPlayerClass {
20212021
on(type: MetricEvent['type'], listener: (e: MetricEvent) => void, scope?: object): void;
20222022

20232023
on(type: MetricChangedEvent['type'], listener: (e: MetricChangedEvent) => void, scope?: object): void;
2024-
2024+
20252025
on(type: NewTrackSelectedEvent['type'], listener: (e: NewTrackSelectedEvent) => void, scope?: object): void;
20262026

20272027
on(type: OfflineRecordEvent['type'], listener: (e: OfflineRecordEvent) => void, scope?: object): void;
@@ -2055,7 +2055,7 @@ export interface MediaPlayerClass {
20552055
on(type: StreamInitializedEvent['type'], listener: (e: StreamInitializedEvent) => void, scope?: object): void;
20562056

20572057
on(type: TextTracksAddedEvent['type'], listener: (e: TextTracksAddedEvent) => void, scope?: object): void;
2058-
2058+
20592059
on(type: TrackChangeRenderedEvent['type'], listener: (e: TrackChangeRenderedEvent) => void, scope?: object): void;
20602060

20612061
on(type: TtmlParsedEvent['type'], listener: (e: TtmlParsedEvent) => void, scope?: object): void;
@@ -2158,6 +2158,8 @@ export interface MediaPlayerClass {
21582158

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

2161+
getRepresentationsByTypeUnfiltered(type: MediaType, streamId?: string | null): Representation[];
2162+
21612163
getSafeAverageThroughput(type: MediaType, calculationMode?: string | null, sampleSize?: number): number;
21622164

21632165
getSettings(): MediaPlayerSettingClass;

src/streaming/MediaPlayer.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ import VideoModel from './models/VideoModel.js';
7878
import {HTTPRequest} from './vo/metrics/HTTPRequest.js';
7979
import {checkParameterType} from './utils/SupervisorTools.js';
8080
import {getVersionString} from '../core/Version.js';
81-
import { Cta608Parser } from '@svta/cml-608';
81+
import {Cta608Parser} from '@svta/cml-608';
8282

8383
/**
8484
* The media types
@@ -1658,6 +1658,8 @@ function MediaPlayer() {
16581658
}
16591659

16601660
/**
1661+
* This method returns the list of all available representations for a given media type. The returned list is filtered according to the current ABR rules (e.g. max/min bitrate and limitBitrateByPortal).
1662+
* If you want to get the unfiltered list of representations then use getRepresentationsByTypeUnfiltered() instead.
16611663
* @param {MediaType} type
16621664
* @param {string} streamId
16631665
* @returns {Array}
@@ -1666,11 +1668,29 @@ function MediaPlayer() {
16661668
* @instance
16671669
*/
16681670
function getRepresentationsByType(type, streamId = null) {
1671+
return _getRepresentations(type, streamId, true);
1672+
}
1673+
1674+
/**
1675+
* This method returns the list of all available representations for a given media type. The returned list is unfiltered and settings like max/min bitrate and limitBitrateByPortal are not taken into account.
1676+
* If you want to get the filtered list of representations then use getRepresentationsByType() instead.
1677+
* @param {MediaType} type
1678+
* @param {string} streamId
1679+
* @returns {Array}
1680+
* @memberof module:MediaPlayer
1681+
* @throws {@link module:MediaPlayer~STREAMING_NOT_INITIALIZED_ERROR STREAMING_NOT_INITIALIZED_ERROR} if called before initializePlayback function
1682+
* @instance
1683+
*/
1684+
function getRepresentationsByTypeUnfiltered(type, streamId = null) {
1685+
return _getRepresentations(type, streamId, false);
1686+
}
1687+
1688+
function _getRepresentations(type, streamId, filterBySettings = true) {
16691689
if (!streamingInitialized) {
16701690
throw STREAMING_NOT_INITIALIZED_ERROR;
16711691
}
16721692
let stream = streamId ? streamController.getStreamById(streamId) : getActiveStream();
1673-
return stream ? stream.getRepresentationsByType(type) : [];
1693+
return stream ? stream.getRepresentationsByType(type, filterBySettings) : [];
16741694
}
16751695

16761696
/**
@@ -2883,6 +2903,7 @@ function MediaPlayer() {
28832903
getProtectionController,
28842904
getRawThroughputData,
28852905
getRepresentationsByType,
2906+
getRepresentationsByTypeUnfiltered,
28862907
getSafeAverageThroughput,
28872908
getSettings,
28882909
getSource,

src/streaming/Stream.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -719,10 +719,11 @@ function Stream(config) {
719719

720720
/**
721721
* @param {string} type
722+
* @param filterBySettings
722723
* @returns {Array}
723724
* @memberof Stream#
724725
*/
725-
function getRepresentationsByType(type) {
726+
function getRepresentationsByType(type, filterBySettings = true) {
726727
checkConfig();
727728
if (type === Constants.IMAGE) {
728729
if (!thumbnailController) {
@@ -731,7 +732,7 @@ function Stream(config) {
731732
return thumbnailController.getPossibleVoRepresentations();
732733
}
733734
const mediaInfo = _getMediaInfo(type);
734-
return abrController.getPossibleVoRepresentationsFilteredBySettings(mediaInfo, true);
735+
return filterBySettings ? abrController.getPossibleVoRepresentationsFilteredBySettings(mediaInfo, true) : abrController.getPossibleVoRepresentations(mediaInfo, true);
735736
}
736737

737738
/**

test/unit/mocks/StreamControllerMock.js

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import StreamMock from './StreamMock.js';
33
class StreamControllerMock {
44

55
constructor() {
6+
this.streamId = 'DUMMY_STREAM-01';
7+
this.activeStream = new StreamMock();
68
}
79

810
setup() {
9-
this.streamId = 'DUMMY_STREAM-01';
10-
this.activeStream = new StreamMock();
1111
}
1212

1313
initialize(streams) {
@@ -63,12 +63,7 @@ class StreamControllerMock {
6363
}
6464

6565
getStreamById() {
66-
return {
67-
id: this.streamId,
68-
getBitrateListFor: function () {
69-
return [1, 2];
70-
}
71-
};
66+
return this.activeStream;
7267
}
7368

7469
load() {

test/unit/mocks/StreamMock.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ function StreamMock() {
1111
new StreamProcessorMock(TYPE_VIDEO),
1212
new StreamProcessorMock(TYPE_AUDIO)
1313
];
14+
this._representations = {};
15+
this._unfilteredRepresentations = {};
1416
}
1517

1618
StreamMock.prototype.initialize = function (streamInfo) {
@@ -56,4 +58,20 @@ StreamMock.prototype.getCurrentRepresentationForType = function () {
5658
return null;
5759
}
5860

61+
StreamMock.prototype.setRepresentationsByType = function (type, filtered, unfiltered) {
62+
this._representations[type] = filtered;
63+
this._unfilteredRepresentations[type] = unfiltered;
64+
};
65+
66+
StreamMock.prototype.getRepresentationsByType = function (type, filterBySettings) {
67+
if (filterBySettings) {
68+
return this._representations[type] || [];
69+
}
70+
return this._unfilteredRepresentations[type] || [];
71+
};
72+
73+
StreamMock.prototype.getBitrateListFor = function () {
74+
return [1, 2];
75+
};
76+
5977
export default StreamMock;

test/unit/test/streaming/streaming.MediaPlayer.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,14 @@ describe('MediaPlayer', function () {
989989
expect(player.getCurrentRepresentationForType).to.throw('You must first call initialize() and set a source before calling this method');
990990
});
991991

992+
it('Method getRepresentationsByType should throw an exception', function () {
993+
expect(player.getRepresentationsByType).to.throw(STREAMING_NOT_INITIALIZED_ERROR);
994+
});
995+
996+
it('Method getRepresentationsByTypeUnfiltered should throw an exception', function () {
997+
expect(player.getRepresentationsByTypeUnfiltered).to.throw(STREAMING_NOT_INITIALIZED_ERROR);
998+
});
999+
9921000
it('Method getStreamsFromManifest should throw an exception', function () {
9931001
expect(player.getStreamsFromManifest).to.throw('You must first call initialize() and set a source before calling this method');
9941002
});
@@ -1148,6 +1156,92 @@ describe('MediaPlayer', function () {
11481156
});
11491157
});
11501158

1159+
describe('getRepresentationsByType and getRepresentationsByTypeUnfiltered', function () {
1160+
const filteredVideoReps = [
1161+
{ id: 'rep1', bandwidth: 500000 },
1162+
{ id: 'rep2', bandwidth: 1000000 }
1163+
];
1164+
const unfilteredVideoReps = [
1165+
{ id: 'rep1', bandwidth: 500000 },
1166+
{ id: 'rep2', bandwidth: 1000000 },
1167+
{ id: 'rep3', bandwidth: 3000000 }
1168+
];
1169+
const filteredAudioReps = [{ id: 'audioRep1', bandwidth: 128000 }];
1170+
const unfilteredAudioReps = [
1171+
{ id: 'audioRep1', bandwidth: 128000 },
1172+
{ id: 'audioRep2', bandwidth: 256000 }
1173+
];
1174+
1175+
beforeEach(function () {
1176+
player.initialize(videoElementMock, dummyUrl, false);
1177+
streamControllerMock.getActiveStream().setRepresentationsByType('video', filteredVideoReps, unfilteredVideoReps);
1178+
streamControllerMock.getActiveStream().setRepresentationsByType('audio', filteredAudioReps, unfilteredAudioReps);
1179+
});
1180+
1181+
describe('getRepresentationsByType', function () {
1182+
it('should return filtered representations from the active stream when no streamId is provided', function () {
1183+
const reps = player.getRepresentationsByType('video');
1184+
expect(reps).to.deep.equal(filteredVideoReps);
1185+
});
1186+
1187+
it('should return filtered representations for a specific streamId', function () {
1188+
const reps = player.getRepresentationsByType('video', 'DUMMY_STREAM-01');
1189+
expect(reps).to.deep.equal(filteredVideoReps);
1190+
});
1191+
1192+
it('should return filtered audio representations', function () {
1193+
const reps = player.getRepresentationsByType('audio');
1194+
expect(reps).to.have.lengthOf(1);
1195+
expect(reps[0].id).to.equal('audioRep1');
1196+
});
1197+
1198+
it('should return empty array when no stream is available', function () {
1199+
streamControllerMock.getActiveStreamInfo = function () { return null; };
1200+
const reps = player.getRepresentationsByType('video');
1201+
expect(reps).to.be.empty;
1202+
});
1203+
1204+
it('should return empty array for a type with no representations configured', function () {
1205+
const reps = player.getRepresentationsByType('text');
1206+
expect(reps).to.be.empty;
1207+
});
1208+
});
1209+
1210+
describe('getRepresentationsByTypeUnfiltered', function () {
1211+
it('should return unfiltered representations from the active stream when no streamId is provided', function () {
1212+
const reps = player.getRepresentationsByTypeUnfiltered('video');
1213+
expect(reps).to.deep.equal(unfilteredVideoReps);
1214+
});
1215+
1216+
it('should return unfiltered representations for a specific streamId', function () {
1217+
const reps = player.getRepresentationsByTypeUnfiltered('video', 'DUMMY_STREAM-01');
1218+
expect(reps).to.deep.equal(unfilteredVideoReps);
1219+
});
1220+
1221+
it('should return unfiltered audio representations', function () {
1222+
const reps = player.getRepresentationsByTypeUnfiltered('audio');
1223+
expect(reps).to.have.lengthOf(2);
1224+
});
1225+
1226+
it('should return more representations than the filtered method', function () {
1227+
const filtered = player.getRepresentationsByType('video');
1228+
const unfiltered = player.getRepresentationsByTypeUnfiltered('video');
1229+
expect(unfiltered.length).to.be.greaterThan(filtered.length);
1230+
});
1231+
1232+
it('should return empty array when no stream is available', function () {
1233+
streamControllerMock.getActiveStreamInfo = function () { return null; };
1234+
const reps = player.getRepresentationsByTypeUnfiltered('video');
1235+
expect(reps).to.be.empty;
1236+
});
1237+
1238+
it('should return empty array for a type with no representations configured', function () {
1239+
const reps = player.getRepresentationsByTypeUnfiltered('text');
1240+
expect(reps).to.be.empty;
1241+
});
1242+
});
1243+
});
1244+
11511245
describe('Protection Management Functions', function () {
11521246
});
11531247

0 commit comments

Comments
 (0)