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
195 changes: 147 additions & 48 deletions src/core/adaptive/__tests__/buffer_based_chooser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

import { ScoreConfidenceLevel } from "../utils/representation_score_calculator";

/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-var-requires */
Expand Down Expand Up @@ -47,12 +49,25 @@ describe("BufferBasedChooser", () => {
bufferGap: 0,
speed: 1,
currentBitrate: undefined,
currentScore: 4,
currentScore: { score: 4, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(1);
expect(new BufferBasedChooser([1, 2, 3]).getEstimate({
bufferGap: 0,
speed: 1,
currentBitrate: undefined,
currentScore: { score: 4, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(1);
expect(new BufferBasedChooser([1, 2, 3]).getEstimate({
bufferGap: 0,
speed: 1,
currentBitrate: undefined,
currentScore: { score: 1, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(1);
expect(new BufferBasedChooser([1, 2, 3]).getEstimate({
bufferGap: 0,
speed: 1,
currentScore: 1,
currentBitrate: undefined,
currentScore: { score: 1, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(1);
});

Expand All @@ -76,7 +91,7 @@ describe("BufferBasedChooser", () => {
});

/* eslint-disable max-len */
it("should go to the next bitrate if the current one is maintainable and we have more buffer than the next level", () => {
it("should not go to the next bitrate if we don't have a high enough maintainability score", () => {
/* eslint-enable max-len */
const logger = { debug: jest.fn() };
jest.mock("../../../log", () => ({ __esModule: true as const,
Expand All @@ -86,82 +101,82 @@ describe("BufferBasedChooser", () => {
bufferGap: 16,
speed: 1,
currentBitrate: 10,
currentScore: 1.01,
})).toEqual(20);
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(10);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 30,
speed: 1,
currentBitrate: 20,
currentScore: 1.01,
})).toEqual(40);
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 30,
speed: 1,
currentBitrate: 20,
currentScore: 100,
})).toEqual(40);
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 30,
speed: 2,
currentBitrate: 20,
currentScore: 2.1,
})).toEqual(40);
currentScore: { score: 2.30, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
bufferGap: 30,
speed: 2,
currentBitrate: 20,
currentScore: 2.1,
})).toEqual(40);
currentScore: { score: 2.30, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 30,
speed: 0, // 0 is a special case
currentBitrate: 20,
currentScore: 100,
})).toEqual(40);
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(20);
});

/* eslint-disable max-len */
it("should go to the next bitrate if the current one is maintainable and we have the buffer corresponding to the next level", () => {
it("should go to the next bitrate if the current one is maintainable and we have more buffer than the next level", () => {
/* eslint-enable max-len */
const logger = { debug: jest.fn() };
jest.mock("../../../log", () => ({ __esModule: true as const,
default: logger }));
const BufferBasedChooser = jest.requireActual("../buffer_based_chooser").default;
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 15,
bufferGap: 16,
speed: 1,
currentBitrate: 10,
currentScore: 1.01,
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 20,
bufferGap: 30,
speed: 1,
currentBitrate: 20,
currentScore: 1.01,
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(40);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 20,
bufferGap: 30,
speed: 1,
currentBitrate: 20,
currentScore: 100,
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(40);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 20,
bufferGap: 30,
speed: 2,
currentBitrate: 20,
currentScore: 2.1,
currentScore: { score: 2.30, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(40);
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
bufferGap: 20,
bufferGap: 30,
speed: 2,
currentBitrate: 20,
currentScore: 2.1,
currentScore: { score: 2.30, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(40);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 20,
bufferGap: 30,
speed: 0, // 0 is a special case
currentBitrate: 20,
currentScore: 100,
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(40);
});

Expand All @@ -176,31 +191,31 @@ describe("BufferBasedChooser", () => {
bufferGap: 6,
speed: 1,
currentBitrate: 10,
currentScore: 1.01,
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(10);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 10,
bufferGap: 13,
speed: 1,
currentBitrate: 20,
currentScore: 1.01,
currentScore: { score: 1.15, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 10,
bufferGap: 13,
speed: 1,
currentBitrate: 20,
currentScore: 100,
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
bufferGap: 10,
bufferGap: 13,
speed: 1,
currentBitrate: 20,
currentScore: 100,
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 10,
bufferGap: 13,
speed: 2,
currentBitrate: 20,
currentScore: 2.1,
currentScore: { score: 2.30, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(20);
});

Expand All @@ -216,13 +231,13 @@ describe("BufferBasedChooser", () => {
bufferGap: 100000000000,
speed: 1,
currentBitrate: 40,
currentScore: 1000000,
currentScore: { score: 1000000, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(40);
expect(new BufferBasedChooser([10, 20, 40, 40]).getEstimate({
bufferGap: 100000000000,
speed: 1,
currentBitrate: 40,
currentScore: 1000000,
currentScore: { score: 1000000, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(40);
});

Expand All @@ -237,31 +252,115 @@ describe("BufferBasedChooser", () => {
bufferGap: 15,
speed: 2,
currentBitrate: 10,
currentScore: 1.01,
currentScore: { score: 2, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(10);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 20,
bufferGap: 22,
speed: 2,
currentBitrate: 20,
currentScore: 1.01,
currentScore: { score: 2, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 20,
bufferGap: 22,
speed: 100,
currentBitrate: 20,
currentScore: 100,
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
bufferGap: 20,
bufferGap: 22,
speed: 100,
currentBitrate: 20,
currentScore: 100,
currentScore: { score: 100, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 20,
bufferGap: 22,
speed: 3,
currentBitrate: 20,
currentScore: { score: 3, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(20);
});

/* eslint-disable max-len */
it("should lower bitrate if the current one is not maintainable due to the speed", () => {
/* eslint-enable max-len */
const logger = { debug: jest.fn() };
jest.mock("../../../log", () => ({ __esModule: true as const,
default: logger }));
const BufferBasedChooser = jest.requireActual("../buffer_based_chooser").default;
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 15,
speed: 2,
currentBitrate: 10,
currentScore: { score: 1.9, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(10);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 22,
speed: 2,
currentBitrate: 20,
currentScore: { score: 1.9, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(10);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 22,
speed: 100,
currentBitrate: 20,
currentScore: { score: 99, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(10);
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
bufferGap: 22,
speed: 100,
currentBitrate: 20,
currentScore: { score: 99, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(10);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 22,
speed: 3,
currentBitrate: 20,
currentScore: { score: 2.5, confidenceLevel: ScoreConfidenceLevel.HIGH },
})).toEqual(10);
});

/* eslint-disable max-len */
it("should not lower bitrate if the current one is not maintainable due to the speed but confidence on the score is low", () => {
/* eslint-enable max-len */
const logger = { debug: jest.fn() };
jest.mock("../../../log", () => ({ __esModule: true as const,
default: logger }));
const BufferBasedChooser = jest.requireActual("../buffer_based_chooser").default;
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 15,
speed: 2,
currentBitrate: 10,
currentScore: { score: 1.9, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(10);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 22,
speed: 2,
currentBitrate: 20,
currentScore: undefined,
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 22,
speed: 2,
currentBitrate: 20,
currentScore: { score: 1.9, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 22,
speed: 100,
currentBitrate: 20,
currentScore: { score: 99, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 20, 40]).getEstimate({
bufferGap: 22,
speed: 100,
currentBitrate: 20,
currentScore: { score: 99, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(20);
expect(new BufferBasedChooser([10, 20, 40]).getEstimate({
bufferGap: 22,
speed: 3,
currentBitrate: 20,
currentScore: 2.1,
currentScore: { score: 2.5, confidenceLevel: ScoreConfidenceLevel.LOW },
})).toEqual(20);
});

Expand Down
11 changes: 7 additions & 4 deletions src/core/adaptive/adaptive_representation_selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import config from "../../config";
import log from "../../log";
import Manifest, {
Adaptation,
Expand Down Expand Up @@ -316,8 +317,7 @@ function getEstimateReference(
const timeRanges = val.buffered;
const bufferGap = getLeftSizeOfRange(timeRanges, position.last);
const { representation } = val.content;
const scoreData = scoreCalculator.getEstimate(representation);
const currentScore = scoreData?.[0];
const currentScore = scoreCalculator.getEstimate(representation);
const currentBitrate = representation.bitrate;
const observation = { bufferGap, currentBitrate, currentScore, speed };
currentBufferBasedEstimate = bufferBasedChooser.getEstimate(observation);
Expand Down Expand Up @@ -362,11 +362,14 @@ function getEstimateReference(
lastPlaybackObservation.speed :
1);

if (allowBufferBasedEstimates && bufferGap <= 5) {
const { ABR_ENTER_BUFFER_BASED_ALGO,
ABR_EXIT_BUFFER_BASED_ALGO } = config.getCurrent();

if (allowBufferBasedEstimates && bufferGap <= ABR_EXIT_BUFFER_BASED_ALGO) {
allowBufferBasedEstimates = false;
} else if (!allowBufferBasedEstimates &&
isFinite(bufferGap) &&
bufferGap > 10)
bufferGap >= ABR_ENTER_BUFFER_BASED_ALGO)
{
allowBufferBasedEstimates = true;
}
Expand Down
Loading