RFC 8698

Network-Assisted Dynamic Adaptation (NADA): A Unified Congestion Control Scheme for Real-Time Media

๐Ÿ“… published February 2020, from ietf

RFC 8698 ๐Ÿฆ‹ Network-Assisted Dynamic Adaptation (NADA): A Unified Congestion Control Scheme for Real-Time Media

okay bestie, so this one is NADA ๐Ÿ’–, an experimental congestion control scheme for real-time media like video calls. It came out in February 2020, it's in the Experimental category (so it's a not-a-Standards-Track thing, ISSN 2070-1721), and it was written by X. Zhu (Cisco Systems), R. Pan (Intel Corporation), M. Ramalho (AcousticComms), and S. Mena (Cisco Systems). It doesn't list anything it obsoletes or updates, so it's standing on its own ๐ŸŒธ

Abstract โœจ

okay so this document describes NADA, a totally new congestion control scheme for interactive real-time media apps like video conferencing ๐Ÿ“น The sender controls its sending rate based on either implicit or explicit congestion signals, all in one unified approach ๐Ÿซถ It can benefit from Explicit Congestion Notification (ECN) markings from network nodes, but if those aren't there, it still acts consistently by reacting to queuing delays and packet losses instead. iconic, honestly ๐Ÿ’…

Status of This Memo ๐ŸŽ€

this document is not an Internet Standards Track specification. it's published for examination, experimental implementation, and evaluation ๐Ÿงช

it defines an Experimental Protocol for the Internet community. it's a product of the Internet Engineering Task Force (IETF), it represents the consensus of the IETF community, and it got public review and was approved for publication by the Internet Engineering Steering Group (IESG). not every IESG-approved doc is a candidate for any level of Internet Standard, so check Section 2 of RFC 7841 if you're curious ๐Ÿค“

for the current status, any errata, and how to give feedback, go to https://www.rfc-editor.org/info/rfc8698 ๐Ÿ”—

Copyright (c) 2020 IETF Trust and the persons identified as the document authors. All rights reserved.

this document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as in effect on the date of publication. please read these carefully, bestie, because they explain your rights and restrictions for this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they're provided without warranty as described in the Simplified BSD License.

Table of Contents ๐Ÿ“

1.  Introduction
2.  Terminology
3.  System Overview
4.  Core Congestion Control Algorithm
  4.1.  Mathematical Notations
  4.2.  Receiver-Side Algorithm
  4.3.  Sender-Side Algorithm
5.  Practical Implementation of NADA
  5.1.  Receiver-Side Operation
    5.1.1.  Estimation of One-Way Delay and Queuing Delay
    5.1.2.  Estimation of Packet Loss/Marking Ratio
    5.1.3.  Estimation of Receiving Rate
  5.2.  Sender-Side Operation
    5.2.1.  Rate-Shaping Buffer
    5.2.2.  Adjusting Video Target Rate and Sending Rate
  5.3.  Feedback Message Requirements
6.  Discussions and Further Investigations
  6.1.  Choice of Delay Metrics
  6.2.  Method for Delay, Loss, and Marking Ratio Estimation
  6.3.  Impact of Parameter Values
  6.4.  Sender-Based vs. Receiver-Based Calculation
  6.5.  Incremental Deployment
7.  Reference Implementations
8.  Suggested Experiments
9.  IANA Considerations
10. Security Considerations
11. References
  11.1.  Normative References
  11.2.  Informative References
Appendix A.  Network Node Operations
  A.1.  Default Behavior of Drop-Tail Queues
  A.2.  RED-Based ECN Marking
  A.3.  Random Early Marking with Virtual Queues
Acknowledgments
Contributors
Authors' Addresses

1. Introduction โœจ

okay so real-time media apps have a unique set of problems for congestion control ๐Ÿ˜ญ Unlike TCP, the mechanism for real-time media has to adapt quickly to bandwidth changes that happen in an instant, handle the wobbly output of video encoder rate control, and keep queuing delay over the network low ๐Ÿƒโ€โ™€๏ธ An ideal scheme should also use every kind of congestion signal well: packet loss, queuing delay, and explicit congestion notification (ECN) [RFC3168] markings. The requirements for the congestion control algorithm are outlined in [RMCAT-CC]. Those requirements say the desired scheme should 1) avoid flow starvation and get a reasonable fair share of bandwidth when competing against other flows, 2) adapt quickly, and 3) operate in a stable manner ๐Ÿ’œ

this document describes an experimental congestion control scheme called Network-Assisted Dynamic Adaptation (NADA). NADA gets a boost from explicit congestion control signals (like ECN markings) from the network, but it also works when only implicit congestion indicators (delay and/or loss) are available ๐Ÿซถ That unified sender behavior is what sets NADA apart from other congestion control schemes for real-time media, and it's kind of the main character move here โœจ On top of that, its core algorithm is designed to stay stable for path round-trip times (RTTs) below a set bound (e.g., 250 ms with default parameter choices) ๐ŸŽฏ It also supports weighted bandwidth sharing among competing video flows with different priorities ๐Ÿ‘‘

the signaling mechanism is made of the standard Real-time Transport Protocol (RTP) timestamp [RFC3550] and Real-time Transport Control Protocol (RTCP) feedback reports ๐Ÿ“ฎ The desired RTCP feedback message is described in detail in [RTCP-FEEDBACK], so that several congestion control schemes for real-time interactive media can operate successfully ๐Ÿฆ‹

2. Terminology ๐ŸŒธ

okay this part is the key word rules, so pay attention ๐Ÿ™ˆ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. Lowercase versions don't count, bestie ๐Ÿ’…

3. System Overview ๐ŸŽ€

here's the end-to-end system for real-time media transport that NADA works in ๐Ÿงš Note that there are also network nodes along the reverse (potentially uncongested) path that the RTCP feedback reports travel through. Those aren't drawn in the figure, for brevity ๐Ÿ™ˆ

  +---------+  r_vin  +--------+        +--------+     +----------+
  |  Media  |<--------|  RTP   |        |Network |     |   RTP    |
  | Encoder |========>| Sender |=======>|  Node  |====>| Receiver |
  +---------+  r_vout +--------+ r_send +--------+     +----------+
                             /|\                                |
                              |                                 |
                              +---------------------------------+
                                    RTCP Feedback Report

Figure 1: System Overview ๐Ÿ“ธ

  • Media encoder with rate control capabilities: this bit encodes raw media (audio and video) frames into a compressed bitstream, which later gets packetized into RTP packets ๐ŸŽฌ As discussed in [RFC8593], the actual output rate from the encoder r_vout can wobble around the target r_vin. It's also possible that the encoder can only react to bit rate changes at pretty coarse time intervals, e.g., once every 0.5 seconds ๐Ÿ™ƒ
  • RTP sender: this one is responsible for calculating the NADA reference rate based on network congestion indicators (delay, loss, or ECN marking reports from the receiver) ๐Ÿงฎ It also updates the video encoder with a new target rate r_vin and regulates the actual sending rate r_send to match. The RTP sender also generates a sending timestamp for each outgoing packet โฑ๏ธ
  • RTP receiver: this is the measuring queen ๐Ÿ‘‘ It measures and estimates end-to-end delay (based on the sender timestamp), packet loss (based on the RTP sequence number), ECN marking ratios (based on [RFC6679]), and the receiving rate (r_recv) of the flow. It calculates the aggregated congestion signal (x_curr) that accounts for queuing delay, ECN markings, and packet losses. The receiver also figures out the mode for sender rate adaptation (rmode) based on whether the flow has hit any standing non-zero congestion. Then it sends periodic RTCP reports back to the sender, containing values of x_curr, rmode, and r_recv ๐Ÿ“ฌ
  • Network node with several modes of operation: the system can work with the default behavior of a simple drop-tail queue ๐Ÿชฃ It can also get extra benefits from advanced Active Queue Management (AQM) features such as Proportional Integral Controller Enhanced (PIE) [RFC8033], Flow Queue Controlling Queue Delay (FQ-CoDel) [RFC8290], ECN marking based on Random Early Detection (RED) [RFC7567], and Pre-Congestion Notification (PCN) marking using a token bucket algorithm [RFC6660]. Note that network node operation is out of scope for the design of NADA ๐Ÿ™…โ€โ™€๏ธ

4. Core Congestion Control Algorithm ๐Ÿ’…

so like TCP-Friendly Rate Control (TFRC) [FLOYD-CCR00] [RFC5348], NADA is a rate-based congestion control algorithm ๐Ÿซง In its simplest form, the sender reacts to the collection of network congestion indicators, which get combined into one aggregated congestion signal, and it operates in one of two modes:

  • Accelerated ramp up: when the bottleneck is deemed underutilized, the rate increases multiplicatively with respect to the rate of previously successful transmissions ๐Ÿš€ The rate increase multiplier (gamma) is calculated from the observed round-trip time and the target feedback interval, so that self-inflicted queuing delay stays limited ๐Ÿง 
  • Gradual rate update: when there's a non-zero aggregate congestion signal, the sending rate gets adjusted in reaction to both its value (x_curr) and its change in value (x_diff) ๐ŸŒŠ

this section introduces the list of mathematical notations and describes the core congestion control algorithm at the sender and receiver, respectively. More details on recommended practical implementations are in Sections 5.1 and 5.2, so keep reading, bestie ๐Ÿ“–โœจ

4.1. Mathematical Notations

okay so bestie, this section is basically the cheat sheet for every variable and parameter NADA uses ๐Ÿ“โœจ Table 1 lists the variables, and Table 2 lists the algorithm parameters with their default values ๐Ÿ’… The defaults are either a typical setting for real-world apps or a setting backed by theory and simulation studies ๐ŸŽ€ If you want the vibe on how the parameter values affect things, check out Section 6.3 ๐Ÿ”ฅ And if you're craving real-world data on picking and adapting these values, Section 8 has the suggested studies ๐Ÿซถ

+------------+------------------------------------------------+
| Notation   | Variable Name                                  |
+============+================================================+
| t_curr     | Current timestamp                              |
+------------+------------------------------------------------+
| t_last     | Last time sending/receiving a feedback message |
+------------+------------------------------------------------+
| delta      | Observed interval between current and previous |
|            | feedback reports: delta = t_curr-t_last        |
+------------+------------------------------------------------+
| r_ref      | Reference rate based on network congestion     |
+------------+------------------------------------------------+
| r_send     | Sending rate                                   |
+------------+------------------------------------------------+
| r_recv     | Receiving rate                                 |
+------------+------------------------------------------------+
| r_vin      | Target rate for video encoder                  |
+------------+------------------------------------------------+
| r_vout     | Output rate from video encoder                 |
+------------+------------------------------------------------+
| d_base     | Estimated baseline delay                       |
+------------+------------------------------------------------+
| d_fwd      | Measured and filtered one-way delay            |
+------------+------------------------------------------------+
| d_queue    | Estimated queuing delay                        |
+------------+------------------------------------------------+
| d_tilde    | Equivalent delay after non-linear warping      |
+------------+------------------------------------------------+
| p_mark     | Estimated packet ECN marking ratio             |
+------------+------------------------------------------------+
| p_loss     | Estimated packet loss ratio                    |
+------------+------------------------------------------------+
| x_curr     | Aggregate congestion signal                    |
+------------+------------------------------------------------+
| x_prev     | Previous value of aggregate congestion signal  |
+------------+------------------------------------------------+
| x_diff     | Change in aggregate congestion signal w.r.t.   |
|            | its previous value: x_diff = x_curr - x_prev   |
+------------+------------------------------------------------+
| rmode      | Rate update mode: (0 = accelerated ramp up; 1  |
|            | = gradual update)                              |
+------------+------------------------------------------------+
| gamma      | Rate increase multiplier in accelerated ramp-  |
|            | up mode                                        |
+------------+------------------------------------------------+
| loss_int   | Measured average loss interval in packet count |
+------------+------------------------------------------------+
| loss_exp   | Threshold value for setting the last observed  |
|            | packet loss to expiration                      |
+------------+------------------------------------------------+
| rtt        | Estimated round-trip time at sender            |
+------------+------------------------------------------------+
| buffer_len | Rate-shaping buffer occupancy measured in      |
|            | bytes                                          |
+------------+------------------------------------------------+

                      Table 1: List of Variables
+-----------+-------------------------------------------+---------+
| Notation  | Parameter Name                            | Default |
|           |                                           | Value   |
+===========+===========================================+=========+
| PRIO      | Weight of priority of the flow            | 1.0     |
+-----------+-------------------------------------------+---------+
| RMIN      | Minimum rate of application supported by  | 150     |
|           | media encoder                             | Kbps    |
+-----------+-------------------------------------------+---------+
| RMAX      | Maximum rate of application supported by  | 1.5     |
|           | media encoder                             | Mbps    |
+-----------+-------------------------------------------+---------+
| XREF      | Reference congestion level                | 10 ms   |
+-----------+-------------------------------------------+---------+
| KAPPA     | Scaling parameter for gradual rate update | 0.5     |
|           | calculation                               |         |
+-----------+-------------------------------------------+---------+
| ETA       | Scaling parameter for gradual rate update | 2.0     |
|           | calculation                               |         |
+-----------+-------------------------------------------+---------+
| TAU       | Upper bound of RTT in gradual rate update | 500 ms  |
|           | calculation                               |         |
+-----------+-------------------------------------------+---------+
| DELTA     | Target feedback interval                  | 100 ms  |
+-----------+-------------------------------------------+---------+
| LOGWIN    | Observation window in time for            | 500 ms  |
|           | calculating packet summary statistics at  |         |
|           | receiver                                  |         |
+-----------+-------------------------------------------+---------+
| QEPS      | Threshold for determining queuing delay   | 10 ms   |
|           | buildup at receiver                       |         |
+-----------+-------------------------------------------+---------+
| DFILT     | Bound on filtering delay                  | 120 ms  |
+-----------+-------------------------------------------+---------+
| GAMMA_MAX | Upper bound on rate increase ratio for    | 0.5     |
|           | accelerated ramp up                       |         |
+-----------+-------------------------------------------+---------+
| QBOUND    | Upper bound on self-inflicted queuing     | 50 ms   |
|           | delay during ramp up                      |         |
+-----------+-------------------------------------------+---------+
| MULTILOSS | Multiplier for self-scaling the           | 7.0     |
|           | expiration threshold of the last observed |         |
|           | loss (loss_exp) based on measured average |         |
|           | loss interval (loss_int)                  |         |
+-----------+-------------------------------------------+---------+
| QTH       | Delay threshold for invoking non-linear   | 50 ms   |
|           | warping                                   |         |
+-----------+-------------------------------------------+---------+
| LAMBDA    | Scaling parameter in the exponent of non- | 0.5     |
|           | linear warping                            |         |
+-----------+-------------------------------------------+---------+
| PLRREF    | Reference packet loss ratio               | 0.01    |
+-----------+-------------------------------------------+---------+
| PMRREF    | Reference packet marking ratio            | 0.01    |
+-----------+-------------------------------------------+---------+
| DLOSS     | Reference delay penalty for loss when     | 10 ms   |
|           | packet loss ratio is at PLRREF            |         |
+-----------+-------------------------------------------+---------+
| DMARK     | Reference delay penalty for ECN marking   | 2 ms    |
|           | when packet marking is at PMRREF          |         |
+-----------+-------------------------------------------+---------+
| FPS       | Frame rate of incoming video              | 30      |
+-----------+-------------------------------------------+---------+
| BETA_S    | Scaling parameter for modulating outgoing | 0.1     |
|           | sending rate                              |         |
+-----------+-------------------------------------------+---------+
| BETA_V    | Scaling parameter for modulating video    | 0.1     |
|           | encoder target rate                       |         |
+-----------+-------------------------------------------+---------+
| ALPHA     | Smoothing factor in exponential smoothing | 0.1     |
|           | of packet loss and marking ratios         |         |
+-----------+-------------------------------------------+---------+

      Table 2: List of Algorithm Parameters and Their Default Values

4.2. Receiver-Side Algorithm ๐ŸŽ€

Okay bestie, the receiver side is where the magic happens ๐Ÿฆ‹ Here's the whole loop:

      On initialization:

         set d_base = +INFINITY

         set p_loss = 0

         set p_mark = 0

         set r_recv = 0

         set both t_last and t_curr as current time in milliseconds

      On receiving a media packet:

         obtain current timestamp t_curr from system clock

         obtain from packet header sending time stamp t_sent

         obtain one-way delay measurement: d_fwd = t_curr - t_sent

         update baseline delay: d_base = min(d_base, d_fwd)

         update queuing delay: d_queue = d_fwd - d_base

         update packet loss ratio estimate p_loss

         update packet marking ratio estimate p_mark

         update measurement of receiving rate r_recv

      On time to send a new feedback report (t_curr - t_last > DELTA):

         calculate non-linear warping of delay d_tilde if packet loss
         exists

         calculate current aggregate congestion signal x_curr

         determine mode of rate adaptation for sender: rmode

         send feedback containing values of: rmode, x_curr, and r_recv

         update t_last = t_curr

So a delay-based flow wants to hold its ground when it's competing with loss-based flows (like loss-based TCP) ๐Ÿ’… That means you have to tell different levels of queuing delay apart. Over wired connections, a moderate queuing delay (tens of milliseconds) is probably self-inflicted or caused by other delay-based flows ๐Ÿ™ˆ But a high queuing delay (several hundreds of milliseconds) can mean a loss-based flow is around that just keeps pushing the delay up, no cap ๐Ÿ˜ญ

If the last observed packet loss is still inside the expiration window of loss_exp (counted in packets), the estimated queuing delay gets a non-linear warp โœจ

              / d_queue,                   if d_queue < QTH
              |
   d_tilde = <                                           (1)
              |                  (d_queue-QTH)
              \ QTH exp(-LAMBDA ---------------) , otherwise
                                    QTH

In Equation (1), the queuing delay stays exactly the same when it's below the first threshold QTH. Otherwise, it gets scaled down along a non-linear curve ๐ŸŒˆ This warping is inspired by the delay-adaptive congestion window backoff policy in [BUDZISZ-AIMD-CC], so the controller can "gradually nudge" itself to work from loss-induced congestion signals when it's competing with loss-based flows. The exact form of the non-linear function is simpler than the one in [BUDZISZ-AIMD-CC]. The threshold QTH needs careful tuning for each environment so you don't discount the congestion signal too early ๐Ÿซถ Usually a higher QTH is needed in a noisier environment (like wireless, or when the video stream is dealing with lots of time-varying background traffic), so it stays robust against non-congestion delay spikes. More tips on tuning or auto-tuning QTH should come from experimental studies in real-world deployments ๐Ÿ”ฅ

The value of loss_exp self-scales with the average packet loss interval loss_int, using a multiplier MULTILOSS:

    loss_exp = MULTILOSS *
   loss_int.

And the average loss interval loss_int gets estimated the way Section 5.4 of "TCP Friendly Rate Control (TFRC): Protocol Specification" [RFC5348] describes ๐Ÿ“š

In practice, it's recommended to linearly interpolate between the warped (d_tilde) and non-warped (d_queue) values of queuing delay during the transition period, which lasts for the duration of loss_int ๐Ÿ“

Now the aggregate congestion signal ๐Ÿ‘‘

                            / p_mark \^2        / p_loss \^2
   x_curr = d_tilde + DMARK*|--------|  + DLOSS*|--------|   (2)
                            \ PMRREF /          \ PLRREF /

Here, DMARK is a reference delay penalty for ECN markings at the reference marking ratio PMRREF, and DLOSS is a reference delay penalty for packet losses at the reference packet loss ratio PLRREF ๐Ÿ’– Neither DLOSS nor DMARK depends on the configuration of the network node. ECN-enabled active queue management usually marks a packet before dropping it, so the value of DLOSS SHOULD be higher than that of DMARK โœจ Also, DLOSS and DMARK need to be set consistently across every NADA flow sharing the same bottleneck link, so they can compete fairly ๐Ÿซถ

Without any packet marking or losses, x_curr just collapses to the observed queuing delay d_queue. In that case NADA is running in the delay-based adaptation regime ๐Ÿงš

The receiver is also in a great spot to figure out whether the network is underutilized, and then recommend the matching rate adaptation mode to the sender ๐Ÿ’… Accelerated ramp-up mode is used when both of these are true:

  • No recent packet losses within the observation window LOGWIN; and
  • No buildup of queuing delay: d_fwd-d_base < QEPS for all previous delay samples within the observation window LOGWIN.

Otherwise, the algorithm operates in graduate update mode ๐ŸŒธ


4.3. Sender-Side Algorithm ๐Ÿฆ‹

Now let's look at the sender side, the part that actually adjusts the rate:

      On initialization:

         set r_ref = RMIN

         set rtt = 0

         set x_prev = 0

         set t_last and t_curr as current system clock time

      On receiving feedback report:

         obtain current timestamp from system clock: t_curr

         obtain values of rmode, x_curr, and r_recv from feedback report

         update estimation of rtt

         measure feedback interval: delta = t_curr - t_last

         if rmode == 0:

            update r_ref following accelerated ramp-up rules

         else:

            update r_ref following gradual update rules

         clip rate r_ref within the range of minimum rate (RMIN) and
         maximum rate (RMAX).

         set x_prev = x_curr

         set t_last = t_curr

In accelerated ramp-up mode, r_ref gets updated like this ๐Ÿš€

                                   QBOUND
       gamma = min(GAMMA_MAX, ------------------)       (3)
                               rtt+DELTA+DFILT

                               r_ref = max(r_ref, (1+gamma) r_recv)
                               (4)

The rate increase multiplier gamma is calculated from the upper bound of self-inflicted queuing delay (QBOUND), the round-trip time (rtt), and the target feedback interval (DELTA). It's also bounded by the filtering delay used to calculate d_queue (DFILT), and it has a maximum value of GAMMA_MAX โœจ The logic behind Equations (3)-(4) is this: the longer the sender takes to notice self-inflicted queuing delay building up, the more conservative it should be about increasing its rate, which means a smaller rate increase multiplier ๐Ÿ™ˆ

In gradual update mode, r_ref is updated as follows ๐Ÿ’…

       x_offset = x_curr - PRIO*XREF*RMAX/r_ref          (5)

       x_diff   = x_curr - x_prev                        (6)

                              delta    x_offset
       r_ref = r_ref - KAPPA*-------*------------*r_ref
                               TAU       TAU

                                   x_diff
                     - KAPPA*ETA*---------*r_ref         (7)
                                    TAU

The rate changes in proportion to the previous rate decision ๐ŸŒˆ Two terms affect it: how far the aggregate congestion signal is from its equilibrium value (x_offset), and how much it changed (x_diff). x_offset depends on the flow's maximum rate (RMAX), its priority weight (PRIO), and a reference congestion signal (XREF). XREF is picked so that the maximum rate RMAX can be reached whenever the observed congestion signal stays below PRIO*XREF ๐Ÿ‘‘

At equilibrium, the aggregated congestion signal settles at x_curr = PRIO*XREF*RMAX/r_ref. This means that when several flows share the same bottleneck and see a common x_curr, their equilibrium rates end up proportional to their priority levels (PRIO) and to the range between the minimum and maximum rate ๐Ÿซถ The minimum rate (RMIN) and maximum rate (RMAX) come from the media codec, for example as outlined in [RMCAT-CC-RTP]. If that info isn't available, the NADA sender picks a default of 0 for RMIN and 3 Mbps for RMAX ๐Ÿ“

As mentioned in the sender-side algorithm, the final rate is always clipped to the dynamic range the application sets ๐Ÿ’–

       r_ref = min(r_ref, RMAX)                         (8)

       r_ref = max(r_ref, RMIN)                         (9)

Heads up, the operations above skip a lot of practical stuff, like clock synchronization between sender and receiver, filtering noise out of delay measurements, and base delay expiration ๐Ÿ˜ญ Those get covered in Section 5.


5. Practical Implementation of NADA ๐ŸŒธ

5.1. Receiver-Side Operation ๐ŸŽ€

The receiver keeps watching end-to-end, per-packet stats for delay, loss, and/or ECN marking ratios ๐Ÿ‘€ It then rolls every form of congestion indicator into one equivalent delay value and reports that back to the sender on a regular basis. On top of that, the receiver tracks the receiving rate of the flow and puts it in the feedback message โœจ

5.1.1. Estimation of One-Way Delay and Queuing Delay ๐Ÿฆ‹

NADA's delay estimation is pretty similar to earlier delay-based congestion control schemes, like Low Extra Delay Background Transport (LEDBAT) [RFC6817] ๐Ÿงš For experimental implementations, rather than relying on RTP timestamps and the transmission time offset RTP header extension [RFC5450], the NADA sender can make its own timestamp from the local system clock and embed it in the transport packet header ๐Ÿ’… The NADA receiver estimates the forward delay as a constant base delay component plus a time-varying queuing delay component. The base delay is estimated as the minimum one-way delay observed over a relatively long period (for example, tens of minutes), and the queuing delay for each sample is the difference between its one-way delay and the base delay ๐ŸŒˆ Re-estimating the base delay periodically helps avoid base delay expiration, which is when an older base delay stops being valid because of route changes or a cumulative timing difference from clock-rate skew between sender and receiver ๐Ÿ˜ญ All delay estimations are based on sender timestamps, with a recommended granularity of 100 microseconds or finer ๐Ÿ“

The individual queuing delay samples should be filtered further against non-congestion noise, like spikes from a processing "hiccup" at network nodes ๐Ÿ™ˆ So on top of calculating queuing delay with d_queue = d_fwd - d_base (as shown in Section 5.1), the current implementation also runs a minimum filter with a window size of 15 samples over the per-packet queuing delay values ๐Ÿ”ฅ

5.1.2. Estimation of Packet Loss/Marking Ratio ๐Ÿ’Œ

Okay so the receiver spots lost packets by checking for gaps in the RTP sequence numbers ๐Ÿ•ต๏ธโ€โ™€๏ธ For real-time stuff like video calls where latency is everything, the receiver skips the reordering delay entirely by treating out-of-order packets as losses. Lowkey genius ๐Ÿง  The instantaneous packet loss ratio p_inst is the number of missing packets divided by the total number of transmitted packets inside the recent observation window LOGWIN. Then p_loss is the smoothed version after exponential smoothing ๐ŸŒŠ

p_loss = ALPHA*p_inst + (1-ALPHA)*p_loss        (10)

The receiver sends this filtered value back to the sender as the observed packet loss ratio p_loss ๐Ÿ’–

The packet marking ratio p_mark gets estimated the exact same way โœจ ECN marking info from the IP header can be handed to the receiving endpoint, for example through the mechanism in [RFC6679] ๐Ÿฆ‹

5.1.3. Estimation of Receiving Rate ๐Ÿ“ˆ

Estimating the receiving rate r_recv is honestly so easy ๐Ÿฅน NADA keeps a recent observation window that spans LOGWIN, adds up the total size of the packets that arrived in that window, and divides by the time span. Done! The r_recv value can either be worked out on the sender side from per-packet feedback sent by the receiver, or it can ride along as part of the feedback report ๐ŸŽ€

5.2. Sender-Side Operation ๐Ÿš€

Figure 2 gives you the full picture of the NADA sender ๐Ÿ‘€ When an RTCP feedback report shows up from the receiver, the NADA sender works out the reference rate r_ref as described in Section 4.3. After that it adjusts two things: the target rate for the live video encoder r_vin, and the sending rate r_send over the network. Both get updated based on the new r_ref and the rate-shaping buffer occupancy buffer_len ๐Ÿ’…

The NADA sender acts the same way no matter which congestion indicator shows up: delay, loss, or ECN marking ๐Ÿ™Œ This unified approach is what lets the scheme transition smoothly as the network moves back and forth between light and heavy congestion levels. Iconic, honestly ๐Ÿ‘‘

                      +----------------+
                      |  Calculate     | <---- RTCP report
                      | Reference Rate |
                      -----------------+
                              | r_ref
                 +------------+-------------+
                 |                          |
                \|/                        \|/
         +-----------------+           +---------------+
         | Calculate Video |           |   Calculate   |
         |  Target Rate    |           | Sending Rate  |
         +-----------------+           +---------------+
             |        /|\                 /|\      |
       r_vin |         |                   |       |
            \|/        +-------------------+       |
         +----------+          | buffer_len        |  r_send
         |  Video   | r_vout  -----------+        \|/
         |  Encoder |-------->   |||||||||=================>
         +----------+         -----------+    RTP packets
         Rate-Shaping Buffer

                      Figure 2: NADA Sender Structure

5.2.1. Rate-Shaping Buffer ๐Ÿงƒ

The live video encoder is not part of the congestion control design here, so NADA treats how it behaves as a black box ๐Ÿ“ฆ

The rate-shaping buffer soaks up any sudden mismatch between the encoder rate output r_vout and the regulated sending rate r_send. Its current occupancy is measured in bytes and is called buffer_len ๐Ÿชฃ

A big rate-shaping buffer adds to the end-to-end delay, and that can seriously hurt real-time media ๐Ÿ˜ญ So the sender has a strong reason to keep the buffer from piling up. It does this in two ways:

  • To drain the rate-shaping buffer faster by raising the sending rate r_send; and
  • To limit the incoming packets going into the rate-shaping buffer by lowering the video encoder target rate r_vin.

5.2.2. Adjusting Video Target Rate and Sending Rate ๐ŸŽฏ

If the sender can see how full the rate-shaping buffer is, it can use that info to fine-tune both the live video encoder target rate r_vin and the actual sending rate r_send ๐Ÿ” The whole point is to cancel out the extra latency that the buffer adds. Here's how the amount of adjustment gets calculated:

    r_diff_v = min(0.05*r_ref, BETA_V*8*buffer_len*FPS)     (11)
    r_diff_s = min(0.05*r_ref, BETA_S*8*buffer_len*FPS)     (12)
    r_vin  = max(RMIN, r_ref - r_diff_v)                    (13)
    r_send = min(RMAX, r_ref + r_diff_s)                    (14)

In Equations (11) and (12), the adjustment grows with the size of the rate-shaping buffer but gets capped at 5% of the reference rate r_ref, which is calculated from network congestion feedback alone ๐Ÿ›ก๏ธ That cap makes sure the buffer adjustment never fights the core congestion control process, which is the vibe we want. Equations (13) and (14) show how the buffer actually pushes things around. A big buffer nudges the encoder target rate slightly below r_ref and the sending rate slightly above it ๐Ÿซถ The final r_vin and r_send also get clamped to the original range of [RMIN, RMAX].

Here's the intuition: the extra rate offset needed to fully drain the buffer within a single video frame is 8*buffer_len*FPS, where FPS is the reference frame rate of the video ๐ŸŽž๏ธ The scaling parameters BETA_V and BETA_S let you balance two competing goals: keeping the buffer small, and not wandering too far from the reference rate point โš–๏ธ Empirical observations show that for a responsive live video encoder, the rate-shaping buffer usually stays empty and only now and then holds a large frame in transit, like when an intra-frame is produced. So the adjustment from this mechanism should be pretty minor ๐ŸŒธ For example, a rate-shaping buffer of 2000 bytes leads to a rate adjustment of 48 Kbps, using the recommended scaling parameters BETA_V = 0.1 and BETA_S = 0.1 and a reference frame rate of FPS = 30 โœจ

5.3. Feedback Message Requirements ๐Ÿ“จ

The following info is required for NADA congestion control to work properly ๐Ÿ’œ

  • Recommended rate adaptation mode (rmode): A 1-bit flag that says whether the sender should run in accelerated ramp-up mode (rmode=0) or gradual update mode (rmode=1).
  • Aggregated congestion signal (x_curr): The most recently updated value, calculated by the receiver according to Section 4.2. This can be expressed in units of 100 microseconds (i.e., 1/10 of a millisecond) using 15 bits. That allows a maximum x_curr value of approximately 3.27 seconds โฑ๏ธ
  • Receiving rate (r_recv): The most recently measured receiving rate, found according to Section 5.1.3. This is expressed in bits per second (bps) using 32 bits (unsigned int). That allows a maximum rate of approximately 4.3 Gbps, which is roughly 1000 times the streaming rate of a typical high-definition (HD) video conferencing session today ๐Ÿคฏ This field can be stretched by a few more bytes if an even higher rate ever needs to be specified.

The info above fits in 48 bits, or 6 bytes, total ๐ŸŽ It can be included in the feedback report from the receiver or, if all the receiver-side calculations get moved over to the sender, it can be derived from per-packet information in the feedback message as defined in [RTCP-FEEDBACK]. Choosing the feedback message interval DELTA is covered in Section 6.3. A target feedback interval of DELTA = 100 ms is recommended ๐Ÿ•

6. Discussions and Further Investigations ๐Ÿง โœจ

This section talks through the different design choices NADA made, alternative variants of its implementation, and guidance on how to pick the key algorithm parameters ๐Ÿ’ญ Section 8 recommends extra experimental setups for digging deeper into all of this ๐Ÿ”ฌ

6.1. Choice of Delay Metrics โณ

The current design uses relative one-way delay (OWD) as the main sign of congestion ๐Ÿšฆ The relative OWD value comes from tracking the minimum observed OWD over a fairly long time horizon, then subtracting it from the observed absolute OWD value. This cancels out the fixed difference between the sender and receiver clocks ๐Ÿ•ฐ๏ธ Other delay-based congestion control approaches like [RFC6817] have adopted this too. As [RFC6817] explains, the time horizon for tracking the minimum OWD has to be chosen carefully. It must be long enough to catch the minimum OWD with zero standing queue along the path, and it must also be short enough to reflect real changes in the minimum OWD caused by route changes and other rare events, and to limit the buildup of cumulative impact from clock rate skew over time ๐Ÿ˜ค

The catch with relying on relative OWD as the congestion signal is this: when multiple flows share the same bottleneck, a flow that arrives late, while the network has a non-empty queue, might mistakenly think the standing queuing delay is part of the fixed path propagation delay. That leads to slightly unfair bandwidth sharing among the flows ๐Ÿฅฒ

Another option is to move the per-packet statistical handling to the sender and use relative round-trip time (RTT) instead of relative OWD, as long as per-packet acknowledgments are available. The main downside of an RTT-based approach is the noise in the measured delay on the reverse direction ๐Ÿ“‰

Here's the tea: picking either delay metric (relative OWD or RTT) doesn't change the proposed rate adaptation algorithm at all ๐Ÿต So comparing the pros and cons of each one can be kept as its own separate line of investigation ๐Ÿ”€

6.2. Method for Delay, Loss, and Marking Ratio Estimation ๐Ÿ”Ž

Like other delay-based congestion control schemes, NADA's performance depends on how accurate its delay measurement and estimation module is ๐ŸŽฏ Appendix A of [RFC6817] has a super thorough discussion of this ๐Ÿ“š

The current recommended practice of applying a minimum filter with a window size of 15 samples is enough to guard against processing delay outliers on wired connections ๐Ÿ”Œ For wireless connections with higher packet delay variation (PDV), you may need more sophisticated techniques for denoising, outlier rejection, and trend analysis ๐Ÿ“ก

More sophisticated methods for packet loss ratio calculation, like the one adopted by [FLOYD-CCR00], will likely be beneficial ๐Ÿ’ซ These alternatives are part of the experiments this document proposes ๐Ÿงช

okay bestie, part 5 of this glow-up ๐ŸŽ€

Wait, the section numbers jumped a bit: the text here is 6.3 onward, so I'll keep it exactly as written. Let's get into it ๐Ÿ’…

6.3. Impact of Parameter Values ๐ŸŽ€

6.3. Impact of Parameter Values

Okay so in gradual rate update mode, the parameter TAU is basically the upper bound on round-trip time (RTT) in the feedback control loop ๐Ÿ”. Usually the feedback interval you actually observe, delta, sits close to the target feedback interval DELTA, and the ratio of delta/TAU versus ETA decides how much the aggregate congestion signal offset term (x_offset) pushes versus how much its recent change (x_diff) pushes ๐Ÿ’–. These two are kinda like the integral and proportional terms in a proportional-integral (PI) controller, which is so iconic ๐Ÿ˜ญ. The recommended choice of TAU = 500 ms, DELTA = 100 ms, and ETA = 2.0 gives a 1:10 ratio between the gains of the integral and proportional terms ๐ŸŒˆ. So the rate adaptation is mostly driven by how the congestion signal is changing, with a long-term drift toward its equilibrium value driven by the offset term ๐Ÿฆ‹. Last thing: the scaling parameter KAPPA sets the overall speed of adaptation, and it has to balance responsiveness and stability โญ.

The target feedback interval DELTA has to balance timely feedback against low RTCP feedback message counts ๐Ÿงš. A target feedback interval of DELTA = 100 ms is recommended, which works out to 16 Kbps of feedback bandwidth with 200 bytes per feedback message, so about 1.6% overhead for a 1 Mbps flow ๐Ÿ“. Both simulation studies and frequency-domain analysis in [IETF-95] showed that a feedback interval below 250 ms (so more than 4 feedback messages per second) will not break up the NADA feedback control loop ๐Ÿ’œ.

When calculating the non-linear warping of delay in Equation (1), the current design uses fixed QTH values to decide whether to do the warping at all ๐Ÿ™ˆ. You should tune this carefully for different environments (like wired vs. wireless) so you don't accidentally discount the congestion signal too early ๐Ÿ˜ฌ. It's possible to adapt the value based on past patterns of queuing delay when packets are lost ๐ŸŒธ. Also, note that the non-linear warping can leave multiple NADA streams stuck in loss-based mode when they compete against each other ๐Ÿ’€.

When calculating the aggregate congestion signal x_curr, DMARK and DLOSS affect the steady-state packet loss/marking ratio the flow sees at a given available bandwidth โœจ. Higher DMARK and DLOSS values give lower steady-state loss/marking ratios, but they're more sensitive to individual loss/marking events ๐Ÿ‘‘. The current design fixes these values, but this document also encourages exploring a way to tune them automatically based on the bandwidth sharing behaviour you want when competing with loss-based flows (like loss-based TCP) ๐Ÿซถ.

6.4. Sender-Based vs. Receiver-Based Calculation

In the current design, the aggregated congestion signal x_curr is calculated at the receiver, so the sender doesn't care what kind of network congestion indication (delay, loss, or marking) is being used ๐Ÿฆ‹.

You can also move those receiver-side calculations to the sender. The receiver just reports per-packet information in periodic feedback messages defined in [RTCP-FEEDBACK] ๐ŸŽ€. This lets senders on different congestion control schemes interoperate ๐ŸŒˆ, but the feedback messages need slightly more overhead ๐Ÿ˜ญ. Check [RTCP-FEEDBACK] for the desired feedback message format and the recommended feedback intervals ๐Ÿ’….

6.5. Incremental Deployment

One nice thing about NADA is that video endpoints behave consistently no matter what the network nodes are doing, and that makes it easy to adopt gradually ๐Ÿงšโœจ.

At first, the congestion control can run with zero explicit network support. It just uses observed relative one-way delay measurements and packet loss ratios as implicit congestion signals ๐ŸŒธ.

If ECN is enabled at the network nodes with RED-based marking, the receiver can fold its ECN marking observations into the equivalent delay calculation ๐Ÿ”ฅ. The sender can respond to these explicit congestion signals without any changes ๐Ÿ’–.

Eventually, networks with proactive marking based on token bucket metering level get the extra perks of zero standing queues and lower end-to-end delay, and they still work seamlessly with existing senders and receivers ๐Ÿ‘‘๐ŸŒˆ.

7. Reference Implementations ๐Ÿ’œ

The NADA scheme has been implemented in both the ns-2 [NS-2] and ns-3 [NS-3] simulators. The ns-2 version runs the calculations from Section 4.2 at the receiver side, while the ns-3 version runs those receiver-side calculations at the sender for interoperability ๐Ÿฆ‹. Extensive ns-2 simulation evaluations of an earlier draft of this document are recorded in [ZHU-PV13] ๐ŸŽ€. An open-source NADA implementation as part of an ns-3 module is available at [NS3-RMCAT] ๐ŸŒธ. Evaluation results of this document based on ns-3 are presented in [IETF-90] and [IETF-91] for the wired test cases documented in [RMCAT-EVAL-TEST] ๐Ÿงš. Evaluation results of NADA over Wi-Fi-based test cases defined in [WIRELESS-TESTS] are presented in [IETF-93] ๐Ÿ“ถ. These simulations showed that NADA flows can get their fair share of bandwidth when competing against each other ๐Ÿ‘‘. They adapt fast when other flows arrive or leave, and they sustain reasonable throughput against loss-based TCP flows ๐Ÿ’….

[IETF-90] describes the implementation and evaluation of NADA in a lab setting ๐Ÿ“. Preliminary evaluation results of NADA in single-flow and multi-flow test scenarios are presented in [IETF-91] โœจ.

A reference implementation of NADA was made by modifying the WebRTC module embedded in the Mozilla open-source browser ๐Ÿฆ‹. Presentations from [IETF-103] and [IETF-105] document real-world evaluations of the modified browser driven by NADA ๐Ÿ”ฅ. The experiments involved remote connections with endpoints over home or enterprise wireless networks ๐ŸŒˆ. These evaluations validate that NADA flows recover quickly from throughput drops caused by intermittent delay spikes over last-hop wireless connections ๐Ÿ˜ญ๐Ÿซถ.

8. Suggested Experiments ๐Ÿงช

NADA has been extensively evaluated under many test scenarios, including the collection of test cases specified by [RMCAT-EVAL-TEST] and the subset of Wi-Fi-based test cases in [WIRELESS-TESTS] ๐Ÿ’–. Additional evaluations looked at how NADA interacts with AQM schemes such as RED, Controlling Queue Delay (CoDel), and Proportional Integral Controller Enhanced (PIE) ๐ŸŒธ. Most of these were done in simulators, and a few key test cases were run in lab environments with implementations embedded in video conferencing clients ๐ŸŽ€. It is strongly recommended to implement and experiment with NADA in real-world settings ๐Ÿšจ. That's how you'll learn how to choose or automatically adapt the key algorithm parameters (see the list in Table 2) as discussed in Section 6 ๐Ÿ’œ.

Additional experiments are suggested for these scenarios, preferably over real-world networks:

  • Experiments reflecting the setup of a typical WAN connection ๐ŸŒ.
  • Experiments with ECN marking turned on at the network for existing test cases ๐Ÿฆ‹.
  • Experiments with multiple NADA streams bearing different user-specified priorities ๐Ÿ‘‘.
  • Experiments with additional access technologies, especially over cellular networks such as 3G/LTE ๐Ÿ“ฑ.
  • Experiments with various media source contents, including audio only, audio and video, and application content sharing (e.g., slideshows) ๐ŸŽฌ.

9. IANA Considerations ๐ŸŒท

This document has no IANA actions ๐Ÿซถ.

10. Security Considerations ๐Ÿ”

โš ๏ธ Big security moment, bestie, pay attention ๐Ÿ˜ค

The rate adaptation mechanism in NADA relies on feedback from the receiver. That makes it vulnerable to attacks where feedback messages get hijacked, replaced, or deliberately injected with misleading information, causing denial of service similar to what can hit TCP ๐Ÿ˜ฑ. Therefore, it is RECOMMENDED that the RTCP feedback message is at least integrity checked ๐Ÿ”’. On top of that, [RTCP-FEEDBACK] talks about the risk of a receiver giving misleading congestion feedback and the ways to mitigate it ๐Ÿ›ก๏ธ.

Changing the sending rate based on the sender-side rate-shaping buffer may cause temporary excessive congestion in the network when the video encoder doesn't respond to rate changes ๐Ÿ’€. This can be reduced by limiting how much rate change the rate-shaping buffer introduces, bounding the size of the rate-shaping buffer at the sender, and keeping a maximum sending rate allowed by NADA ๐Ÿงฏ.

11. References ๐Ÿ“š

11.1. Normative References

11.2. Informative References ๐Ÿ“šโœจ

Okay bestie, here's the reading list for the nerdy extras ๐Ÿค“๐Ÿ’– Each one is a reference the spec points to but doesn't need you to read first.


Appendix A. Network Node Operations ๐Ÿงš

NADA is super flexible ๐Ÿ’… It can work with different network queue management schemes and it doesn't assume any one specific network node operation. ๐ŸŒธ To show what that looks like, this appendix walks through three variants of queue management behavior at the network node. Each one leads to either implicit or explicit congestion signals. โœจ We also have to be honest here: NADA has not yet been tested with non-probabilistic ECN marking behaviors. ๐Ÿ™ˆ

In all three flavors, the network queue runs on the simple First In, First Out (FIFO) principle. ๐Ÿ“ There's no need to keep per-flow state, so the whole thing can scale easily with a big pile of video flows and at high link capacity. ๐Ÿ‘‘

A.1. Default Behavior of Drop-Tail Queues ๐ŸŽ€

In a conventional network with drop-tail or RED queues, congestion gets inferred from the estimation of end-to-end delay and/or packet loss. ๐Ÿฆ‹ Packet drops at the queue are detected at the receiver, and they contribute to the calculation of the aggregated congestion signal x_curr. The network node doesn't need to do anything special here. ๐Ÿ’–

A.2. RED-Based ECN Marking ๐Ÿ’œ

In this mode, the network node randomly marks the ECN field in the IP packet header, following the Random Early Detection (RED) algorithm [RFC7567]. The marking probability gets calculated in two steps every time a packet arrives:

  1. update smoothed queue size q_avg as:
q_avg = w*q + (1-w)*q_avg
  1. calculate marking probability p as:
              / 0,                    if q < q_lo
              |
              |        q_avg - q_lo
          p= <  p_max*--------------, if q_lo <= q < q_hi
              |         q_hi - q_lo
              |
              \ p = 1,                if q >= q_hi

Here, q_lo and q_hi are the low and high thresholds of queue occupancy. โœจ The maximum marking probability is p_max.

The ECN marking events contribute to the calculation of an equivalent delay x_curr at the receiver. ๐Ÿซถ No changes are needed at the sender, which is honestly so nice for the sender. ๐Ÿ’…

A.3. Random Early Marking with Virtual Queues ๐ŸŒˆ

Advanced network nodes may support random early marking based on a token bucket algorithm that was originally designed for Pre-Congestion Notification (PCN) [RFC6660]. ๐Ÿ”ฅ The early congestion notification (ECN) bit in the IP header of packets gets marked randomly. The marking probability is calculated based on that PCN token bucket algorithm [RFC6660]. The target link utilization is set as 90%. The marking probability is designed to grow linearly with the token bucket size when it varies between 1/3 and 2/3 of the full token bucket limit. ๐Ÿง

Calculation of the marking probability involves the following steps upon packet arrival:

  1. meter packet against token bucket (r,b)
  2. update token level b_tk
  3. calculate the marking probability as:
               / 0,                     if b-b_tk < b_lo
               |
               |          b-b_tk-b_lo
          p = <  p_max* --------------, if b_lo <= b-b_tk < b_hi
               |           b_hi-b_lo
               |
               \ 1,                     if b-b_tk >= b_hi

Here, the token bucket lower and upper limits are denoted by b_lo and b_hi, respectively. ๐Ÿฆ‹ The parameter b indicates the size of the token bucket. The parameter r is chosen to be below capacity, which results in slight underutilization of the link. The maximum marking probability is p_max.

The ECN marking events contribute to the calculation of an equivalent delay x_curr at the receiver. No changes are needed at the sender. ๐Ÿ’– The virtual queuing mechanism from the PCN-based marking algorithm leads to additional benefits, such as zero standing queues. ๐ŸŽ‰

Acknowledgments ๐Ÿซถ

The authors would like to thank Randell Jesup, Luca De Cicco, Piers O'Hanlon, Ingemar Johansson, Stefan Holmer, Cesar Ilharco Magalhaes, Safiqul Islam, Michael Welzl, Mirja Kรผhlewind, Karen Elisabeth Egede Nielsen, Julius Flohr, Roland Bless, Andreas Smas, and Martin Stiemerling for their valuable review comments and helpful input to this specification. Y'all are the real MVPs ๐Ÿ’–๐Ÿ‘‘

Contributors ๐ŸŽ€

okay bestie, these are the legends who helped make NADA real ๐Ÿซถ they got their hands dirty with the implementation and testing, so this spec is way more solid because of them โœจ

Paul E. Jones <paulej@packetizer.com> of Cisco Systems ๐Ÿ’– built an early version of the NADA congestion control scheme and helped with its lab-based testbed evaluations. iconic behaviour ๐Ÿ‘‘

Jiantao Fu <jianfu@cisco.com> of Cisco Systems ๐Ÿ”ฅ helped with the implementation and extensive evaluation of NADA, both in Mozilla web browsers and in earlier simulation-based evaluation efforts. the dedication is unreal ๐Ÿ˜ญ

Stefano D'Aronco <stefano.daronco@geod.baug.ethz.ch> of ETH Zurich ๐Ÿฆ‹ (previously at Ecole Polytechnique Federale de Lausanne when contributing to this work) helped with the implementation and evaluation of an early version of NADA in [NS-3]. ngl the simulator era was a whole vibe ๐ŸŒˆ

Charles Ganzhorn <charles.ganzhorn@gmail.com> ๐ŸŒธ contributed to the testbed-based evaluation of NADA during an early stage of its development. early-stage helpers are the realest ๐Ÿงš


Authors' Addresses ๐Ÿ’…

these are the four people who wrote the spec itself, so here's where to find them ๐Ÿ“

Xiaoqing Zhu ๐Ÿ’œ Cisco Systems

12515 Research Blvd., Building 4
Austin, TX 78759
United States of America

Email: xiaoqzhu@cisco.com


Rong Pan ๐ŸŒธ Intel Corporation

2200 Mission College Blvd
Santa Clara, CA 95054
United States of America

Email: rong.pan@intel.com


Michael A. Ramalho ๐Ÿฆ‹ AcousticComms Consulting

6310 Watercrest Way Unit 203
Lakewood Ranch, FL 34202-5211
United States of America

Phone: +1 732 832 9723 Email: mar42@cornell.edu URI: http://ramalho.webhop.info/


Sergio Mena ๐Ÿซถ Cisco Systems

EPFL, Quartier de l'Innovation, Batiment E
CH-1015 Ecublens
Switzerland

Email: semena@cisco.com

and that's a wrap on RFC 8698, the NADA congestion control spec, fully slay ๐ŸŒˆ๐Ÿ‘‘โœจ

๐Ÿ“ฆ where this page comes from