Subject: [rtcweb] Congestion Control proposal

From: Randell Jesup <[email-masked]>
Date: Thu, 06 Oct 2011 11:32:22 -0400

Situation:

We have a UDP connection, either direct or via a TURN server.

On that UDP connection, we've negotiated DTLS.

We're running multiple RTP streams in both directions using DTLS-SRTP.

We also are running multiple data channels, both reliable and unreliable,
over DTLS (perhaps UDP-DTLS-SCTP).

We want to congestion-control all the network data, preferably in as
unified fashion as possible.

Google disclosed an algorithm for doing "predictive" bottleneck-buffer
queue-length sensing based on packet arrival times compared to RTP
timestamps.

Their algorithm should work well in most cases on a single channel, but
with multiple channels there may be inequities and hunting, plus the
application may want to have input into which streams get the available
bits.

I propose an extended version of Google's algorithm, based around computing
the available bandwidth and buffer-fullness across either all the media
channels, or the media channels and the data channels.

Constraints/assumptions:

1) variable number of media streams (SSRCs), audio and/or video
2) The streams may use different timestamp sample rates
3) The streams may have timestamp rates that are not synchronized;
    i.e. they may drift both relative to NTP and to each other.
4) Media streams may start and stop at any point
5) Audio streams may use DTX/VAD and so have gaps in sending
6) Video streams may use variable frame rates
7) Video streams may have major variation in bandwidth from frame
    to frame (iframes, motion or lack thereof, etc).
8) All media streams in a direction might be inactive or in DTX/VAD at
    any given time, for an indeterminate period
9) Media streams will have limits on their ability to adjust bandwidth
    use.  In some cases a renegotiation of streams and/or codecs may be
    required to meet the limitations of the bottleneck.
10) If the other end doesn't implement this congestion control mechanism
     we must adapt bandwidth based on normal RTCP

Goals: (roughly in order of importance)
1) Consistently low-delay
    Note that we don't say "staying within bandwidth" here; the goal
    is the end-user experience (delay&  loss), not the mechanism
    affecting delay and loss (bandwidth).
2) Low but not necessarily 0 loss.
3) Good use of available bandwidth (within 'fair-share' bounds).
4) Rapid adaptation to changes in bandwidth available
5) Good startup pattern
6) Stable algorithm; few bad "corner cases" and quick recovery from
    them.
7) Good performance in the face of true random loss.
8) Good performance/recovery when the browser is active (or another browser
    on the same access/bottleneck link).
9) Bandwidth must be controlled to the level of not allowing the JS app to
    use it in a denial-of-service attack.

The general algorithm is to take each incoming packet from each SSRC
source; convert the timestamp to an estimated (source) NTP time it was sent
at, including compensation for clock drift rates; and then using the stream
of source packets, sizes, and time of sending estimate the slope of the
incoming rate compared to the sending rate.  Effectively, we consider all
the media packets to be one, big stream using an algorithm effectively
similar to Google's, giving us more data points.  The merged packets will
look rather more like a video stream with a collection of small and large
packets than an audio stream.

To communicate the bandwidth available, we have two main options:

1) run the algorithm on the recipient side, and send the target value to
    the sender in the equivalent of TMMBR.  (We can't use normal TMMBR since
    that's for one SSRC, and we want it to apply to all SSRCs being sent.)
2) collect and process the arrival data, and communicate to the sender the
    slope of the line, the incoming bitrate, number of packets, and loss
    rate (anything else?).  The sender will calculate how it should respond.

Both of these require a new RTCP feedback message, though the first is very
closely associated with TMMBR.  I've had good experiences in the past with
case #2.

Concerns:

Stability of this merged stream is a concern; we'll need to do some good
real-world and simulated tests (see Testing below).

Startup:

There are issues both with starting too low (quality is poor at the start
and takes a while to get better), and with starting too high (you
immediately can get into a delay situation and have to go into recovery).
In general, starting too low is better than starting too high, as when we
ramp up past the bottleneck we will not be too far over the limit and so
recovery will be easier.  In general, the bottleneck link is often
upstream, though this is moderating as high-bandwidth broadband becomes
more common.

Options include:
   a) Start at fixed value
   b) Start at N% below the value from the last call with this person
      (probably requires the App to help here)
   c) Start at N% below the value from the last call with anyone
   d) Have the other side tell us the rate they successfully received in the
      last call.  Start the call at the lower of the last-call reception
      rate from the far end or our last-call sending rate, minus n%
   e) probe bandwidth at or before the start of the call using a packet
      train

'a' will be quite sub-optimal for most cases, though if the value is
low enough it won't be over-bandwidth.  Some applications (games, etc)
may want to limit the starting bandwidth to avoid negative interactions
with other dataflows.

'b' has a problem that if the last call had a much higher bottleneck
bandwidth (especially on the remote downstream), the new call may be
over-bandwidth, perhaps badly.  This won't be the norm, but may happen
especially with mobile/wifi at either end.

'c' has a problem that if the last callee had a much higher bottleneck
bandwidth (especially on the remote downstream), the new call may be
over-bandwidth, perhaps badly.  If the caller's upstream bandwidth is high
compared to typical downstream bandwidth, then the likelihood of starting
over-bandwidth is high.

'd' has the advantage of selecting an appropriate value regardless of
whether the bottleneck is on upstream or downstream.  The downside of 'd'
is that the bottlenecks may have changed since the last call in which case
we may start over-bandwidth.  The historical data could be transferred
via pre-call signalling.

'e' allows direct measurement of the current call bottlenecks.  However 'e'
can be misled if a mid-call router that isn't the bottleneck buffers the
packet train while housekeeping or doing other operations and then releases
them (it can collapse the signal from an earlier bottleneck).  It would
need to be combined with starting on the low side until a valid measurement
is completed.  Single measurements are imprecise with packet trains.

Also, we need to consider the impact on other existing PeerConnections -
for example, when you add a new person to a full-mesh conference, you'll want
to start their bandwidth at about 1/Nth of the former total outgoing
bandwidth, and reduce the outgoing bandwidth of those other channels to
provide the bandwidth for the new participant.

Obviously there is no obvious perfect solution, and combinations of
solutions may give the best overall experience.  In this situation, it
makes sense to leave the actual choice up to the implementations or even
the application, and make sure that they have the information needed to
make the choice, such as the last-call bandwidth from the other end.
(I don't believe that information would be a privacy leakage of any note.)

Data channels:

If we use SCTP-DTLS-UDP, we can rely on SCTP's congestion-control, perhaps
modified to "play nice" with the media streams, and to have some amount of
known priority relative to them.  (For example, if the media streams need
to back off and the data streams are using a consistent amount of data, it
could reduce the amount or rate data is sent.)  We also could pre-allocate
some amount of bandwidth to data, and so long as it's not using it media
could.  Note that SCTP's congestion control is supposed to be in some
manner pluggable, so we could modify/replace it fairly easily.

Worst case: it acts as a separate, TCP-friendly flow we compete with.

If we have to use TCP-over-UDP, then that will be congestion-controlled for
each individual flow, but the non-reliable channels will need separate
congestion control.  Simplest would be to add RTP-like timestamps to the
non-reliable data channels so they could pulled into the framework of the
RTP channels as if they were bursty RTP data.

Even if the data flows are separately congestion controlled, in many uses
they will be non-continuous flows (discrete messages as opposed to data or
file transfers).  These sorts of channels have different needs and
different impacts on the media channels from continuous flows: they're
bursty; low delay is important (especially on the initial packet for a
burst, which is often the only packet), and without a steady stream
congestion control will have little effect - and will have little impact on
the media flows.  For small bursts of data traffic, the "right" solution
may be to simply ignore them up to some limit, and above that limit start
to subtract the data channel usage from the available bandwidth for
variable-rate encoders.

The problem here will be defining "small".  This will need to be tested and
simulated so we know the impacts of different data usage patterns.  I'll
throw a straw-man proposal out there: if the increase in data usage over
the last 1/2 second is below 20% of the total estimated channel bandwidth,
no adjustment to the media channels shall be done, and normal congestion
control mechanisms will be allowed to operate with no interference.  Above
that value, the media channels if possible will be adjusted down in
bandwidth by some amount related to the increase in data channel bandwidth.

The reason for using the increase in bandwidth here is that for steady
flows, normal congestion control should operate well; the problem is when
you have a spike in bandwidth use - the latency in reaction may be longer
than the duration of the burst, and hurt end-to-end delay in the meantime.
So when there's a sudden jump in data bandwidth, you temporarily offset
media down to keep delay and buffering under control.  You could also
increase media bitrates if a steady flow suddenly drops, though normal
congestion control mechanisms should use the now-available bandwidth
quickly on their own.

JS Interface:

We need to tell the application about bandwidth changes, and give it the
option of making choices, both in the allocation of bits among the various
streams of data, and of the actual streams themselves (adding or shutting
down streams, or switching modes (mono/stereo, codecs possibly, etc)).  If
the application doesn't care to make a choice we'll do it for them.  We'll
also want the JS application to be able to affect the congestion-control
status of the data channels, so it could take bits from the data channels
without engendering a tug-of-war and temporary over-bandwidth/buffering.

There are inherent delays to some of these actions by the app, and in an
over-bandwidth case we need to reduce bandwidth *now*, so we may want to
have the "I'm over-bandwidth" case start by automatically reducing
bandwidth if possible, and inform the JS app of the reduction and let it
rebalance or change the details or nature of the call.

We could use some good straw-men proposals for an API here to the JS code.

Security comes in slightly here in the avoidance-of-DoS issue.  If we
reduce bandwidth on a notification from the far side first, then tell the
app, then even if the app goes rogue and hikes the bandwidth instead of
dropping it we'll just cut it back again.  We may need some extra levers
and limits, but I think this is all handleable.

Testing:

We'll want to experiment with both real-world packet traces and with
simulated scenarios, since as an active algorithm pure network traces only
go so far when testing.  We need to test with cross traffic on our side
of the bottleneck going to the far side, traffic that stays on our side or
stays on the other side, with appearance of new bottleneck nodes, with
route changes in mid-call, interface changes, wireless, wireless-in-motion
going into and out-of good signal range, competing traffic hosted by the
same browser, etc.

Extensions:

Can we generalize this to provide guidance when we're receiving connections
from multiple sources?

This would be gated on knowing if the bottleneck is in a "shared" section
of the path or not.  (*Usually* bottlenecks are on upstream, but that might
be changing.)

-- 
Randell Jesup
[email-masked]

---

From: Wesley Eddy <[email-masked]>
Date: Thu, 06 Oct 2011 18:47:33 -0400

On 10/6/2011 11:32 AM, Randell Jesup wrote:
 > ...

I can't claim to fully understand the intended architecture from the
description in this email, but something struck me as odd when in one
breath it seems like data is flowing over TCP or SCTP (layered over
UDP) and in another there's a separate algorithm (the Google one, or
some modification) running for estimating bandwidth.  Those seem
mutually exclusive to me, unless I completely misunderstand the goal
(which is entirely possible).

Reporting changes to the application is another matter with its own
challenges in either case, since the way the application responds will
limit what the CC can do afterwards (without additional probing).

If running TCP or SCTP, the congestion window (cwnd) and RTT should be
sufficient to convey the available bandwidth at a point in time.  If
anything lower is reported to the app, the cwnd will never open up
because it will be application-limited, and if anything higher is
reported, it will build up a queue in the sender that won't be
drained any faster than the cwnd allows.

-- 
Wes Eddy
MTI Systems

---

From: Randell Jesup <[email-masked]>
Date: Thu, 06 Oct 2011 19:12:04 -0400

Comments inline

> (which is entirely possible).

Well, I should note that the Google algorithm primarily estimates the 
buffer state of the bottleneck router, which indirectly is correlated to 
the bandwidth available at that instant.  And TCP & the default SCTP 
congestion control are loss-based AIMD algorithms, so at any point may 
have a view of available bandwidth that is inflated (due to bufferbloat) 
or too low (in recovery from a loss event(s)).  The fallback/simplest 
model would be to just consider the data channels under SCTP and the 
media channels to be separate flows, and let them fight for bandwidth as 
normal.

If we can make them work together or at least be respectful of each 
other to avoid "fighting", that would be better.  The app may be able to 
help us by indicated the type of data to be transferred and the relative 
priority of it.  (Background file transfers might stick to a small 
percentage of the bandwidth unless bandwidth is very high; a game may 
give priority to one stream of data over both media and other data 
streams - it's unclear currently if we'll be able to support that, but 
it would be nice.)

> drained any faster than the cwnd allows.

Don't forget that we normally will have a media channel active, and if 
video is being sent (and to a lesser extent audio, especially if we're 
using Opus) that media channel is adaptive and can adapt upwards to find 
the limits of bandwidth.  Involving the app is so that, if it wants, it 
can make more global decisions like "drop the second video stream", or 
"reduce the resolution", or "drop stereo", or "drop audio to narrowband 
to save bits for video".  Decisions like that are tough or impossible 
for webrtc to make on it's own because it doesn't have the context of 
the application to guide it.

That said, the interface and parameters and style for interacting with 
the JS app is the thing this posting is weakest on, since I'm not 
well-versed in the common API paradigms that JS app developers expect, 
and I'd love proposals for how we expose these choices and information 
to the app.

-- 
Randell Jesup
[email-masked]

---

From: Bernard Aboba <[email-masked]>
Date: Fri, 7 Oct 2011 12:02:21 -0700

> > (which is entirely possible).

[BA] In practice, I think the concern is largely over UDP-based traffic. 
For TCP or SCTP  traffic, the native congestion control mechanisms should
be sufficient. 

> The fallback/simplest model would be to just consider the data channels 
> under SCTP and the media channels to be separate flows, and let them 
> fight for bandwidth as normal.

[BA] There are multiple concerns here.  One was about DoS attacks, which
was about having the recipient confirm the desired bandwidth.  That's 
what Harald mentioned.

The other issue is congestion control/codec adaptation (e.g. responding
to RFC 3714 concerns).   While I understand the need for this on the
datagram channel, with respect to congestion control of RTP traffic, won't
adaptation be codec-specific?  If the codec doesn't adapt (e.g. G.711) or
does so based on RTCP feedback, how would an additional congestion
control mechanism work?  

> other to avoid "fighting", that would be better.   
>

> The app may be able to help us by indicated the type of data to be transferred and the relative 

[BA] Agree. For example, if we're talking about a high-twitch game, 
you might want different behavior than for one where the datagram
channel needs more reliability.  

> limit what the CC can do afterwards (without additional probing).

[BA] Yes.  

> the limits of bandwidth. 

[BA] Yes, it can but today that adaption is typically based on RTCP, right?

> Decisions like that are tough or impossible for webrtc to make on it's 
> own because it doesn't have the context of the application to guide it.

[BA] The problem is that handling the events correctly will also probably be
outside the capability of your average application developer.  So enabling
reasonable things to happen by default is probably a practical requirement. 

> and I'd love proposals for how we expose these choices and information 

[BA] The problem in my  mind is whether we're really expecting RTCWEB
Codecs do something with the additional information provided.

---

From: Colin Perkins <[email-masked]>
Date: Fri, 7 Oct 2011 20:12:13 +0100

[inline]

On 6 Oct 2011, at 16:32, Randell Jesup wrote:
...
> is completed.  Single measurements are imprecise with packet trains.

For a new call, the only safe approach for the network would seem to be option (a), starting at a low rate, followed by a fairly rapid increase in rate to find the safe operating point (i.e., mirroring TCP slow start in concept, if not in detail). The low rate would be chosen to support the voice channel, presumably, so the call is useful immediately, but might then take several RTTs to ramp up to a high enough rate for video to be usable. An initial delay on the video is not an ideal user experience, but I don't see it as being especially problematic provided the voice channel is usable immediately, and we don't seem to have safe options for avoiding it.

Using a packet pair/train to get an estimate of the available bandwidth is appealing, but I'm unconvinced it's accurate enough to be reliable. We've done packet pair measurements to residential links that show extremely inaccurate (high) bandwidth estimates in many cases, so I wouldn't trust that as an initial sending rate. Using a longer packet train would improve accuracy, but at the cost of loading the path, and potentially disrupting any traffic sharing the path. I'm not sure such a bandwidth estimate is that worthwhile if it delays/disrupts the start of the voice channel.

When restarting a previously application limited flow after some short pause in transmission (e.g., the centralised video mixer scenario, where only the active speaker sends video to the mixer), then I'm much more comfortable with restarting at or near the previous rate, provided there's been no indication that the path has changed. The rationale here is that you've had some recent indication that the path can support the rate, but with a new connection, even if to someone you've previously spoken with, there's much less of a guarantee that the available bandwidth is consistent with the previous observation.

> congestion control mechanisms should use the now-available bandwidth

Is there some way of measuring the spare queueing capacity of the path, perhaps by periodic probing? To define "small" in a way that's meaningful to the path, we'd be looking at a burst that can be queued in the network without causing excessive delay or queue overflow/loss. Using "1/2 second" or "20%" seems too arbitrary. 

> We could use some good straw-men proposals for an API here to the JS code.

The right model might be for the application to communicate policy for how to adapt, which the browser then implements. Putting Javascript in the congestion control loop is a concern because of the slow response, which runs the risk of causing oscillation. If we can let the browser run the rate adaption mechanism that's more likely to be stable, and leave the slower Javascript to make the decision about adaptation policy.

-- 
Colin Perkins
http://csperkins.org/

---

From: Randell Jesup <[email-masked]>
Date: Fri, 07 Oct 2011 17:07:50 -0400

> does so based on RTCP feedback, how would an additional congestion

This (this proposal) is the mechanism which will tell the sender to 
adapt their codec settings (video encoder bitrate, etc).

> [BA] Yes, it can but today that adaption is typically based on RTCP, right?

Not on traditional SR/RR RTCP sub-packets, but on AVPF Feedback 
messages; either a variant of TMMBR (if we do all the bandwidth 
calculations in the client), or a message where we feed back cooked 
arrival statistics to the sender via a new Feedback message.  If we 
don't get this info from the receiver we'll fall back to classic 
RR/SR-based adaptation, which sucks.  Doable, but sucks (especially if 
you only get a report average every 5 seconds).

> reasonable things to happen by default is probably a practical requirement.

We'll definitely supply or apply defaults, and if the application 
doesn't choose we'll handle it for them.  We may have some hinting to 
guide our default adaptation (relative priorities).

> Codecs do something with the additional information provided.

You should read Harald's draft for the base algorithm that we'll be 
modifying to provide this.  The base algorithm is from a very good class 
of low-delay congestion control algorithms, based on bottleneck router 
bufferstate sensing:

http://www.ietf.org/id/draft-alvestrand-rtcweb-congestion-00.txt

-- 
Randell Jesup
[email-masked]

---

From: Randell Jesup <[email-masked]>
Date: Fri, 07 Oct 2011 17:37:31 -0400

> For a new call, the only safe approach for the network would seem to be option (a), starting at a low rate, followed by a fairly rapid increase in rate to find the safe operating point (i.e., mirro…

I understand your concern, and agree one should start "low" - but I also 
feel that for many applications and many users, this would be an 
over-conservatism that would seriously degrade a very important point in 
a communication.  That initial "answer" behavior had a big impact on the 
user experience and in the end, utility to the user.  In "most" calls 
(I'd guess for residential desktop browsers >95%, laptops >70% though 
much more variable) the bottleneck will be the same or similar to the 
last call - the local upstream, which is fairly constant.

There are users and use-cases where this consistency will not apply - 
mobile laptop users (when away from desk/office), tablet/handsets.  I 
will note that in most of these cases the change in bottleneck will tend 
to be less than 2x, so major changes in bandwidth will be fairly 
uncommon.  (You can get a hint on this by checking for external IP 
address changes!)

In most videophones and soft clients that I've looked at, they have a 
configured bitrate set by the user and either start at that bitrate, or 
start at a fraction of that bitrate.  At WorldGate, we started at a 
sliding percentage of the configured bandwidth - a higher percentage at 
low bandwidths, and down to 50% of configured at high bandwidths, 
combined (as you suggest) with a much higher ramp-up rate (and 
faster/further cut-back on problems) for the first seconds of the call.

These things, taken together, make we want to be a bit more aggressive 
at using history, and perhaps also use the recent N calls' variance in 
bottleneck rate as a guide (if they're all good at higher rates, start 
at 50 or 60% of the average; if there's a lot of variance (laptop moving 
around) use not the last call, but perhaps the lowest quartile or 10th 
minus 10 or 20%.

Also - this is something that I strongly feel should not be normative.  
This is guidance and I do feel that there is  a place for the 
application to provide input and/or user preference here.  I think we 
*should* provide guidance and defaults.

> Using a packet pair/train to get an estimate of the available bandwidth is appealing, but I'm unconvinced it's accurate enough to be reliable. We've done packet pair measurements to residential lin…

I am likewise leery of packet trains, especially short start-of-call 
trains.  They're interesting, but as you mention they don't seem 
reliable enough.

> When restarting a previously application limited flow after some short pause in transmission (e.g., the centralised video mixer scenario, where only the active speaker sends video to the mixer), th…

Agreed.

> Is there some way of measuring the spare queueing capacity of the path, perhaps by periodic probing? To define "small" in a way that's meaningful to the path, we'd be looking at a burst that can be…

It may be possible to use naturally-occuring bursts (or slightly 
artificially-contrived bursts) to probe the channel.  For example, 
periodic or error-recovery iframes amount to a fairly large burst of 
large packets; measuring the dispersion at the reception end may will 
give you a reasonable estimate of unused bandwidth. (I'll note that if 
you don't have access to the raw network interface this might be a 
little noisier).

> The right model might be for the application to communicate policy for how to adapt, which the browser then implements. Putting Javascript in the congestion control loop is a concern because of the…

Agreed, though some of the adaptations have to occur at the application 
level (turning off channels, which may involve UI changes, etc).   That 
was why I suggested we adapt using defaults (and any hints given 
("policy" in your post)), and then inform the JS app of the change and 
allow it to rebalance or re-allocate the BW usage, or to change the 
already-made decisions.  This helps guarantee we have working defaults 
and response speed.

I fear if we try to push all that logic down into the media code it 
becomes too complex, because you have to anticipate any way an 
application might want to react, and provide it (and test it).

-- 
Randell Jesup
[email-masked]

---

From: Colin Perkins <[email-masked]>
Date: Tue, 11 Oct 2011 16:35:02 +0100

On 7 Oct 2011, at 22:37, Randell Jesup wrote:
>>> There are issues both with starting too low (quality is poor at the start and takes a while to get better), and with starting too high (you immediately can get into a delay situation and have to go into recovery). In general, starting too low is better than starting too high, as when we ramp up past the bottleneck we will not be too far over the limit and so recovery will be easier.  In general, the bottleneck link is often upstream, though this is moderating as high-bandwidth broadband becomes more common.
>>> 
>>> Options include:
>>>  a) Start at fixed value
>>> 'a' will be quite sub-optimal for most cases, though if the value is low enough it won't be over-bandwidth.  Some applications (games, etc) may want to limit the starting bandwidth to avoid negative interactions with other dataflows.
>>> 
>>> 'b' has a problem that if the last call had a much higher bottleneck bandwidth (especially on the remote downstream), the new call may be over-bandwidth, perhaps badly.  This won't be the norm, but may happen especially with mobile/wifi at either end.
>>> 
>>> 'c' has a problem that if the last callee had a much higher bottleneck bandwidth (especially on the remote downstream), the new call may be over-bandwidth, perhaps badly.  If the caller's upstream bandwidth is high compared to typical downstream bandwidth, then the likelihood of starting over-bandwidth is high.
>>> 
>>> 'd' has the advantage of selecting an appropriate value regardless of whether the bottleneck is on upstream or downstream.  The downside of 'd' is that the bottlenecks may have changed since the last call in which case we may start over-bandwidth.  The historical data could be transferred via pre-call signalling.
>>> 
>>> 'e' allows direct measurement of the current call bottlenecks.  However 'e' can be misled if a mid-call router that isn't the bottleneck buffers the packet train while housekeeping or doing other operations and then releases them (it can collapse the signal from an earlier bottleneck).  It would need to be combined with starting on the low side until a valid measurement is completed.  Single measurements are imprecise with packet trains.
>> 
> I understand your concern, and agree one should start "low" - but I also feel that for many applications and many users, this would be an over-conservatism that would seriously degrade a very important point in a communication.  That initial "answer" behavior had a big impact on the user experience and in the end, utility to the user.  In "most" calls (I'd guess for residential desktop browsers >95%, laptops >70% though much more variable) the bottleneck will be the same or similar to the last call - the local upstream, which is fairly constant.
> 
> There are users and use-cases where this consistency will not apply - mobile laptop users (when away from desk/office), tablet/handsets.  I will note that in most of these cases the change in bottleneck will tend to be less than 2x, so major changes in bandwidth will be fairly uncommon.  (You can get a hint on this by checking for external IP address changes!)
> 
> In most videophones and soft clients that I've looked at, they have a configured bitrate set by the user and either start at that bitrate, or start at a fraction of that bitrate.  At WorldGate, we started at a sliding percentage of the configured bandwidth - a higher percentage at low bandwidths, and down to 50% of configured at high bandwidths, combined (as you suggest) with a much higher ramp-up rate (and faster/further cut-back on problems) for the first seconds of the call.
> 
> These things, taken together, make we want to be a bit more aggressive at using history, and perhaps also use the recent N calls' variance in bottleneck rate as a guide (if they're all good at higher rates, start at 50 or 60% of the average; if there's a lot of variance (laptop moving around) use not the last call, but perhaps the lowest quartile or 10th minus 10 or 20%.
> 
> Also - this is something that I strongly feel should not be normative.  This is guidance and I do feel that there is  a place for the application to provide input and/or user preference here.  I think we *should* provide guidance and defaults.

I'm hesitant to accept the argument that bottleneck bandwidth is likely to be roughly consistent, so we can start at a rate near that bandwidth. There's getting to be a lot more mobile devices that can switch between WiFi and 3G links with potentially very different capacity, and even ADSL lines can be highly variable with time of day and other users on the same link. As a result, if we are to use history, I think we need normative rules for how, so we at least limit the amount and duration of any damage caused when the history-derived bandwidth estimate is wrong.

> I am likewise leery of packet trains, especially short start-of-call trains.  They're interesting, but as you mention they don't seem reliable enough.
> 
> It may be possible to use naturally-occuring bursts (or slightly artificially-contrived bursts) to probe the channel.  For example, periodic or error-recovery iframes amount to a fairly large burst of large packets; measuring the dispersion at the reception end may will give you a reasonable estimate of unused bandwidth. (I'll note that if you don't have access to the raw network interface this might be a little noisier).

Unused bandwidth might be less important than unused queuing capacity. 

> Agreed, though some of the adaptations have to occur at the application level (turning off channels, which may involve UI changes, etc).   That was why I suggested we adapt using defaults (and any hints given ("policy" in your post)), and then inform the JS app of the change and allow it to rebalance or re-allocate the BW usage, or to change the already-made decisions.  This helps guarantee we have working defaults and response speed.
> 
> I fear if we try to push all that logic down into the media code it becomes too complex, because you have to anticipate any way an application might want to react, and provide it (and test it).

Agree. There's clearly a balance to be got here. The main point is that the javascript can be in the control loop, since it's operating at a slower timescale.

-- 
Colin Perkins
http://csperkins.org/

---

From: Randell Jesup <[email-masked]>
Date: Wed, 12 Oct 2011 02:54:10 -0400

Inline below...

We should probably move this to rtp-congestion.

On 10/11/2011 11:35 AM, Colin Perkins wrote:
>> I understand your concern, and agree one should start "low" - but I also feel that for many applications and many users, this would be an over-conservatism that would seriously degrade a very important point in a communication.  That initial "answer" behavior had a big impact on the user experience and in the end, utility to the user.  In "most" calls (I'd guess for residential desktop browsers>95%, laptops>70% though much more variable) the bottleneck will be the same or similar to the last call - the local upstream, which is fairly constant.
>>

Hopefully we can identify most of the interface changes such as you 
mention (IP address changes, OS notification, etc).  But even if we 
can't (ADSL or cable modem upstream variability), the algorithm is 
adaptive; the downside of starting too high is that it quickly sees that 
packets arrive at the destination slower than they should; so roughly 
(depending on RTT) a fractional second or perhaps in some cases a second 
or two will go by before low-latency within-bandwidth communication is 
established.  And if we're only a little over it may not be very 
noticeable.  And as I suggested, if you start at a significant reduction 
from expected bandwidth (I generally would recommend 20-30% below at 
"low" bandwidths, and up to 50-60% reduction at "high" bandwidths), the 
odds of being over the actual limit, especially in the ADSL/Cable cases 
is low.

> Unused bandwidth might be less important than unused queuing capacity.

I'm not sure we care about unused queuing capability at all - we want to 
stay out of the queue.  We are interested in how far below the limit 
where queuing begins we are.

-- 
Randell Jesup
[email-masked]