Do you use WebRTC with Asterisk? Did you notice calls stop working after updating Google Chrome to version 57? Are you curious why that happened? The answer is the rtcp-mux feature.
What is rtcp-mux?
The majority of VoIP protocols make use of the Realtime Transmission Protocol (RTP) for transmitting and receiving media. In addition to RTP, endpoints send each other Realtime Transmission Control Protocol (RTCP) packets that indicate metadata about the session. This includes the number of packets sent/received, jitter information, and a slew of other statistics. Extensions to RTCP also allow for it to be used for protocol-specific controls to the stream, such as indicating to a sender to send a full frame of video.
The point here is that there are two separate streams of data involved in a typical RTP session: the RTP and the RTCP. Traditionally, when an endpoint makes use of RTP, that endpoint opens a UDP port to receive RTP traffic and a separate UDP port to receive RTCP traffic. In other words, demultiplexing of the traffic types is performed at the transport layer. Simply by knowing the port that traffic is coming in on, you know what type of packet you are receiving.
RFC 5761 defines a new way of doing things. Rather than using separate UDP ports for each, RTP and RTCP are received on the same port. This offers some advantages over the old method:
- It simplifies NAT traversal since only a single port is used for media and control messages.
- You can theoretically double the amount of media sessions on your system with the same number of UDP ports.
- Gathering of ICE candidates and SDP signaling for ICE becomes *much* simpler. You only need one set of candidates instead of two.
- When combined with BUNDLE, *all* media sessions use the same port, simplifying transport usage and NAT traversal even further.
rtcp-mux in Google Chrome
Google Chrome has had rtcp-mux capabilities for several years. Juan de Bravo, a Chrome developer, recently published a blog post detailing the chrome team’s perspective on rtcp-mux. In addition, Chrome and Asterisk guru Dan Jenkins wrote a blog post that details the Chrome changes, how they affect Asterisk, and how you can work around them if necessary. rtcp-mux operates in one of two modes:
- negotiate: In this mode, Chrome will try to use rtcp-mux but can fall back to traditional mode if the remote end does not support rtcp-mux.
- require: In this mode, Chrome will negotiate in such a way that if rtcp-mux is not supported by the remote end, then the call setup fails.
Prior to the release of Chrome 57, Chrome operated in “negotiate” mode. This means that when placing calls to Asterisk, Chrome would fall back to using traditional RTCP since Asterisk did not support rtcp-mux. Starting with Chrome 57, they switched to “require” mode. Their reasoning for doing so was two-fold:
- rtcp-mux is used by the vast majority of their WebRTC traffic.
- A forthcoming standard mandates that “require” behavior is used.
With this switchover, calls from Chrome to Asterisk started failing.
You can get around this issue by setting the rtcpMuxPolicy flag on your RTCPeerConnections in Chrome to be “negotiate” instead of “require”. Dan’s blog post that I linked earlier goes into more detail about how you can do this with specific WebRTC SIP clients. Rumor has it that the Chrome team are eventually going to remove this flag altogether and force the “require” behavior in a future release of Chrome.
rtcp-mux in Asterisk
To get around this problem, the Asterisk team decided to add support for rtcp-mux into Asterisk before it became too late. I added support for rtcp-mux for chan_pjsip, and Sean Bright added rtcp-mux for chan_sip. The feature is available starting in Asterisk 13.15.0 and Asterisk 14.4.0. For those of you still on older versions, you may want to start upgrading soon if you plan to interoperate with Chrome.
For chan_pjsip, you can enable rtcp-mux on an endpoint by setting rtcp_mux=yes
For chan_sip, you can enable rtcp-mux by setting rtcp_mux=yes on a peer, user or friend. You also have the option of setting rtcp_mux=yes in the general section to apply it globally.