import { type VideoLimit, type VideoRole } from "./videoDemand.js"; /** Video spends this much of what's left after audio; the rest absorbs the estimate's wobble. */ export declare const SPEND = 0.9; export declare const RISE_MARGIN = 1.2; export declare const RISE_AFTER_MS = 2000; /** A keyframe at 0.8 Mbps stalled a 1080p share for up to 7 s, which is no reason to shrink it. */ export declare const DRASTIC_AFTER_MS = 10000; /** Off until they pay off (GRYT-1572): at 0.5 Mbps they cost 23 share freezes against 0.6.0's 19. */ export declare const DRASTIC_CUTS = false; export declare const MIN_CAMERA_FPS = 15; /** Under 10 fps, VideoToolbox stalled a text share for seconds at a time at 0.8 Mbps. */ export declare const MIN_SCREEN_FPS = 10; export declare const MIN_HEIGHT = 180; /** A stream's need is 25% over what it was seen to use, so a busier picture has room to show. */ export declare const HEADROOM = 1.25; /** A fall with the sender this far under the estimate is Chrome decaying an idle estimate, not congestion. */ export declare const APP_LIMITED = 1.5; export interface BudgetStream { role: VideoRole; source: { width: number; height: number; }; /** What demand and the user's ceiling ask for, before the budget. */ scale: number; fps: number; maxBitrate?: number; /** A share drawn at half its size or more: the one kept sharp, and cut last. */ large: boolean; /** maintain-framerate, as a gaming share asks: it gives up size before frames. */ keepFramerate?: boolean; /** Bits per second it was seen to need at its source size and 30 fps, or null before any. */ rate: number | null; /** It encoded under 60% of the frames it's allowed last second. */ starved?: boolean; /** Last second's limit: nothing goes back up until it fits with RISE_MARGIN to spare. */ was?: VideoLimit | null; } /** The most a stream may take at this size: the bitrate rule, under the user's own cap. */ export declare function streamCeiling(s: BudgetStream, scale: number, fps: number): number; /** What a stream needs at this size: its ceiling, or less when it was seen to use less. */ export declare function streamNeed(s: BudgetStream, scale: number, fps: number): number; /** A rate sample from bits sent, normalised to the source size and 30 fps, averaged in slowly. */ export declare function learnRate(previous: number | null, used: number, scale: number, fps: number, limited: boolean): number | null; export interface BudgetSplit { limits: VideoLimit[]; /** It only fits by pausing the camera or shrinking the large share, which wait for DRASTIC_AFTER_MS. */ short: boolean; /** Short even with RISE_MARGIN to spare, which is what lifting those two cuts waits for. */ shortWithMargin?: boolean; } /** * Section 3's rule: cut until the streams fit the budget, then share out what's left, the * large share first. A cut takes effect at once; undoing one waits for RISE_MARGIN of room. */ export declare function splitVideoBudget(budget: number, streams: BudgetStream[], drastic: boolean, spend?: number): BudgetSplit; export interface BudgetState { /** The estimate the split follows: down at once, up only after RISE_AFTER_MS of RISE_MARGIN headroom. */ estimate: number | null; riseSince: number | null; riseLow: number; shortSince: number | null; /** This second's estimate, which the bitrates follow both ways; null when it only sank for want of traffic. */ current: number | null; } export declare const INITIAL_BUDGET_STATE: BudgetState; /** Follows availableOutgoingBitrate, given what was sent over the same second. */ export declare function followEstimate(state: BudgetState, raw: number | null, sent: number, now: number): BudgetState; export interface BudgetPlanInput { now: number; estimate: number | null; /** The SFU's ingest cap for this peer, in bits per second, if the operator set one. */ ingestCap: number | null; /** Bits per second going to audio, and to any video the engine can't set. */ reserved: number; sent: number; streams: BudgetStream[]; /** Pausing the camera and shrinking the large share. Defaults to DRASTIC_CUTS. */ drasticCuts?: boolean; } /** The split for this second, or null limits when there's no estimate to split. */ export declare function planVideoBudget(input: BudgetPlanInput, previous: BudgetState): { limits: VideoLimit[] | null; budget: number | null; state: BudgetState; };