Asterisk RTCP

Before patch 10590 (which was applied to Asterisk 1.6) the RTCP data presented in Asterisk 1.4 were basically useless: For example packet loss values could be 10x higher than the number of total received packets, and only one of the two calls legs was being watched.

See Patch 10590 (updated and committed in June 2008)
"rtpqos-14-r119891.diff" is meant for Asterisk 1.4 and does also apply to Asterisk 1.4.30 after minimal manual intervention. Since Asterisk 1.4 does not receive new features this has not made it into subsequent 1.4 realeases.
Note: Packet2Packet bridging (aka p2p) will completely mess up the RTCP stats with this patch with up to wrongly reported 100% packet loss! So either make sure that p2p bridging does not occur (by using a force-enabled jitter buffer or by making sure transcoding is done), or disable the p2p code in rtp.c (which is really simple to do).

In Asterisk 1.6 the RTCP data are now provided with the help of the CHANNEL function.

Useful CLI commands

rtcp stats
sip show channelstats (Asterisk 1.6)
rtcp debug <ip>

Quality rules

  • Packet loss < 1% (preferably 0.5%); with a packet loss of > 3% call quality will degrade audibly, at > 6% quality turns bad, and above 10% a call becomes entirely unacceptable.
  • Delay/Latency < 150 ms (one way); to much delay can aslo affect/kill echo cancellation (think satellite link with 500-700 ms delay)
  • RTT/Round Trip Time < 200-250 ms (RTT = delays of both directions added)
  • Jitter < 30 ms. The meaning of the jitter value depends greatly on the jitter buffers involved. Jitter affects the packet loss
  • "Bursts" of consecutively lost packets are bad bad bad (aka "drop out")
  • codecs: Some codecs (g729, iLBC) are better at concealing a lost packets than others (g711), keyword "PLC": Packet Loss Concealment
  • TOS/QoS/DiffServ settings can help to prioritize VoIP traffic on that part of the network you have control over


  • Is it mandatory to have a proper NTP time setup to issue (and correctly honor received) RTCP reports? A: No, but it helps.
  • What are the dimensions of the reported values - typically they are in seconds, however "reported jitter" appears to be shown in milliseconds?
  • Is there a way to match a SSRC to a SIP UA, a call leg or call's unique ID? No, not easily, the SSRCs change often.


RTCP: RTP Control protocol
SSRC: Synchronization Source
SR: Sender Report (issued by sites that also sent data in the past interval)
RR: Receiver Report (issued by sites that only received data)
RTT: Round Trip Time (how long does it take to the other side and then back to us = both delays/latencies added)
QOS: Quality of Service
rx: Receive
tx: Transmit (send)
Transit: Relative transit time for previous packet
DLSR (and LSR) allow a sender to calculate the round trip time of RTCP reports. (minus the internal delay on the remote side)
avg: average
stdev: standard deviation (statistics)


Example 1: CLI statistics of an unpatched Asterisk 1.4:

Note: There are two call legs with each a "sender" and a "receiver"

  • Our Receiver:
SSRC: 1562797448
Received packets: 851
Lost packets: 0
Jitter: 0.0032
Transit: -0.0041
RR-count: 0

  • Our Sender:
SSRC: 1172311862
Sent packets: 798
Lost packets: 0
Jitter: 0
SR-count: 3
RTT: 0.026000

Example 2: CLI output of "rtcp debug ip aa.bbb.cc.ddd" on a patched Asterisk 1.4

Got RTCP from aa.bbb.cc.ddd:55397
PT: 200(Sender Report)
Reception reports: 1
SSRC of sender: 2186108039
NTP timestamp: 3484999682.2060017664
RTP timestamp: 61854128
SPC: 451 SOC: 144320
Fraction lost: 0
Packets lost so far: 0
Highest sequence number: 55871
Sequence number cycles: 0
Interarrival jitter: 156
Last SR(our NTP): 57342.2415919104
DLSR: 4.8380 (sec)
RTT: 57(sec)

Got RTCP from aa.bbb.cc.ddd:55397
PT: 202(Unknown)
Reception reports: 1
SSRC of sender: 2186108039
Received an SDES from aa.bbb.cc.ddd:55397
  • Sent RTCP SR to aa.bbb.cc.ddd:55397
Our SSRC: 1955422078
Sent(NTP): 1276010883.0381779968
Sent(RTP): 87560
Sent packets: 264
Sent octets: 42240
Report block:
Fraction lost: 0
Cumulative loss: 0
IA jitter: 0.0006
Their last SR: 3758290055
DLSR: 0.1050 (sec)

Example 3: Channel variables provided by patch 10590


Note: If the other side does not support RTCP/ does not provide RTCP data then the variable may carry less data in a different order!




Example 4: Sample dialplan to store RTCP data in the CDR field "userfield"

Call this macro from within the h extension. Make sure to have endbeforehexten=no in cdr.conf (which is the default value).

Tip: Use the M option of Dial() if you would like to get the codec (audionativeformat) of the remote call leg/channel and similar data. Those are not available anymore during the hangup phase (h extension), however you can store them directly in the CDR system, or use the SHARED function to export them to the local call leg/channel.

exten => s,1,GotoIf($[$["${CHANNEL(channeltype)}" != "SIP"] | $["${DIALSTATUS}" = ""]]?continue)

; - These RTCP stats provided by CHANNEL(rtpqos) apparently only show data for the last RTCP message we got!
exten => s,n,NoOp(-- QoS stats
${CHANNEL(rtpqos,audio,all)}) ; causes a warning for non-SIP channels
exten => s,n,NoOp(-- QoS stats RTPAUDIOQOS: ${RTPAUDIOQOS}) ; same as CHANNEL(rtpqos,audio,all)

; - See bug/patch #10590 for these TOTAL values that cover the ENTIRE call
; - Obtain the stats for the first (=original =local) channel i.e. the caller
exten => s,n,NoOp(-- QoS stats RTPAUDIOQOSRTT: ${RTPAUDIOQOSRTT})

; - The BRIDGED channel is the outbound (=new =2nd =callee =remote) channel established by Dial()
; - It normally has a lower packet count because it connected later (if both legs use 20 ms packets)

; - Preparing data for storage -
exten => s,n,NoOp(-- BRIDGED packet loss: ${CUT(RTPAUDIOQOSLOSSBRIDGED,\;,1):5} lost of ${CUT(RTPAUDIOQOSLOSSBRIDGED,\;,2):9} in total --)
; - The jitter we measured ourselves - we might also be interested in the maximum jitter
exten => s,n,Set(RTT_LOCAL_AVG=${CUT(RTPAUDIOQOSRTT,\;,3):7})

exten => s,n,Set(FORMAT_NATIVE=${CHANNEL(audionativeformat)})
exten => s,n,GotoIf($["${HANGUPCAUSE}" != "16"]?continue) ; only store the data if this was a normal call

- Quality rules
Packet loss should be below 0.5% and jitter < 5 ms, and rtt (measurement for latency) < 200 ms or less
; - Watch out! The 'userfield' is only 255 characters long in the table 'cdr' on MySQL!
exten => s,n,Set(LOST_LOCAL_TOT=${MATH(${CUT(RTPAUDIOQOSLOSS,\;,1):5} / ${CUT(RTPAUDIOQOSLOSS,\;,2):9},float)})
- The jitter reported by other end - watch out
Might be measured in milliseconds and not seconds!
exten => s,n,Set(JITTER_REP_LOCAL_AVG=${MATH(${CUT(RTPAUDIOQOSJITTER,\;,7):19} / 1000)})
exten => s,n,Set(CDR(userfield)=${CDR(userfield)}&lost_remote:${LOST_REMOTE_TOT}&lost_local:${LOST_LOCAL_TOT}&format_native=${FORMAT_NATIVE})
exten => s,n,Set(CDR(userfield)=${CDR(userfield)}&jitter_remote:${JITTER_RX_REMOTE_AVG}&jitter_local:${JITTER_RX_LOCAL_AVG})
exten => s,n,Set(CDR(userfield)=${CDR(userfield)}&jitter_rep_remote:${JITTER_REP_REMOTE_AVG}&jitter_rep_local:${JITTER_REP_LOCAL_AVG})
exten => s,n,Set(CDR(userfield)=${CDR(userfield)}&rtt_remote:${RTT_REMOTE_AVG}&rtt_local:${RTT_LOCAL_AVG})

; - And here is how to do it with the old unreliable data provided by an unpatched Asterisk 1.4
exten => s,n,Set(LOST_REMOTE=${MATH(${CHANNEL(rtpqos,audio,remote_lostpackets)} / ${CHANNEL(rtpqos,audio,remote_count)},float)})
exten => s,n,Set(LOST_LOCAL=${MATH(${CHANNEL(rtpqos,audio,local_lostpackets)} / ${CHANNEL(rtpqos,audio,local_count)},float)})
exten => s,n,Set(JITTER_REMOTE=${CHANNEL(rtpqos,audio,remote_jitter)})
exten => s,n,Set(JITTER_LOCAL=${CHANNEL(rtpqos,audio,local_jitter)})
exten => s,n,Set(CDR(userfield)=${CDR(userfield)}&lost_remote
exten => s,n,Set(CDR(userfield)=${CDR(userfield)}&jitter_remote

exten => s,n(continue),NoOp(do something else)

Background info

Jan 2010: RTCP is also affected by NAT, the same way as RTP and SIP. So if there's too much time between each RTCP report, NAT relationships will be forgotten and RTCP packets lost.
One way to avoid this problem is to use RTP/RTCP multiplexing as defined in RFC5761 (tba or draft-ietf-avt-rtp-and-rtcp-mux-07). I guess that if asterisk were to support this it may require some minor enhancements.

From the field

Olle in Nov 2009:
"I want to add support for RTCP SDES and BYE. When we get a BYE, we should produce a final report that summarizes the 'call'. I also want to try to aggregate some stats on peer level, so we can see stats for a particular 'trunk' or device in regards of packet loss and jitter for the last <configurable> amount of calls.

The RTCP SDES name is a tag for the RTP session, since the SSRC might change. This will help us to separate RTCP when we reinvite and transfer calls. One "call" might have multiple SDES sessions and multiple SSRCs. I haven't got a clear plan on how to handle this. If an outbound call has a first media session with one device, then suddenly gets reinvited to another device, we need to see this as two media sessions with different RTCP stats. Well, let's start with being able to separate them and see what happens next."

Olle in Jan 2010:
"I've just created a combined test branch for work on RTCP that I would appreciate your feedback on.

Test branch for patches hidden in several branches - all based on Asterisk 1.4
  • RTCP improvements from pinefrog-1.4
  • "Sip show chanstats" cli command
  • pinequality-* giving you the manager "sipchannel" event to check QoS

This branch is now open for testing and I need feedback. Among the improvements
  • Manager QoS events during a call and after a call
  • Improved RTCP - rtcp now works for p2p bridge in RTP, which means that we will get RTCP for many, many more sip calls
  • RTCP over NAT improvements - if Asterisk is behind NAT, we will now kick-start RTCP from the remote end by sending a first emtpy RTCP packet to open a NAT port.
  • QoS reports to realtime storage after each call - one report per call leg (The amount of data and the names will change)

The reason that I store QoS data in realtime, is that the CDR is usually gone or frozen at the time that we freeze the RTP channels and get the last QoS data. The QoS reports can't thus be included in CDR, you have to merge it in automatically later in your database.

There's still a lot to do, but please test it so I get some sort of feedback.

For testing, don't forget to run the "rtcp debug" cli command so you can see what's going on in the RTCP channel.

Yes, this work will be ported to trunk and hopefully merged soon.
No, I have no reason or funding to adapt it to 1.6.x at this point.
No, the RTPAUDIOQOS is not changed at all. YOu might get more data now though."

Taken from: http://lists.digium.com/pipermail/asterisk-dev/2010-January/041829.html (Jan 2010)

"During my adventures in RTCP I've discovered that it's not only Asterisk that has been paying too little attention to RTCP...

Grandstream GXV3140 doesn't send any RTCP reports during a five minute call. And it's a video phone. Video really needs RTCP. I *hope* there's a setting somewhere that I've missed.

Polycom Soundpoint IP600 - propably with old firmware - sends NTP timestamps that Wireshark tells me are dated Feb 7, 2036. This means that we have many years of roundtrip time, measured in millisecs. For a phone connected to the same switch as my Asterisk server, that's a huge latency. I guess they need a bit more of CPU power for that device. :-) (or it's me that needs help to upgrade my phone to a version where they've fixed this bug).

SNOM 370 sends a timestamp that's all zeroes, so we can't measure RTT.

Cisco/Linksys sends a valid timestamp and Asterisk measures RTT properly.

Many phones only send RTCP at regular intervals. If this interval is longer than the call, we'll get no report at all from the other side and can't get any idea about QoS for the outbound stream. It should really be a requirement to send a final report at hangup time for every call.

RTCP is also affected by NAT, the same way as RTP and SIP. So if there's too much time between each RTCP report, NAT relationships will be forgotten and RTCP packets lost. There should be a setting for the RTCP timer, so you can make sure that NAT is kept open. Asterisk has that and in my "pinefrog-1.4" version also sends a packet to open up the NAT when media starts.

We need to get the industry to shape up here and treat RTCP seriously. It will become even more important with new codecs that use the stats from RTCP to adapt to current network conditions. If you buy a lot of phones from a vendor, require proper RTCP support in the bid. I'll try to update a blacklist document in my svn branch. So far, CounterPath Eyebeam is the winner - final report sent together with the GoodBye packet. Cisco SPA is the second on the list, even though I get no final report from that phone.

Please keep testing my test branch "pinefrog-deluxe-rtcp-test" and provide me with feedback!


See also

Created by: JustRumours, Last modification: Sun 06 of Jan, 2013 (11:37 UTC)
Please update this page with new information, just login and click on the "Edit" or "Discussion" tab. Get a free login here: Register Thanks! - Find us on Google+