Help me understand bitrate settings

I am a little confused by the bitrate settings available and how they work between producers and consumers.

First there is initialAvailableOutgoingBitrate for the WebRTC transport which defaults to 600kbps. Is this the outgoing rate from the client, or from the server? There was also at one point a minimumAvailableOutgoingBitrate mentioned in the docs but I no longer see it referenced anywhere?

Next there is transport.setMaxIncomingBitrate(bitrate) which seems pretty self-explanatory, but I don’t understand how it relates to initialAvailableOutgoingBitrate.

Lastly I am struggling to understand how these bitrates interact with a target audio bitrate for the opus codec.

My overall goal is to support audio-only connections using the opus codec between 96-192kbps. But I want to actually understand how these values interact to achieve this.


initialAvailableOutgoingBitrate is the initial bandwidth estimation for a receiver that mediasoup assumes, this is, how much bitrate mediasoup can send to it.

minimumAvailableOutgoingBitrate is deprecated.

It does not relate at all. That methods sets the maximum bitrate an endpoint can send to mediasoup. It affects both audio and video streams sent by the endpoint to mediasoup. IMHO this is well documented in the API doc.

Audio does not currently affect the bitrate estimation and vice-versa. This will be different in the future when browser implementations evolve.

If you just want to use audio, forget about “bandwidth estimation” at all in mediasoup. Just tell your client side how much bitrate to send. There is API in mediasoup-client for that.

Thank you that clarifies things a bit. Is the client-side API you are referring to just setting the maxBitrate in the encodings array or something different? I tried doing this but I don’t see any change showing up in the SDP offer from the client. I was expecting to see some entry like b=AS which sets the bitrate.

My client-side code looks like:

          track: audioTrack,
          codecOptions: {opusFec: true, opusDtx: true},
          encodings: [{maxBitrate: 40000}], // intentionally low to verify in webrtc internals

edit: I also tried messing with opusMaxPlaybackRate but again, saw no change when I dumped out the sdp offer/answer on the client and no change in chrome://webrtcinternals. It is unclear to me if this codec specific option actually effects the stream bitrate or the expected clockrate of the opus encoded data.

No, you won’t see any difference in the SDP. This is how WebRTC works. See the RTCRtpEncodingParameters spec.

BTW it won’t do anything in Chrome unless you force “Chrome74” handler when creating a Device. Right now by default it uses “Chrome70” handler even if detected Chrome version is higher. This is because there were some issues in Chrome74 and 75.

No, you should expect absolutely nothing at SDP level.

Okay, got it. Again I appreciate you dealing with my complete ignorance here. I got myself mixed up reading too many articles and confused this encoding bitrate with the"extensible bandwidth attribute" of SDP (

Further adding to the confusion was that I have seen SDP lines that reflect that opusMaxPlaybackRate in the SDP like this:
a=fmtp:111 vbr=1; minptime=10; ptime=20; useinbandfec=1; usedtx=0; sprop-maxcapturerate=48000; maxplaybackrate=48000; maxaveragebitrate=320000
I know the mediasoup client does add the FEC and DTX settings in the SDP for those opus settings, so I expected to see maxplaybackrate there as well.

Good to know about the Chrome70 handler as that is what I was testing against.

I think my final question here is what is the best way to verify that the encoding bitrate I have set has actually taken effect? Currently I have just been looking to see a decrease in bytes/sec in chrome’s webrtc internals. Is this viable, or should I be checking the RTC stats from the mediasoup server or some other way?

Thanks again

Client side stats is the most reliable way to see the sending bitrate.

Just wanted to mention that I found the real root cause of my issues and that some of these parameters should (and do) indeed show up in the descriptor when set.

The root bug was this:

This was causing my transpiled version of mediasoup-client to break out of the loop over answerRtpParameters.codecs (here: early and not correctly finishing the building up of the fmtp.config

I verified this by removing the blocks around the switch statement cases and everything is now working as expected! What a strange and unexpected bug. Just wanted to drop a note about it here for posterity.

Thanks again for all your help.

Wow, terrible. So you mean that better use case without { and }? If so, where did you change it? I mean, if this really affects current Babel version we should modify mediasoup-client code.

No, sorry this does not affect current babel versions to my knowledge. It looks like a fix was merged some time ago, but my project is using a quite out-dated version (7.0.0). The fix was merged in 7.1.5 so I don’t think it would be a compelling reason to modify the code. We may end up creating a fork though as it would take far less time than dealing with a major babel version upgrade for us right now.

But yes I removed the { and } from around the case blocks here: and here: (even though I was only dealing with audio in this case I figured I should apply the change everywhere to be sure).

Thanks for the clarification.