Skip to content

Commit

Permalink
Allow configuring adaptive buffering by passing config object as `buf…
Browse files Browse the repository at this point in the history
…ferTime` driver option
  • Loading branch information
ku1ik committed Apr 27, 2024
1 parent c0cfdc1 commit 0950a6d
Showing 1 changed file with 18 additions and 24 deletions.
42 changes: 18 additions & 24 deletions src/buffer.js
Expand Up @@ -5,6 +5,7 @@ function getBuffer(bufferTime, feed, setTime, baseStreamTime, minFrameTime, logg
logger.debug("using no buffer");
return nullBuffer(feed);
} else {
bufferTime = bufferTime ?? {};
let getBufferTime;

if (typeof bufferTime === "number") {
Expand All @@ -14,8 +15,8 @@ function getBuffer(bufferTime, feed, setTime, baseStreamTime, minFrameTime, logg
logger.debug("using custom dynamic buffer");
getBufferTime = bufferTime({ logger });
} else {
logger.debug("using adaptive buffer");
getBufferTime = adaptiveBufferTimeProvider({ logger });
logger.debug("using adaptive buffer", bufferTime);
getBufferTime = adaptiveBufferTimeProvider({ logger }, bufferTime);
}

return buffer(getBufferTime, feed, setTime, logger, baseStreamTime ?? 0.0, minFrameTime);
Expand Down Expand Up @@ -117,41 +118,42 @@ function sleep(t) {
});
}

const MIN_BUFFER_TIME = 25;
const MAX_BUFFER_LEVEL = 100;
const BUFFER_TIME_MULTIPLIER = 50;
const LATENCY_WINDOW_SIZE = 20;
const SMOOTHING_FACTOR = 0.2;
const MIN_IMPROVEMENT_DURATION = 1000;

function adaptiveBufferTimeProvider({ logger }) {
function adaptiveBufferTimeProvider({ logger }, { minTime = 25, maxLevel = 100, interval = 50, windowSize = 20, smoothingFactor = 0.2, minImprovementDuration = 1000 }) {
let bufferLevel = 0;
let bufferTime = calcBufferTime(bufferLevel);
let latencies = [];
let maxJitter = 0;
let jitterRange = 0;
let improvementTs = null;

function calcBufferTime(level) {
if (level === 0) {
return minTime;
} else {
return interval * level;
}
}

return (latency) => {
latencies.push(latency);

if (latencies.length < LATENCY_WINDOW_SIZE) {
if (latencies.length < windowSize) {
return bufferTime;
};

latencies = latencies.slice(-LATENCY_WINDOW_SIZE);
latencies = latencies.slice(-windowSize);
const currentMinJitter = min(latencies);
const currentMaxJitter = max(latencies);
const currentJitterRange = currentMaxJitter - currentMinJitter;
maxJitter = currentMaxJitter * SMOOTHING_FACTOR + maxJitter * (1 - SMOOTHING_FACTOR);
jitterRange = currentJitterRange * SMOOTHING_FACTOR + jitterRange * (1 - SMOOTHING_FACTOR);
maxJitter = currentMaxJitter * smoothingFactor + maxJitter * (1 - smoothingFactor);
jitterRange = currentJitterRange * smoothingFactor + jitterRange * (1 - smoothingFactor);
const minBufferTime = maxJitter + jitterRange;

if (latency > bufferTime) {
logger.debug('buffer underrun', { latency, maxJitter, jitterRange, bufferTime });
}

if (bufferLevel < MAX_BUFFER_LEVEL && minBufferTime > bufferTime) {
if (bufferLevel < maxLevel && minBufferTime > bufferTime) {
bufferTime = calcBufferTime((bufferLevel += 1));
logger.debug(`jitter increased, raising bufferTime`, { latency, maxJitter, jitterRange, bufferTime });
} else if (
Expand All @@ -160,7 +162,7 @@ function adaptiveBufferTimeProvider({ logger }) {
) {
if (improvementTs === null) {
improvementTs = performance.now();
} else if (performance.now() - improvementTs > MIN_IMPROVEMENT_DURATION) {
} else if (performance.now() - improvementTs > minImprovementDuration) {
improvementTs = performance.now();
bufferTime = calcBufferTime((bufferLevel -= 1));
logger.debug(`jitter decreased, lowering bufferTime`, { latency, maxJitter, jitterRange, bufferTime });
Expand All @@ -183,12 +185,4 @@ function max(numbers) {
return numbers.reduce((prev, cur) => cur > prev ? cur : prev);
}

function calcBufferTime(level) {
if (level === 0) {
return MIN_BUFFER_TIME;
} else {
return BUFFER_TIME_MULTIPLIER * level;
}
}

export default getBuffer;

0 comments on commit 0950a6d

Please sign in to comment.