# 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.