197 lines
6.8 KiB
TypeScript
197 lines
6.8 KiB
TypeScript
// Metro module 12879 (f12880).
|
|
import { VideoToggleState } from "../Constants";
|
|
import Logger from "../modules/debug/Logger";
|
|
import { isMobile } from "../_bundle/Module4426";
|
|
import dispatchAutoDisableVideo from "../modules/media_engine/dispatchAutoDisableVideo";
|
|
import { now } from "../_bundle/sleep";
|
|
import Durations from "../utils/Durations";
|
|
export class VideoHealthManager {
|
|
static defaultConfig = {
|
|
featureEnabled: isMobile,
|
|
windowLength: 5,
|
|
allowedPoorFpsRatio: 1,
|
|
fpsThreshold: 5,
|
|
backoffTimeSec: 15
|
|
};
|
|
constructor(a0, a1, a2, a3) {
|
|
const r27 = {
|
|
__proto__: new.target.prototype,
|
|
logger: new Logger("VideoHealthManager"),
|
|
disabled: false,
|
|
perUserFpsWindow: null,
|
|
prevFramesCodec: null,
|
|
prevTimestamp: null,
|
|
streamDisabledUsers: null,
|
|
retryBackoffCache: null,
|
|
timeoutIdCache: null,
|
|
currentVideoAutoToggleState: null,
|
|
enableQueue: null
|
|
};
|
|
r27.perUserFpsWindow = {};
|
|
r27.prevFramesCodec = {};
|
|
r27.prevTimestamp = {};
|
|
r27.streamDisabledUsers = new Set();
|
|
r27.retryBackoffCache = {};
|
|
r27.timeoutIdCache = {};
|
|
r27.currentVideoAutoToggleState = {};
|
|
r27.enableQueue = [];
|
|
r27.windowLength = a0;
|
|
r27.fpsThreshold = a2;
|
|
r27.fpsWindowBorderlineCount = Math.ceil(a0 * a1);
|
|
r27.backoffTimeSec = a3;
|
|
r27.logger.enableNativeLogger(true);
|
|
r27.logger.info(`constructor with windowLength = ${r27.windowLength},
|
|
fpsWindowBorderlineCount = ${r27.fpsWindowBorderlineCount},
|
|
fpsThreshold = ${r27.fpsThreshold},
|
|
backoffTimeSec = ${a3}`);
|
|
return r27;
|
|
}
|
|
calculateFps(a0, a1, a2) {
|
|
if (this.prevFramesCodec[a0] !== -1 && !(a1 < this.prevFramesCodec[a0]) && !(a2 < this.prevTimestamp[a0]) && !(a2 > this.prevTimestamp[a0] + 1000 * this.windowLength)) {
|
|
if (a2 < this.prevTimestamp[a0] + 900) {
|
|
return NaN;
|
|
}
|
|
const r24 = this.elapsedSeconds(a2, this.prevTimestamp[a0]);
|
|
this.prevTimestamp[a0] = a2;
|
|
const r29 = (a1 - this.prevFramesCodec[a0]) / r24;
|
|
this.prevFramesCodec[a0] = a1;
|
|
return r29;
|
|
}
|
|
this.prevFramesCodec[a0] = a1;
|
|
this.prevTimestamp[a0] = a2;
|
|
this.perUserFpsWindow[a0] = [];
|
|
return NaN;
|
|
}
|
|
updateFps(a0, a1, a2) {
|
|
L15: {
|
|
if (!this.disabled && !this.streamDisabledUsers.has(a0)) {
|
|
const r8 = this.calculateFps(a0, a1, a2);
|
|
if (!(r8 < 0) && Number.isFinite(r8)) {
|
|
this.perUserFpsWindow[a0].push(r8);
|
|
if (this.perUserFpsWindow[a0].length < this.windowLength) {
|
|
return void 0;
|
|
}
|
|
if (this.perUserFpsWindow[a0].length > this.windowLength) {
|
|
this.perUserFpsWindow[a0].shift();
|
|
}
|
|
if (this.perUserFpsWindow[a0].filter((item) => item < this.fpsThreshold).length >= this.fpsWindowBorderlineCount) {
|
|
this.logger.info(`${a0}: detected poor network quality, turning off video`);
|
|
this.streamDisabledUsers.add(a0);
|
|
this.currentVideoAutoToggleState[a0] = VideoToggleState.DISABLED;
|
|
dispatchAutoDisableVideo(a0, VideoToggleState.DISABLED);
|
|
this.startReenableBackoffTimer(a0);
|
|
} else if (this.currentVideoAutoToggleState[a0] === VideoToggleState.AUTO_PROBING) {
|
|
this.currentVideoAutoToggleState[a0] = VideoToggleState.AUTO_ENABLED;
|
|
this.logger.info(`acceptable conditions reached, will reset and send a AUTO_ENABLED for user ${a0}`);
|
|
dispatchAutoDisableVideo(a0, VideoToggleState.AUTO_ENABLED);
|
|
}
|
|
if (this.probingUserId !== a0) {
|
|
break L15;
|
|
}
|
|
this.probingUserId = void 0;
|
|
this.tryReenableQueue();
|
|
break L15;
|
|
}
|
|
return void 0;
|
|
}
|
|
}
|
|
}
|
|
startReenableBackoffTimer(a0) {
|
|
if (!this.disabled) {
|
|
this.logger.info(`startReenableBackoffTimer for user ${a0}`);
|
|
const r19 = this.retryBackoffCache[a0];
|
|
const { lastBackoffTime, expBackoffFactor } = r19;
|
|
const expBackoffFactor2 = lastBackoffTime !== null ? expBackoffFactor > 16 ? 1 : this.elapsedSeconds(now(), lastBackoffTime) > 600 ? 1 : expBackoffFactor * 2 : 1;
|
|
this.retryBackoffCache[a0] = {
|
|
lastBackoffTime: now(),
|
|
expBackoffFactor: expBackoffFactor2
|
|
};
|
|
const r50 = expBackoffFactor2 * this.backoffTimeSec * Durations.Millis.SECOND;
|
|
this.logger.info(`starting backoff timer with time = ${r50} milliseconds`);
|
|
this.timeoutIdCache[a0] = setTimeout(() => {
|
|
this.queueReenable(a0);
|
|
}, r50);
|
|
}
|
|
}
|
|
queueReenable(a0) {
|
|
this.enableQueue.push(a0);
|
|
this.tryReenableQueue();
|
|
}
|
|
tryReenableQueue() {
|
|
let r14;
|
|
L7: {
|
|
if (!this.disabled) {
|
|
if (this.probingUserId != null && this.probingUserId in this.perUserFpsWindow) {
|
|
break L7;
|
|
}
|
|
const r9 = this.enableQueue.shift();
|
|
if (r9 != null && !this.reenableVideo(r9)) {
|
|
do {
|
|
r14 = this.enableQueue.shift();
|
|
if (r14 == null) {
|
|
break;
|
|
}
|
|
} while (!this.reenableVideo(r14));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
reenableVideo(a0) {
|
|
let r0 = a0 in this.perUserFpsWindow;
|
|
if (r0) {
|
|
this.logger.info(`reenableVideo called for user ${a0} - time = ${now()}`);
|
|
this.stateCleanupBeforeEnable(a0);
|
|
this.currentVideoAutoToggleState[a0] = VideoToggleState.AUTO_PROBING;
|
|
this.probingUserId = a0;
|
|
dispatchAutoDisableVideo(a0, VideoToggleState.AUTO_PROBING);
|
|
r0 = true;
|
|
}
|
|
return r0;
|
|
}
|
|
elapsedSeconds(a0, a1) {
|
|
return (a0 - a1) / 1000;
|
|
}
|
|
stateCleanupBeforeEnable(a0) {
|
|
this.logger.info("VideoHealthManager::stateCleanupBeforeEnable");
|
|
this.perUserFpsWindow[a0] = [];
|
|
this.prevFramesCodec[a0] = -1;
|
|
this.streamDisabledUsers.delete(a0);
|
|
}
|
|
getCurrentVideoToggleState(a0) {
|
|
return this.currentVideoAutoToggleState[a0];
|
|
}
|
|
createUser(a0) {
|
|
this.logger.info(`VideoHealthManager::createUser ${a0}`);
|
|
if (!(a0 in this.perUserFpsWindow)) {
|
|
this.perUserFpsWindow[a0] = [];
|
|
this.prevFramesCodec[a0] = -1;
|
|
this.currentVideoAutoToggleState[a0] = VideoToggleState.NONE;
|
|
this.retryBackoffCache[a0] = {
|
|
lastBackoffTime: null,
|
|
expBackoffFactor: 1
|
|
};
|
|
}
|
|
}
|
|
deleteUser(a0) {
|
|
this.logger.info(`VideoHealthManager::deleteUser ${a0}`);
|
|
delete this.perUserFpsWindow[a0];
|
|
delete this.prevFramesCodec[a0];
|
|
delete this.retryBackoffCache[a0];
|
|
delete this.currentVideoAutoToggleState[a0];
|
|
this.streamDisabledUsers.delete(a0);
|
|
if (a0 === this.probingUserId) {
|
|
this.probingUserId = void 0;
|
|
this.tryReenableQueue();
|
|
}
|
|
clearTimeout(this.timeoutIdCache[a0]);
|
|
delete this.timeoutIdCache[a0];
|
|
}
|
|
disable() {
|
|
this.disabled = true;
|
|
const perUserFpsWindow = this.perUserFpsWindow;
|
|
for (const key in perUserFpsWindow) {
|
|
this.deleteUser(key);
|
|
}
|
|
}
|
|
}
|