blob: 7ce162c9a0e18f16281aff30120c92f1b0d45411 [file] [view]
# SCReAM v2 Implementation Differences
**Date:** June 9, 2026\
**Commit:**
[f48df12def0d531a66a3dffcea021fbe0f99dcde](https://webrtc.googlesource.com/src/+/f48df12def0d531a66a3dffcea021fbe0f99dcde)\
**Note:** This document was automatically generated by an AI assistant (Gemini)
comparing the WebRTC source code with the IETF specification.
This document describes the differences between the WebRTC implementation of
SCReAM v2 and the IETF draft
[draft-johansson-ccwg-rfc8298bis-screamv2-07](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html).
The WebRTC implementation is currently in development and some features are not
yet fully implemented.
## 4. Detailed Description of SCReAMv2 Sender Algorithm
### 4.1. Sender Side State
#### 4.1.1. Status Update When Sending Data
- **Differences in Default Parameters:**
- `MinRefWindow` (`MIN_REF_WND` in spec): The spec recommends **3000 bytes**
([Section 4.2.2](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.2)).
The WebRTC implementation defaults to **1000 bytes** in
[scream_v2_parameters.cc:L21](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2_parameters.cc#21).
- `MaxSegmentSize` (`MSS` in spec): The spec recommends **1000 bytes**
([Section 4.2.2](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.2)).
The WebRTC implementation defaults to **1280 bytes** in
[scream_v2_parameters.cc:L29](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2_parameters.cc#29).
- `BytesInFlightHeadRoom` (`BYTES_IN_FLIGHT_HEAD_ROOM` in spec): The spec
recommends **1.5**
([Section 4.2.2](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.2)).
The WebRTC implementation defaults to **1.1** in
[scream_v2_parameters.cc:L30](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2_parameters.cc#30).
#### 4.1.2. Status Update on Receiving Feedback
- The WebRTC implementation defines the feedback structure in
[scream_feedback.h](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_feedback.h).
- Instead of tracking `bytes_newly_acked` and `bytes_newly_acked_ce` separately
and resetting them after window updates as described in the spec
([Section 4.1.2](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.1.2)),
the WebRTC `ScreamFeedback` struct directly provides `acked_not_marked_size`
(sum of sizes of packets in the feedback that are NOT ECN CE-marked) and
`num_ce_marked_packets`. This simplifies the window update logic in
[scream_v2.cc](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc).
- **Feedback Hold Time Tracking:**
- The WebRTC implementation explicitly tracks `feedback_hold_time_` (the
average time feedback is delayed at the receiver before being sent) in
[scream_v2.cc:L311](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#311).
- This hold time is integrated into multiple RTT-based calculations (initial
window, window increase scaling, and target rate calculation) to prevent
underestimating the true round-trip loop time.
### 4.2. Network Congestion Control
#### 4.2.1. Congestion Detection: Delay, Data Unit Loss and ECN-CE
##### 4.2.1.1. Detecting Lost Data Units
- **Different Loss Detection Mechanism:**
- The spec describes a RACK-like loss detection mechanism based on a
reordering window and a "lost" flag in the list of transmitted data units
([Section 4.2.1.1](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.1.1)).
- The WebRTC implementation uses a custom
[LossEstimator](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/loss_estimator.h)
([loss_estimator.cc](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/loss_estimator.cc))
which implements a **biased asymmetric step filter** (leaky bucket) to
estimate a short-term `congestion_level_` (between 0.0 and 1.0).
- **Filter Mechanics:** If one or more packets are lost during an RTT, the
filter steps up the congestion level by
`1.0 / rtts_with_loss_before_backoff` (default +1/3). If an RTT is
lossless, it steps down by `1.0 / lossless_rtts_before_clear` (default
-1/2).
- **Spurious Loss Filtering:** This asymmetric design ensures that spurious
random losses (e.g., 1% uniform loss on wireless links, which results in
~40% of RTTs having at least one loss) result in a net-negative drift,
keeping the congestion level near 0.0 and preventing unnecessary backoffs.
It requires 3 consecutive RTTs with loss to reach the 1.0 threshold.
- **Impact on Backoff:** Instead of reacting to individual loss events
immediately, the WebRTC implementation only triggers a loss-based backoff
when the `LossEstimator` reports that the connection is `congested()`
(congestion level >= 0.99) OR if queue delay is also detected. See
[scream_v2.cc:L134-L139](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#134).
- **Impact on Window Increase:** When the congestion level is elevated ($\\ge
0.01$), the reference window increase is **blocked**, even if the current
feedback report contains zero packet loss. Because the congestion level
decays by 0.5 per lossless RTT, it takes **2 full lossless RTTs** for the
increase blocker to clear after congestion ends. This prevents the window
from immediately expanding again after a congestion event. See
[scream_v2.cc:L199](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#199)
and
[loss_estimator.cc:L77](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/loss_estimator.cc#77).
##### 4.2.1.2. Receiving ECN-CE with classic ECN
- **Classic ECN Not Supported:**
- The spec defines a classic ECN mode where the reference window is scaled by
a fixed `BETA_ECN` (default 0.8)
([Section 4.2.1.2](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.1.2)).
- The WebRTC implementation **does not support classic ECN**. It only
implements L4S-style ECN marking reaction. There is no `BETA_ECN` parameter
or classic ECN backoff path in
[scream_v2.cc](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc).
##### 4.2.1.3. Receiving ECN-CE for L4S
- **L4S Alpha Update Frequency:**
- The spec recommends accumulating delivered and marked packets and updating
`l4s_alpha` at most once per `min(10ms, s_rtt)`
([Section 4.2.1.3](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.1.3)).
- The WebRTC implementation updates `l4s_alpha_` on **every feedback message**
based on the fraction of marked packets in that specific feedback, without
the time interval constraint. See
[scream_v2.cc:L109-L125](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#109).
##### 4.2.1.4. Detecting Increased Queue Delay
- **Jitter Reduction and Delay Variation Scaling:**
- The spec describes an optional jitter reduction mechanism based on a
normalized queue delay deviation `qdelay_dev_norm`
([Section 4.2.1.4](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.1.4)).
- The WebRTC implementation replaces `qdelay_dev_norm` with two alternative
scaling factors calculated in
[DelayBasedCongestionControl](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/delay_based_congestion_control.h)
([delay_based_congestion_control.cc](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/delay_based_congestion_control.cc)):
1. `ref_window_scale_factor_due_to_avg_min_delay` (based on
`queue_delay_min_avg_`): Scales growth based on the average minimum queue
delay. See
[delay_based_congestion_control.cc:L122](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/delay_based_congestion_control.cc#122).
2. `ref_window_scale_factor_due_to_latency_difference` (based on
`latency_difference_avg_`): Scales growth based on the difference between
max and min latency in feedback. See
[delay_based_congestion_control.cc:L131](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/delay_based_congestion_control.cc#131).
- These factors are used in
[scream_v2.cc](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc)
to scale backoff and window increase, replacing the `qdelay_dev_norm` terms
in the spec.
- **Queue Delay Average Update Frequency:**
- The spec updates `qdelay_avg` at most once per `min(virtual_rtt, s_rtt)`.
- The WebRTC implementation updates `queue_delay_avg_` on every feedback in
[delay_based_congestion_control.cc:L61-L72](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/delay_based_congestion_control.cc#61).
###### 4.2.1.4.1. Competing Flows Compensation
- **Not Implemented:**
- The spec describes a dynamic target delay adjustment
(`adjust_qdelay_target`) to allow SCReAM v2 to compete with aggressive
loss-based flows (like TCP Reno/Cubic) by increasing `qdelay_target` when
competing traffic is detected
([Section 4.2.1.4.1](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.1.4.1)).
- The WebRTC implementation **does not implement this feature**. The
`queue_delay_target` remains static (default 60ms). This is explicitly
marked as a TODO in
[scream_v2_parameters.h:L107](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2_parameters.h#107).
#### 4.2.2. Reference Window Update
##### 4.2.2.1. Reference Window Reduction
- **Inflection Point Scaling Factor:**
- The spec uses a factor of **8** in the calculation of `scl_t` (scaling
factor close to inflection point `ref_wnd_i`)
([Section 4.2.2.1](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.2.1)).
- The WebRTC implementation defaults to a lower factor of **2.0**
(`backoff_scale_factor_close_to_ref_window_i` in
[scream_v2_parameters.cc:L38](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2_parameters.cc#38)),
meaning the increase/decrease around the inflection point is slower (more
cautious) than in the spec.
- **Backoff Scaling Condition:**
- The spec scales down L4S backoff if `qdelay < qdelay_target * 0.25`
([Section 4.2.2.1](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.2.1)).
- The WebRTC implementation scales it down if
`!delay_based_congestion_control_.IsQueueDelayDetected()`, which translates
to `queue_delay_avg_ <= queue_delay_target / 2` (default 30ms)
([scream_v2.cc:L158](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#158)).
- **L4S Alpha Bump:**
- When resetting the reference window after a long period of inactivity (> 100
RTTs), the WebRTC implementation also bumps `l4s_alpha_` to **0.25** to
ensure a rapid reaction if congestion re-occurs
([scream_v2.cc:L187](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#187)).
This is not explicitly specified in the spec.
- **Inflection Point (`ref_window_i`) Update Logic:**
- **Spec:** `ref_wnd_i` is updated to `ref_wnd` immediately when *any*
congestion event is detected, protected by a simple time-based guard: it
cannot be updated more than once every **10 RTTs**
([Section 4.2.2.1](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.2.1)).
- **WebRTC:** Implements a state-based guard using
`allow_ref_window_i_update_`. It only updates `ref_window_i_` when a **net
decrease** in `ref_window_` occurs, and then blocks further updates
(`allow_ref_window_i_update_ = false`) until a **net increase** in
`ref_window_` has been observed. This ensures `ref_window_i_` captures the
true peak before a congestion episode and is not dragged down by consecutive
back-to-back reductions. See
[scream_v2.cc:L259-L271](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#259).
##### 4.2.2.2. Reference Window Increase
- **RTT Scaling for Small RTTs:**
- The spec scales down the window increase linearly using
`s_rtt / VIRTUAL_RTT`
([Section 4.2.2.2](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.2.2)).
- The WebRTC implementation scales it down using the **square of the RTT
ratio** (`rtt_ratio * rtt_ratio`) and also includes `feedback_hold_time_` in
the RTT calculation: `(rtt + feedback_hold) / virtual_rtt`. This results in
a more aggressive reduction of the increase rate for very small RTTs. See
[scream_v2.cc:L209-L215](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#209).
- **Application Limited State (ALR) Tracking:**
- **Spec:** The spec discusses limiting the reference window growth when the
amount of data in flight is small to avoid window inflation ("Increase
ref_wnd only if bytes in flight is large enough") and recommends stopping
the increase if `target_bitrate` reaches `TARGET_BITRATE_MAX`
([Section 4.2.2.2](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.2.2.2)).
- **WebRTC:** Implements a formal, explicit **Application Limited State
(ALR)** tracking mechanism (enabled by default via `EnableAlr` field trial).
The sender enters ALR when the maximum data in flight during the last RTTs
is insufficient to fill the reference window
(`max_allowed_ref_window() < ref_window_`). See
[scream_v2.cc:L68-L70](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#68).
- **ALR Effects in WebRTC:** Entering ALR has three major impacts to ensure
stability during sparse traffic periods:
1. **Halts Window Growth:** The reference window `ref_window_` is strictly
prevented from increasing. See
[scream_v2.cc:L253](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#253).
2. **Slows RTT Smoothing:** The EWMA gain used for smoothing the RTT is
drastically reduced from `1/8` to `1/128` (`smoothed_rtt_avg_in_alr_g`).
This prevents RTT estimates from being corrupted by sparse, potentially
delayed feedback samples when traffic is low. See
[delay_based_congestion_control.cc:L101](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/delay_based_congestion_control.cc#101).
3. **Freezes Feedback Hold Time Updates:** The running average of the
receiver's feedback hold time is not updated during ALR, preventing stale
or atypical delay samples from affecting the average. See
[scream_v2.cc:L74](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#74).
### 4.3. Sender Transmission Control
#### 4.3.1. Send Window Calculation
- The WebRTC implementation calculates the maximum allowed data in flight (send
window) in `ScreamV2::max_data_in_flight()`
([scream_v2.cc:L286-L297](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#286))
using the same formula as the spec: `ref_window * ref_wnd_overhead`
([Section 4.3.1](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.3.1)).
- However, it uses `ref_window_scale_factor_due_to_avg_min_delay(true)` instead
of `qdelay_dev_norm` to dynamically adjust `ref_wnd_overhead` between
`REF_WND_OVERHEAD_MIN` (1.5) and `REF_WND_OVERHEAD_MAX` (3.0).
#### 4.3.2. Packet Pacing
- **No Relaxed Pacing Logic:**
- The spec describes a complex "relaxed pacing" mechanism that increases the
pacing rate (effectively allowing larger bursts) when the target bitrate is
close to the maximum, to reduce application-layer latency
([Section 4.3.2](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.3.2)).
- The WebRTC implementation **does not implement relaxed pacing** in the
SCReAM module. Instead, it calculates a simple `pacing_rate` as
`target_rate_ * pacing_factor` (default factor 1.1) in
[scream_v2.h:L50](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.h#50)
and delegates the actual pacing to the standard WebRTC pacer via
[ScreamNetworkController::MaybeCreatePacerConfig](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_network_controller.cc#224).
- **Bandwidth Probing and Periodic Padding (WebRTC Addition):**
- **Spec:** The spec does not define any mechanism for bandwidth probing or
background padding.
- **WebRTC:** Adds a comprehensive probing and periodic padding mechanism to
quickly discover and maintain link capacity estimates, especially during
inactivity or at call start. This is implemented in
[scream_network_controller.cc:L224](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_network_controller.cc#224)
and controlled by WebRTC-specific parameters (e.g.,
`initial_probing_duration`, `time_between_periodic_padding`,
`periodic_padding_duration`, `allow_padding_after_last_congestion_time`)
defined in
[scream_v2_parameters.h](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2_parameters.h).
### 4.4. Media Rate Control
- **Simplified Target Rate Calculation (Missing Compensations):**
- The spec describes a complex media rate control that adjusts the target rate
using `rate_adjust_factor` (to compensate for media queue buildup) and
`frame_size_dev` (to compensate for varying frame sizes)
([Section 4.4](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.4)).
- The WebRTC implementation **does not implement these compensations**. This
is marked as a TODO in
[scream_v2.cc:L359](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#359).
- Instead, it uses a simplified formula:
`target_rate = scale_target_rate * (ref_window_ / (smoothed_rtt + feedback_hold_time_))`
(where `scale_target_rate` scales down the rate slightly if the window is
very small). See
[scream_v2.cc:L321-L335](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#321).
- **Queue Draining Logic:**
- The WebRTC implementation adds a custom "drain queue" logic. If the minimum
queue delay remains above a threshold (`queue_delay_drain_threshold`,
default 5ms) for a prolonged period (`queue_delay_drain_period`, default
20s), it temporarily halves the target rate for a few RTTs to attempt to
drain the queue. If this fails, it resets the queue delay estimate. See
[scream_v2.cc:L336-L357](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/scream_v2.cc#336).
This is not explicitly part of Section 4.4 in the spec, but serves as a
robust guard against persistent queue build-up.
### 4.5. Clock drift issues and remedies
- **Implementation Details:**
- The spec describes a clock drift remedy that tracks `qdelay_min` over an
RTT, averages it, and triggers a reset and 50% rate reduction if
`qdelay_min_avg > qdelay_target / 4`
([Section 4.5](https://www.ietf.org/archive/id/draft-johansson-ccwg-rfc8298bis-screamv2-07.html#section-4.5)).
- The WebRTC implementation uses a sliding window minimum filter
(`base_delay_history_` with window length 10) in
[DelayBasedCongestionControl](https://webrtc.googlesource.com/src/+/master/modules/congestion_controller/scream/delay_based_congestion_control.h)
to track the base delay and compensate for clock drift. The history is
updated every 1 minute (`base_delay_history_update_interval`).
- The "drain queue" logic in `UpdateTargetRate` (described in Section 4.4
above) acts as the practical trigger for resetting the queue delay estimate
if clock drift (or other non-congestion factors) causes the one-way delay to
increase permanently.