Skip to content

feat: EWMA throughput estimator + measured cellular ceiling (fixes #24) - #37

Merged
joeblau merged 1 commit into
mainfrom
feat/24-ewma-throughput-estimator
Jul 6, 2026
Merged

feat: EWMA throughput estimator + measured cellular ceiling (fixes #24)#37
joeblau merged 1 commit into
mainfrom
feat/24-ewma-throughput-estimator

Conversation

@joeblau

@joeblau joeblau commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Closes #24 (M9 · EWMA throughput estimator + measured cellular ceiling).

Problem

The ABR was reactive-only and hard-capped any cellular path at 2.5 Mbps regardless of the real 5G uplink. Recovery started from a low seed and could never exceed the cap.

What changed

ThroughputEstimator (new, StreamCore): pure Sendable/Equatable EWMA (0.4 factor) fed the 1 Hz currentBytesOutPerSecond the network monitor already surfaces. First positive sample verbatim; stalls ignored; reset() on handoff.

NetworkPathSnapshot: the 2.5 Mbps cellular value is now a seed, not a hard ceiling. videoBitRateCeiling keeps the genuine hard caps (Low Data Mode 1.2M, ultra-constrained 0.8M, minimal-link halving); new videoBitRateSeed returns the conservative opening bid (2.5M on cellular/expensive, hard ceiling otherwise).

AdaptiveBitRateState: opens cellular at the seed, and the upward probe climbs freely below the seed (recovery) but only above it (toward the user max) when the audio-netted EWMA is within 90% of the target and the queue has been clean for 30 s. A sustained clean queue clears congestion (restoring full frame rate) even while the target is held at the seed.

Publishers: RTMP and the shared SRT/WHIP controller pass the seed alongside the ceiling and feed live audio bitrate into the status path.

Design note (from review)

The reduction stays on the raw congestion-tick egress (≈ true capacity during sustained queue growth). The EWMA is used only for the probe gate: egress conflates encoder demand (healthy ticks) with link capacity (congestion), and two adversarial review rounds showed that smoothing the cut against it regresses congestion response in both directions. The estimator's sound job is confirming the link is delivering the rate before climbing above the conservative seed.

Testing

CI-run Swift Testing suites: AdaptiveBitRateStateTests (new cases for reduction-vs-EWMA, cellular seed/probe, frame-rate restoration, audio-netting), ThroughputEstimatorTests, updated SharedSupervisionTests. All arithmetic independently validated against the compiled StreamCore types (25 assertions). Two adversarial multi-agent review rounds; all findings resolved.

🤖 Generated with Claude Code

The ABR was reactive-only and hard-capped any cellular path at 2.5 Mbps
regardless of the real 5G uplink. This turns that hard cap into a soft SEED
the upward probe can exceed toward the user max once measured throughput and
a sustained clean queue justify it, and adds an EWMA throughput estimator.

StreamCore/ThroughputEstimator.swift (new):
- Pure, Sendable/Equatable EWMA (0.4 factor) fed the 1 Hz currentBytesOutPerSecond
  the network monitor already surfaces. First positive sample is adopted verbatim;
  non-positive samples (stalls) are ignored; reset() drops the estimate on handoff.

NetworkPathSnapshot:
- videoBitRateCeiling no longer hard-caps cellular/expensive at 2.5 Mbps (Low Data
  Mode / ultra-constrained / minimal-link-quality remain hard caps).
- New videoBitRateSeed returns the conservative opening bid: 2.5 Mbps on
  cellular/expensive, the hard ceiling otherwise.

AdaptiveBitRateState:
- pathSeed + throughput fields. onPathProfile(ceiling:seed:...) opens cellular at
  the seed on baseline, seeds a handoff from lastGoodTarget (measurement-derived)
  or the conservative cold seed, and resets the estimator on a genuine handoff.
- Upward probe climbs freely below the seed (recovery) but only ABOVE it when the
  audio-netted EWMA is within 90% of the target AND the queue has been clean 30 s.
- A sustained clean queue clears congestion (restoring full frame rate) even when
  the target is held at the seed below effectiveMaximum, and signals an apply on
  the clearing tick so the encoder actually restores fps.

Publishers: both RTMP and the shared SRT/WHIP controller pass the seed alongside
the ceiling, and feed live audio bitrate into the status path so the probe gate
compares video-vs-video.

Reduction stays on the raw congestion-tick egress (true capacity during sustained
queue growth); the EWMA is used only for the probe gate, because egress conflates
encoder demand (healthy ticks) with link capacity (congestion) and smoothing the
cut against it regresses congestion response either way.

Validated by two adversarial review rounds and CI-run Swift Testing suites
(AdaptiveBitRateStateTests, ThroughputEstimatorTests, SharedSupervisionTests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@joeblau
joeblau merged commit 6b6e999 into main Jul 6, 2026
1 check passed
@joeblau
joeblau deleted the feat/24-ewma-throughput-estimator branch July 6, 2026 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

M9 · EWMA throughput estimator + measured cellular ceiling

1 participant