summaryrefslogtreecommitdiff
path: root/res/res_rtp_asterisk.c
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2013-07-05 17:33:33 +0000
committerMatthew Jordan <mjordan@digium.com>2013-07-05 17:33:33 +0000
commitd0a55fa52dcc29f2db3e22549c9c2f2e68cada56 (patch)
treeb3d339dcfa5611a7be0e12b99131d21d206719a3 /res/res_rtp_asterisk.c
parentd789681eaff813affe6f88f33813aebcc99d8b6a (diff)
Refactor RTCP events over to Stasis; associate with channels
This patch does the following: * It merges Jaco Kroon's patch from ASTERISK-20754, which provides channel information in the RTCP events. Because Stasis provides a cache, Jaco's patch was modified to pass the channel uniqueid to the RTP layer as opposed to a pointer to the channel. This has the following benefits: (1) It keeps the RTP engine 'clean' of references back to channels (2) It prevents circular dependencies and other potential ref counting issues * The RTP engine now allows any RTP implementation to raise RTCP messages. Potentially, other implementations (such as res_rtp_multicast) could also raise RTCP information. The engine provides structs to represent RTCP headers and RTCP SR/RR reports. * Some general refactoring in res_rtp_asterisk was done to try and tame the RTCP code. It isn't perfect - that's *way* beyond the scope of this work - but it does feel marginally better. * A few random bugs were fixed in the RTCP statistics. (Example: performing an assignment of a = a is probably not correct) * We now raise RTCP events for each SR/RR sent/received. Previously we wouldn't raise an event when we sent a RR report. Note that this work will be of use to others who want to monitor call quality or build modules that report call quality statistics. Since the events are now moving across the Stasis message bus, this is far easier to accomplish. It is also a first step (though by no means the last step) towards getting Olle's pinefrog work incorporated. Again: note that the patch by Jaco Kroon was modified slightly for this work; however, he did all of the hard work in finding the right places to set the channel in the RTP engine across the channel drivers. Much thanks goes to Jaco for his hard work here. Review: https://reviewboard.asterisk.org/r/2603/ (closes issue ASTERISK-20574) Reported by: Jaco Kroon patches: asterisk-rtcp-channel.patch uploaded by jkroon (License 5671) (closes issue ASTERISK-21471) Reported by: Matt Jordan git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393740 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/res_rtp_asterisk.c')
-rw-r--r--res/res_rtp_asterisk.c675
1 files changed, 322 insertions, 353 deletions
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 3f19dbdeb..efe5b967e 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -85,8 +85,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define TURN_ALLOCATION_WAIT_TIME 2000
#define RTCP_PT_FUR 192
-#define RTCP_PT_SR 200
-#define RTCP_PT_RR 201
+#define RTCP_PT_SR AST_RTP_RTCP_SR
+#define RTCP_PT_RR AST_RTP_RTCP_RR
#define RTCP_PT_SDES 202
#define RTCP_PT_BYE 203
#define RTCP_PT_APP 204
@@ -2182,52 +2182,46 @@ static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw)
*lsw = frac;
}
-/*! \brief Send RTCP recipient's report */
-static int ast_rtcp_write_rr(struct ast_rtp_instance *instance)
+static void ntp2timeval(unsigned int msw, unsigned int lsw, struct timeval *tv)
{
- struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
- int res;
- int len = 32;
- unsigned int lost;
- unsigned int extended;
- unsigned int expected;
+ tv->tv_sec = msw - 2208988800u;
+ tv->tv_usec = ((lsw << 6) / 3650) - (lsw >> 12) - (lsw >> 8);
+}
+
+static void calculate_lost_packet_statistics(struct ast_rtp *rtp,
+ unsigned int *lost_packets,
+ int *fraction_lost)
+{
+ unsigned int extended_seq_no;
+ unsigned int expected_packets;
unsigned int expected_interval;
unsigned int received_interval;
- int lost_interval;
- struct timeval now;
- unsigned int *rtcpheader;
- char bdata[1024];
- struct timeval dlsr;
- int fraction;
- int rate = rtp_get_rate(&rtp->f.subclass.format);
- int ice;
double rxlost_current;
- struct ast_sockaddr remote_address = { {0,} };
+ int lost_interval;
- if (!rtp || !rtp->rtcp) {
- return 0;
+ /* Compute statistics */
+ extended_seq_no = rtp->cycles + rtp->lastrxseqno;
+ expected_packets = extended_seq_no - rtp->seedrxseqno + 1;
+ if (rtp->rxcount > expected_packets) {
+ expected_packets += rtp->rxcount - expected_packets;
}
-
- if (ast_sockaddr_isnull(&rtp->rtcp->them)) {
- /*
- * RTCP was stopped.
- */
- return 0;
- }
-
- extended = rtp->cycles + rtp->lastrxseqno;
- expected = extended - rtp->seedrxseqno + 1;
- lost = expected - rtp->rxcount;
- expected_interval = expected - rtp->rtcp->expected_prior;
- rtp->rtcp->expected_prior = expected;
+ *lost_packets = expected_packets - rtp->rxcount;
+ expected_interval = expected_packets - rtp->rtcp->expected_prior;
received_interval = rtp->rxcount - rtp->rtcp->received_prior;
- rtp->rtcp->received_prior = rtp->rxcount;
lost_interval = expected_interval - received_interval;
+ if (expected_interval == 0 || lost_interval <= 0) {
+ *fraction_lost = 0;
+ } else {
+ *fraction_lost = (lost_interval << 8) / expected_interval;
+ }
+ /* Update RTCP statistics */
+ rtp->rtcp->received_prior = rtp->rxcount;
+ rtp->rtcp->expected_prior = expected_packets;
if (lost_interval <= 0) {
rtp->rtcp->rxlost = 0;
} else {
- rtp->rtcp->rxlost = rtp->rtcp->rxlost;
+ rtp->rtcp->rxlost = lost_interval;
}
if (rtp->rtcp->rxlost_count == 0) {
rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
@@ -2238,200 +2232,162 @@ static int ast_rtcp_write_rr(struct ast_rtp_instance *instance)
if (lost_interval > rtp->rtcp->maxrxlost) {
rtp->rtcp->maxrxlost = rtp->rtcp->rxlost;
}
-
- rxlost_current = normdev_compute(rtp->rtcp->normdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->rxlost_count);
- rtp->rtcp->stdev_rxlost = stddev_compute(rtp->rtcp->stdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->normdev_rxlost, rxlost_current, rtp->rtcp->rxlost_count);
+ rxlost_current = normdev_compute(rtp->rtcp->normdev_rxlost,
+ rtp->rtcp->rxlost,
+ rtp->rtcp->rxlost_count);
+ rtp->rtcp->stdev_rxlost = stddev_compute(rtp->rtcp->stdev_rxlost,
+ rtp->rtcp->rxlost,
+ rtp->rtcp->normdev_rxlost,
+ rxlost_current,
+ rtp->rtcp->rxlost_count);
rtp->rtcp->normdev_rxlost = rxlost_current;
rtp->rtcp->rxlost_count++;
-
- if (expected_interval == 0 || lost_interval <= 0) {
- fraction = 0;
- } else {
- fraction = (lost_interval << 8) / expected_interval;
- }
- gettimeofday(&now, NULL);
- timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
- rtcpheader = (unsigned int *)bdata;
- rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_RR << 16) | ((len/4)-1));
- rtcpheader[1] = htonl(rtp->ssrc);
- rtcpheader[2] = htonl(rtp->themssrc);
- rtcpheader[3] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
- rtcpheader[4] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
- rtcpheader[5] = htonl((unsigned int)(rtp->rxjitter * rate));
- rtcpheader[6] = htonl(rtp->rtcp->themrxlsr);
- rtcpheader[7] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
-
- /*! \note Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos
- it can change mid call, and SDES can't) */
- rtcpheader[len/4] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
- rtcpheader[(len/4)+1] = htonl(rtp->ssrc); /* Our SSRC */
- rtcpheader[(len/4)+2] = htonl(0x01 << 24); /* Empty for the moment */
- len += 12;
-
- ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
-
- res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &remote_address, &ice);
-
- if (res < 0) {
- ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted: %s\n",strerror(errno));
- return 0;
- }
-
- rtp->rtcp->rr_count++;
-
- update_address_with_ice_candidate(rtp, COMPONENT_RTCP, &remote_address);
-
- if (rtcp_debug_test_addr(&remote_address)) {
- ast_verbose("\n* Sending RTCP RR to %s%s\n"
- " Our SSRC: %u\nTheir SSRC: %u\niFraction lost: %d\nCumulative loss: %u\n"
- " IA jitter: %.4f\n"
- " Their last SR: %u\n"
- " DLSR: %4.4f (sec)\n\n",
- ast_sockaddr_stringify(&remote_address),
- ice ? " (via ICE)" : "",
- rtp->ssrc, rtp->themssrc, fraction, lost,
- rtp->rxjitter,
- rtp->rtcp->themrxlsr,
- (double)(ntohl(rtcpheader[7])/65536.0));
- }
-
- return res;
}
-/*! \brief Send RTCP sender's report */
-static int ast_rtcp_write_sr(struct ast_rtp_instance *instance)
+/*! \brief Send RTCP SR or RR report */
+static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+ RAII_VAR(struct ast_json *, message_blob, NULL, ast_json_unref);
int res;
int len = 0;
struct timeval now;
unsigned int now_lsw;
unsigned int now_msw;
unsigned int *rtcpheader;
- unsigned int lost;
- unsigned int extended;
- unsigned int expected;
- unsigned int expected_interval;
- unsigned int received_interval;
- int lost_interval;
- int fraction;
- struct timeval dlsr;
+ unsigned int lost_packets;
+ int fraction_lost;
+ struct timeval dlsr = { 0, };
char bdata[512];
int rate = rtp_get_rate(&rtp->f.subclass.format);
int ice;
+ int header_offset = 0;
struct ast_sockaddr remote_address = { {0,} };
+ struct ast_rtp_rtcp_report_block *report_block;
+ RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report,
+ ast_rtp_rtcp_report_alloc(1),
+ ao2_cleanup);
if (!rtp || !rtp->rtcp) {
return 0;
}
if (ast_sockaddr_isnull(&rtp->rtcp->them)) { /* This'll stop rtcp for this rtp session */
- /*
- * RTCP was stopped.
- */
+ /* RTCP was stopped. */
return 0;
}
+ if (!rtcp_report) {
+ return 1;
+ }
+
+ report_block = ast_calloc(1, sizeof(*report_block));
+ if (!report_block) {
+ return 1;
+ }
+
+ /* Compute statistics */
+ calculate_lost_packet_statistics(rtp, &lost_packets, &fraction_lost);
+
gettimeofday(&now, NULL);
- timeval2ntp(now, &now_msw, &now_lsw); /* fill thses ones in from utils.c*/
+ rtcp_report->reception_report_count = 1;
+ rtcp_report->ssrc = rtp->ssrc;
+ rtcp_report->type = sr ? RTCP_PT_SR : RTCP_PT_RR;
+ if (sr) {
+ rtcp_report->sender_information.ntp_timestamp = now;
+ rtcp_report->sender_information.rtp_timestamp = rtp->lastts;
+ rtcp_report->sender_information.packet_count = rtp->txcount;
+ rtcp_report->sender_information.octet_count = rtp->txoctetcount;
+ }
+ rtcp_report->report_block[0] = report_block;
+ report_block->source_ssrc = rtp->themssrc;
+ report_block->lost_count.fraction = (fraction_lost & 0xff);
+ report_block->lost_count.packets = (lost_packets & 0xffffff);
+ report_block->highest_seq_no = (rtp->cycles | (rtp->lastrxseqno & 0xffff));
+ report_block->ia_jitter = (unsigned int)(rtp->rxjitter * rate);
+ report_block->lsr = rtp->rtcp->themrxlsr;
+ /* If we haven't received an SR report, DLSR should be 0 */
+ if (!ast_tvzero(rtp->rtcp->rxlsr)) {
+ timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
+ report_block->dlsr = (((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000;
+ }
+ timeval2ntp(rtcp_report->sender_information.ntp_timestamp, &now_msw, &now_lsw);
rtcpheader = (unsigned int *)bdata;
- rtcpheader[1] = htonl(rtp->ssrc); /* Our SSRC */
- rtcpheader[2] = htonl(now_msw); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/
- rtcpheader[3] = htonl(now_lsw); /* now, LSW */
- rtcpheader[4] = htonl(rtp->lastts); /* FIXME shouldn't be that, it should be now */
- rtcpheader[5] = htonl(rtp->txcount); /* No. packets sent */
- rtcpheader[6] = htonl(rtp->txoctetcount); /* No. bytes sent */
- len += 28;
-
- extended = rtp->cycles + rtp->lastrxseqno;
- expected = extended - rtp->seedrxseqno + 1;
- if (rtp->rxcount > expected) {
- expected += rtp->rxcount - expected;
- }
- lost = expected - rtp->rxcount;
- expected_interval = expected - rtp->rtcp->expected_prior;
- rtp->rtcp->expected_prior = expected;
- received_interval = rtp->rxcount - rtp->rtcp->received_prior;
- rtp->rtcp->received_prior = rtp->rxcount;
- lost_interval = expected_interval - received_interval;
- if (expected_interval == 0 || lost_interval <= 0) {
- fraction = 0;
- } else {
- fraction = (lost_interval << 8) / expected_interval;
- }
- timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
- rtcpheader[7] = htonl(rtp->themssrc);
- rtcpheader[8] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
- rtcpheader[9] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
- rtcpheader[10] = htonl((unsigned int)(rtp->rxjitter * rate));
- rtcpheader[11] = htonl(rtp->rtcp->themrxlsr);
- rtcpheader[12] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
+ rtcpheader[1] = htonl(rtcp_report->ssrc); /* Our SSRC */
+ len += 8;
+ if (sr) {
+ header_offset = 5;
+ rtcpheader[2] = htonl(now_msw); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/
+ rtcpheader[3] = htonl(now_lsw); /* now, LSW */
+ rtcpheader[4] = htonl(rtcp_report->sender_information.rtp_timestamp);
+ rtcpheader[5] = htonl(rtcp_report->sender_information.packet_count);
+ rtcpheader[6] = htonl(rtcp_report->sender_information.octet_count);
+ len += 20;
+ }
+ rtcpheader[2 + header_offset] = htonl(report_block->source_ssrc); /* Their SSRC */
+ rtcpheader[3 + header_offset] = htonl((report_block->lost_count.fraction << 24) | report_block->lost_count.packets);
+ rtcpheader[4 + header_offset] = htonl(report_block->highest_seq_no);
+ rtcpheader[5 + header_offset] = htonl(report_block->ia_jitter);
+ rtcpheader[6 + header_offset] = htonl(report_block->lsr);
+ rtcpheader[7 + header_offset] = htonl(report_block->dlsr);
len += 24;
-
- rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SR << 16) | ((len/4)-1));
+ rtcpheader[0] = htonl((2 << 30) | (1 << 24) | ((sr ? RTCP_PT_SR : RTCP_PT_RR) << 16) | ((len/4)-1));
/* Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos */
/* it can change mid call, and SDES can't) */
rtcpheader[len/4] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | 2);
- rtcpheader[(len/4)+1] = htonl(rtp->ssrc); /* Our SSRC */
- rtcpheader[(len/4)+2] = htonl(0x01 << 24); /* Empty for the moment */
+ rtcpheader[(len/4)+1] = htonl(rtcp_report->ssrc);
+ rtcpheader[(len/4)+2] = htonl(0x01 << 24);
len += 12;
ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
-
res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &remote_address, &ice);
if (res < 0) {
- ast_log(LOG_ERROR, "RTCP SR transmission error to %s, rtcp halted %s\n",
+ ast_log(LOG_ERROR, "RTCP %s transmission error to %s, rtcp halted %s\n",
+ sr ? "SR" : "RR",
ast_sockaddr_stringify(&rtp->rtcp->them),
strerror(errno));
return 0;
}
- /* FIXME Don't need to get a new one */
- gettimeofday(&rtp->rtcp->txlsr, NULL);
- rtp->rtcp->sr_count++;
-
- rtp->rtcp->lastsrtxcount = rtp->txcount;
+ /* Update RTCP SR/RR statistics */
+ if (sr) {
+ rtp->rtcp->txlsr = rtcp_report->sender_information.ntp_timestamp;
+ rtp->rtcp->sr_count++;
+ rtp->rtcp->lastsrtxcount = rtp->txcount;
+ } else {
+ rtp->rtcp->rr_count++;
+ }
update_address_with_ice_candidate(rtp, COMPONENT_RTCP, &remote_address);
if (rtcp_debug_test_addr(&rtp->rtcp->them)) {
- ast_verbose("* Sent RTCP SR to %s%s\n", ast_sockaddr_stringify(&remote_address), ice ? " (via ICE)" : "");
- ast_verbose(" Our SSRC: %u\n", rtp->ssrc);
- ast_verbose(" Sent(NTP): %u.%010u\n", (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096);
- ast_verbose(" Sent(RTP): %u\n", rtp->lastts);
- ast_verbose(" Sent packets: %u\n", rtp->txcount);
- ast_verbose(" Sent octets: %u\n", rtp->txoctetcount);
+ ast_verbose("* Sent RTCP %s to %s%s\n", sr ? "SR" : "RR",
+ ast_sockaddr_stringify(&remote_address), ice ? " (via ICE)" : "");
+ ast_verbose(" Our SSRC: %u\n", rtcp_report->ssrc);
+ if (sr) {
+ ast_verbose(" Sent(NTP): %u.%010u\n",
+ (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
+ (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096);
+ ast_verbose(" Sent(RTP): %u\n", rtcp_report->sender_information.rtp_timestamp);
+ ast_verbose(" Sent packets: %u\n", rtcp_report->sender_information.packet_count);
+ ast_verbose(" Sent octets: %u\n", rtcp_report->sender_information.octet_count);
+ }
ast_verbose(" Report block:\n");
- ast_verbose(" Fraction lost: %u\n", fraction);
- ast_verbose(" Cumulative loss: %u\n", lost);
- ast_verbose(" IA jitter: %.4f\n", rtp->rxjitter);
- ast_verbose(" Their last SR: %u\n", rtp->rtcp->themrxlsr);
- ast_verbose(" DLSR: %4.4f (sec)\n\n", (double)(ntohl(rtcpheader[12])/65536.0));
- }
- manager_event(EVENT_FLAG_REPORTING, "RTCPSent", "To: %s\r\n"
- "OurSSRC: %u\r\n"
- "SentNTP: %u.%010u\r\n"
- "SentRTP: %u\r\n"
- "SentPackets: %u\r\n"
- "SentOctets: %u\r\n"
- "ReportBlock:\r\n"
- "FractionLost: %u\r\n"
- "CumulativeLoss: %u\r\n"
- "IAJitter: %.4f\r\n"
- "TheirLastSR: %u\r\n"
- "DLSR: %4.4f (sec)\r\n",
- ast_sockaddr_stringify(&remote_address),
- rtp->ssrc,
- (unsigned int)now.tv_sec, (unsigned int)now.tv_usec*4096,
- rtp->lastts,
- rtp->txcount,
- rtp->txoctetcount,
- fraction,
- lost,
- rtp->rxjitter,
- rtp->rtcp->themrxlsr,
- (double)(ntohl(rtcpheader[12])/65536.0));
+ ast_verbose(" Their SSRC: %u\n", report_block->source_ssrc);
+ ast_verbose(" Fraction lost: %u\n", report_block->lost_count.fraction);
+ ast_verbose(" Cumulative loss: %u\n", report_block->lost_count.packets);
+ ast_verbose(" Highest seq no: %u\n", report_block->highest_seq_no);
+ ast_verbose(" IA jitter: %.4f\n", (double)report_block->ia_jitter / rate);
+ ast_verbose(" Their last SR: %u\n", report_block->lsr);
+ ast_verbose(" DLSR: %4.4f (sec)\n\n", (double)(report_block->dlsr / 65536.0));
+ }
+
+ message_blob = ast_json_pack("{s: s}",
+ "to", ast_sockaddr_stringify(&remote_address));
+ ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_sent_type(),
+ rtcp_report,
+ message_blob);
return res;
}
@@ -2450,9 +2406,11 @@ static int ast_rtcp_write(const void *data)
}
if (rtp->txcount > rtp->rtcp->lastsrtxcount) {
- res = ast_rtcp_write_sr(instance);
+ /* Send an SR */
+ res = ast_rtcp_write_report(instance, 1);
} else {
- res = ast_rtcp_write_rr(instance);
+ /* Send an RR */
+ res = ast_rtcp_write_report(instance, 0);
}
if (!res) {
@@ -2791,7 +2749,6 @@ static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int t
d=-d;
}
rtp->rxjitter += (1./16.) * (d - rtp->rxjitter);
-
if (rtp->rtcp) {
if (rtp->rxjitter > rtp->rtcp->maxrxjitter)
rtp->rtcp->maxrxjitter = rtp->rxjitter;
@@ -3100,6 +3057,98 @@ static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, u
return &rtp->f;
}
+static int update_rtt_stats(struct ast_rtp *rtp, unsigned int lsr, unsigned int dlsr)
+{
+ struct timeval now;
+ struct timeval rtt_tv;
+ unsigned int msw;
+ unsigned int lsw;
+ unsigned int rtt_msw;
+ unsigned int rtt_lsw;
+ unsigned int lsr_a;
+ unsigned int rtt;
+ double normdevrtt_current;
+
+ gettimeofday(&now, NULL);
+ timeval2ntp(now, &msw, &lsw);
+
+ lsr_a = ((msw & 0x0000ffff) << 16) | ((lsw & 0xffff0000) >> 16);
+ rtt = lsr_a - lsr - dlsr;
+ rtt_msw = (rtt & 0xffff0000) >> 16;
+ rtt_lsw = (rtt & 0x0000ffff) << 16;
+ rtt_tv.tv_sec = rtt_msw;
+ rtt_tv.tv_usec = ((rtt_lsw << 6) / 3650) - (rtt_lsw >> 12) - (rtt_lsw >> 8);
+ rtp->rtcp->rtt = (double)rtt_tv.tv_sec + ((double)rtt_tv.tv_usec / 1000000);
+ if (lsr_a - dlsr < lsr) {
+ return 1;
+ }
+
+ rtp->rtcp->accumulated_transit += rtp->rtcp->rtt;
+ if (rtp->rtcp->rtt_count == 0 || rtp->rtcp->minrtt > rtp->rtcp->rtt) {
+ rtp->rtcp->minrtt = rtp->rtcp->rtt;
+ }
+ if (rtp->rtcp->maxrtt < rtp->rtcp->rtt) {
+ rtp->rtcp->maxrtt = rtp->rtcp->rtt;
+ }
+
+ normdevrtt_current = normdev_compute(rtp->rtcp->normdevrtt,
+ rtp->rtcp->rtt,
+ rtp->rtcp->rtt_count);
+ rtp->rtcp->stdevrtt = stddev_compute(rtp->rtcp->stdevrtt,
+ rtp->rtcp->rtt,
+ rtp->rtcp->normdevrtt,
+ normdevrtt_current,
+ rtp->rtcp->rtt_count);
+ rtp->rtcp->normdevrtt = normdevrtt_current;
+ rtp->rtcp->rtt_count++;
+
+ return 0;
+}
+
+/*! \internal \brief Update RTCP interarrival jitter stats */
+static void update_jitter_stats(struct ast_rtp *rtp, unsigned int ia_jitter)
+{
+ double reported_jitter;
+ double reported_normdev_jitter_current;
+
+ rtp->rtcp->reported_jitter = ia_jitter;
+ reported_jitter = (double) rtp->rtcp->reported_jitter;
+ if (rtp->rtcp->reported_jitter_count == 0) {
+ rtp->rtcp->reported_minjitter = reported_jitter;
+ }
+ if (reported_jitter < rtp->rtcp->reported_minjitter) {
+ rtp->rtcp->reported_minjitter = reported_jitter;
+ }
+ if (reported_jitter > rtp->rtcp->reported_maxjitter) {
+ rtp->rtcp->reported_maxjitter = reported_jitter;
+ }
+ reported_normdev_jitter_current = normdev_compute(rtp->rtcp->reported_normdev_jitter, reported_jitter, rtp->rtcp->reported_jitter_count);
+ rtp->rtcp->reported_stdev_jitter = stddev_compute(rtp->rtcp->reported_stdev_jitter, reported_jitter, rtp->rtcp->reported_normdev_jitter, reported_normdev_jitter_current, rtp->rtcp->reported_jitter_count);
+ rtp->rtcp->reported_normdev_jitter = reported_normdev_jitter_current;
+}
+
+/*! \internal \brief Update RTCP lost packet stats */
+static void update_lost_stats(struct ast_rtp *rtp, unsigned int lost_packets)
+{
+ double reported_lost;
+ double reported_normdev_lost_current;
+
+ rtp->rtcp->reported_lost = lost_packets;
+ reported_lost = (double)rtp->rtcp->reported_lost;
+ if (rtp->rtcp->reported_jitter_count == 0) {
+ rtp->rtcp->reported_minlost = reported_lost;
+ }
+ if (reported_lost < rtp->rtcp->reported_minlost) {
+ rtp->rtcp->reported_minlost = reported_lost;
+ }
+ if (reported_lost > rtp->rtcp->reported_maxlost) {
+ rtp->rtcp->reported_maxlost = reported_lost;
+ }
+ reported_normdev_lost_current = normdev_compute(rtp->rtcp->reported_normdev_lost, reported_lost, rtp->rtcp->reported_jitter_count);
+ rtp->rtcp->reported_stdev_lost = stddev_compute(rtp->rtcp->reported_stdev_lost, reported_lost, rtp->rtcp->reported_normdev_lost, reported_normdev_lost_current, rtp->rtcp->reported_jitter_count);
+ rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;
+}
+
static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
@@ -3107,6 +3156,12 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
unsigned char rtcpdata[8192 + AST_FRIENDLY_OFFSET];
unsigned int *rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET);
int res, packetwords, position = 0;
+ int report_counter = 0;
+ struct ast_rtp_rtcp_report_block *report_block;
+ RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report,
+ NULL,
+ ao2_cleanup);
+ RAII_VAR(struct ast_json *, message_blob, NULL, ast_json_unref);
struct ast_frame *f = &ast_null_frame;
/* Read in RTCP data from the socket */
@@ -3166,10 +3221,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
while (position < packetwords) {
int i, pt, rc;
- unsigned int length, dlsr, lsr, msw, lsw, comp;
- struct timeval now;
- double rttsec, reported_jitter, reported_normdev_jitter_current, normdevrtt_current, reported_lost, reported_normdev_lost_current;
- uint64_t rtt = 0;
+ unsigned int length;
i = position;
length = ntohl(rtcpheader[i]);
@@ -3177,6 +3229,13 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
rc = (length & 0x1f000000) >> 24;
length &= 0xffff;
+ rtcp_report = ast_rtp_rtcp_report_alloc(rc);
+ if (!rtcp_report) {
+ return &ast_null_frame;
+ }
+ rtcp_report->reception_report_count = rc;
+ rtcp_report->ssrc = ntohl(rtcpheader[i + 1]);
+
if ((i + length) > packetwords) {
if (rtpdebug) {
ast_debug(1, "RTCP Read too short\n");
@@ -3187,28 +3246,41 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
if (rtcp_debug_test_addr(&addr)) {
ast_verbose("\n\nGot RTCP from %s\n",
ast_sockaddr_stringify(&addr));
- ast_verbose("PT: %d(%s)\n", pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown");
+ ast_verbose("PT: %d(%s)\n", pt, (pt == RTCP_PT_SR) ? "Sender Report" :
+ (pt == RTCP_PT_RR) ? "Receiver Report" :
+ (pt == RTCP_PT_FUR) ? "H.261 FUR" : "Unknown");
ast_verbose("Reception reports: %d\n", rc);
- ast_verbose("SSRC of sender: %u\n", rtcpheader[i + 1]);
+ ast_verbose("SSRC of sender: %u\n", rtcp_report->ssrc);
}
i += 2; /* Advance past header and ssrc */
- if (rc == 0 && pt == RTCP_PT_RR) { /* We're receiving a receiver report with no reports, which is ok */
+ if (rc == 0 && pt == RTCP_PT_RR) {
+ /* We're receiving a receiver report with no reports, which is ok */
position += (length + 1);
continue;
}
-
switch (pt) {
case RTCP_PT_SR:
- gettimeofday(&rtp->rtcp->rxlsr,NULL); /* To be able to populate the dlsr */
- rtp->rtcp->spc = ntohl(rtcpheader[i+3]);
+ gettimeofday(&rtp->rtcp->rxlsr, NULL);
+ rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff0000) >> 16);
+ rtp->rtcp->spc = ntohl(rtcpheader[i + 3]);
rtp->rtcp->soc = ntohl(rtcpheader[i + 4]);
- rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff0000) >> 16); /* Going to LSR in RR*/
+ rtcp_report->type = RTCP_PT_SR;
+ rtcp_report->sender_information.packet_count = rtp->rtcp->spc;
+ rtcp_report->sender_information.octet_count = rtp->rtcp->soc;
+ ntp2timeval((unsigned int)ntohl(rtcpheader[i]),
+ (unsigned int)ntohl(rtcpheader[i + 1]),
+ &rtcp_report->sender_information.ntp_timestamp);
+ rtcp_report->sender_information.rtp_timestamp = ntohl(rtcpheader[i + 2]);
if (rtcp_debug_test_addr(&addr)) {
- ast_verbose("NTP timestamp: %lu.%010lu\n", (unsigned long) ntohl(rtcpheader[i]), (unsigned long) ntohl(rtcpheader[i + 1]) * 4096);
- ast_verbose("RTP timestamp: %lu\n", (unsigned long) ntohl(rtcpheader[i + 2]));
- ast_verbose("SPC: %lu\tSOC: %lu\n", (unsigned long) ntohl(rtcpheader[i + 3]), (unsigned long) ntohl(rtcpheader[i + 4]));
+ ast_verbose("NTP timestamp: %u.%010u\n",
+ (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
+ (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096);
+ ast_verbose("RTP timestamp: %u\n", rtcp_report->sender_information.rtp_timestamp);
+ ast_verbose("SPC: %u\tSOC: %u\n",
+ rtcp_report->sender_information.packet_count,
+ rtcp_report->sender_information.octet_count);
}
i += 5;
if (rc < 1) {
@@ -3216,166 +3288,63 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
}
/* Intentional fall through */
case RTCP_PT_RR:
- /* Don't handle multiple reception reports (rc > 1) yet */
- /* Calculate RTT per RFC */
- gettimeofday(&now, NULL);
- timeval2ntp(now, &msw, &lsw);
- if (ntohl(rtcpheader[i + 4]) && ntohl(rtcpheader[i + 5])) { /* We must have the LSR && DLSR */
- comp = ((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16);
- lsr = ntohl(rtcpheader[i + 4]);
- dlsr = ntohl(rtcpheader[i + 5]);
- rtt = comp - lsr - dlsr;
-
- /* Convert end to end delay to usec (keeping the calculation in 64bit space)
- sess->ee_delay = (eedelay * 1000) / 65536; */
- if (rtt < 4294) {
- rtt = (rtt * 1000000) >> 16;
- } else {
- rtt = (rtt * 1000) >> 16;
- rtt *= 1000;
- }
- rtt = rtt / 1000.;
- rttsec = rtt / 1000.;
- rtp->rtcp->rtt = rttsec;
-
- if (comp - dlsr >= lsr) {
- rtp->rtcp->accumulated_transit += rttsec;
-
- if (rtp->rtcp->rtt_count == 0) {
- rtp->rtcp->minrtt = rttsec;
- }
-
- if (rtp->rtcp->maxrtt<rttsec) {
- rtp->rtcp->maxrtt = rttsec;
- }
- if (rtp->rtcp->minrtt>rttsec) {
- rtp->rtcp->minrtt = rttsec;
- }
-
- normdevrtt_current = normdev_compute(rtp->rtcp->normdevrtt, rttsec, rtp->rtcp->rtt_count);
-
- rtp->rtcp->stdevrtt = stddev_compute(rtp->rtcp->stdevrtt, rttsec, rtp->rtcp->normdevrtt, normdevrtt_current, rtp->rtcp->rtt_count);
-
- rtp->rtcp->normdevrtt = normdevrtt_current;
-
- rtp->rtcp->rtt_count++;
- } else if (rtcp_debug_test_addr(&addr)) {
- ast_verbose("Internal RTCP NTP clock skew detected: "
- "lsr=%u, now=%u, dlsr=%u (%d:%03dms), "
- "diff=%d\n",
- lsr, comp, dlsr, dlsr / 65536,
- (dlsr % 65536) * 1000 / 65536,
- dlsr - (comp - lsr));
- }
- }
-
- rtp->rtcp->reported_jitter = ntohl(rtcpheader[i + 3]);
- reported_jitter = (double) rtp->rtcp->reported_jitter;
-
- if (rtp->rtcp->reported_jitter_count == 0) {
- rtp->rtcp->reported_minjitter = reported_jitter;
- }
-
- if (reported_jitter < rtp->rtcp->reported_minjitter) {
- rtp->rtcp->reported_minjitter = reported_jitter;
- }
-
- if (reported_jitter > rtp->rtcp->reported_maxjitter) {
- rtp->rtcp->reported_maxjitter = reported_jitter;
- }
-
- reported_normdev_jitter_current = normdev_compute(rtp->rtcp->reported_normdev_jitter, reported_jitter, rtp->rtcp->reported_jitter_count);
-
- rtp->rtcp->reported_stdev_jitter = stddev_compute(rtp->rtcp->reported_stdev_jitter, reported_jitter, rtp->rtcp->reported_normdev_jitter, reported_normdev_jitter_current, rtp->rtcp->reported_jitter_count);
-
- rtp->rtcp->reported_normdev_jitter = reported_normdev_jitter_current;
-
- rtp->rtcp->reported_lost = ntohl(rtcpheader[i + 1]) & 0xffffff;
-
- reported_lost = (double) rtp->rtcp->reported_lost;
-
- /* using same counter as for jitter */
- if (rtp->rtcp->reported_jitter_count == 0) {
- rtp->rtcp->reported_minlost = reported_lost;
+ if (rtcp_report->type != RTCP_PT_SR) {
+ rtcp_report->type = RTCP_PT_RR;
}
- if (reported_lost < rtp->rtcp->reported_minlost) {
- rtp->rtcp->reported_minlost = reported_lost;
+ /* Don't handle multiple reception reports (rc > 1) yet */
+ report_block = ast_calloc(1, sizeof(*report_block));
+ if (!report_block) {
+ return &ast_null_frame;
}
-
- if (reported_lost > rtp->rtcp->reported_maxlost) {
- rtp->rtcp->reported_maxlost = reported_lost;
+ rtcp_report->report_block[report_counter] = report_block;
+ report_block->source_ssrc = ntohl(rtcpheader[i]);
+ report_block->lost_count.packets = ntohl(rtcpheader[i + 1]) & 0x00ffffff;
+ report_block->lost_count.fraction = ((ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24);
+ report_block->highest_seq_no = ntohl(rtcpheader[i + 2]);
+ report_block->ia_jitter = ntohl(rtcpheader[i + 3]);
+ report_block->lsr = ntohl(rtcpheader[i + 4]);
+ report_block->dlsr = ntohl(rtcpheader[i + 5]);
+ if (report_block->lsr
+ && update_rtt_stats(rtp, report_block->lsr, report_block->dlsr)
+ && rtcp_debug_test_addr(&addr)) {
+ struct timeval now;
+ unsigned int lsr_now, lsw, msw;
+ gettimeofday(&now, NULL);
+ timeval2ntp(now, &msw, &lsw);
+ lsr_now = (((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16));
+ ast_verbose("Internal RTCP NTP clock skew detected: "
+ "lsr=%u, now=%u, dlsr=%u (%d:%03dms), "
+ "diff=%d\n",
+ report_block->lsr, lsr_now, report_block->dlsr, report_block->dlsr / 65536,
+ (report_block->dlsr % 65536) * 1000 / 65536,
+ report_block->dlsr - (lsr_now - report_block->lsr));
}
- reported_normdev_lost_current = normdev_compute(rtp->rtcp->reported_normdev_lost, reported_lost, rtp->rtcp->reported_jitter_count);
-
- rtp->rtcp->reported_stdev_lost = stddev_compute(rtp->rtcp->reported_stdev_lost, reported_lost, rtp->rtcp->reported_normdev_lost, reported_normdev_lost_current, rtp->rtcp->reported_jitter_count);
-
- rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;
-
+ update_jitter_stats(rtp, report_block->ia_jitter);
+ update_lost_stats(rtp, report_block->lost_count.packets);
rtp->rtcp->reported_jitter_count++;
if (rtcp_debug_test_addr(&addr)) {
- ast_verbose(" Fraction lost: %ld\n", (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24));
- ast_verbose(" Packets lost so far: %d\n", rtp->rtcp->reported_lost);
- ast_verbose(" Highest sequence number: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff));
- ast_verbose(" Sequence number cycles: %ld\n", (long) (ntohl(rtcpheader[i + 2])) >> 16);
- ast_verbose(" Interarrival jitter: %u\n", rtp->rtcp->reported_jitter);
- ast_verbose(" Last SR(our NTP): %lu.%010lu\n",(unsigned long) ntohl(rtcpheader[i + 4]) >> 16,((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096);
- ast_verbose(" DLSR: %4.4f (sec)\n",ntohl(rtcpheader[i + 5])/65536.0);
- if (rtt) {
- ast_verbose(" RTT: %lu(sec)\n", (unsigned long) rtt);
- }
- }
- if (rtt) {
- manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From: %s\r\n"
- "PT: %d(%s)\r\n"
- "ReceptionReports: %d\r\n"
- "SenderSSRC: %u\r\n"
- "FractionLost: %ld\r\n"
- "PacketsLost: %d\r\n"
- "HighestSequence: %ld\r\n"
- "SequenceNumberCycles: %ld\r\n"
- "IAJitter: %u\r\n"
- "LastSR: %lu.%010lu\r\n"
- "DLSR: %4.4f(sec)\r\n"
- "RTT: %llu(sec)\r\n",
- ast_sockaddr_stringify(&addr),
- pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown",
- rc,
- rtcpheader[i + 1],
- (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24),
- rtp->rtcp->reported_lost,
- (long) (ntohl(rtcpheader[i + 2]) & 0xffff),
- (long) (ntohl(rtcpheader[i + 2])) >> 16,
- rtp->rtcp->reported_jitter,
- (unsigned long) ntohl(rtcpheader[i + 4]) >> 16, ((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096,
- ntohl(rtcpheader[i + 5])/65536.0,
- (unsigned long long)rtt);
- } else {
- manager_event(EVENT_FLAG_REPORTING, "RTCPReceived", "From: %s\r\n"
- "PT: %d(%s)\r\n"
- "ReceptionReports: %d\r\n"
- "SenderSSRC: %u\r\n"
- "FractionLost: %ld\r\n"
- "PacketsLost: %d\r\n"
- "HighestSequence: %ld\r\n"
- "SequenceNumberCycles: %ld\r\n"
- "IAJitter: %u\r\n"
- "LastSR: %lu.%010lu\r\n"
- "DLSR: %4.4f(sec)\r\n",
- ast_sockaddr_stringify(&addr),
- pt, (pt == 200) ? "Sender Report" : (pt == 201) ? "Receiver Report" : (pt == 192) ? "H.261 FUR" : "Unknown",
- rc,
- rtcpheader[i + 1],
- (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24),
- rtp->rtcp->reported_lost,
- (long) (ntohl(rtcpheader[i + 2]) & 0xffff),
- (long) (ntohl(rtcpheader[i + 2])) >> 16,
- rtp->rtcp->reported_jitter,
- (unsigned long) ntohl(rtcpheader[i + 4]) >> 16,
- ((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096,
- ntohl(rtcpheader[i + 5])/65536.0);
+ ast_verbose(" Fraction lost: %u\n", report_block->lost_count.fraction);
+ ast_verbose(" Packets lost so far: %u\n", report_block->lost_count.packets);
+ ast_verbose(" Highest sequence number: %u\n", report_block->highest_seq_no & 0x0000ffff);
+ ast_verbose(" Sequence number cycles: %u\n", report_block->highest_seq_no >> 16);
+ ast_verbose(" Interarrival jitter: %u\n", report_block->ia_jitter);
+ ast_verbose(" Last SR(our NTP): %lu.%010lu\n",(unsigned long)(report_block->lsr) >> 16,((unsigned long)(report_block->lsr) << 16) * 4096);
+ ast_verbose(" DLSR: %4.4f (sec)\n",(double)report_block->dlsr / 65536.0);
+ ast_verbose(" RTT: %4.4f(sec)\n", rtp->rtcp->rtt);
}
+ report_counter++;
+
+ /* If and when we handle more than one report block, this should occur outside
+ * this loop.
+ */
+ message_blob = ast_json_pack("{s: s, s: f}",
+ "from", ast_sockaddr_stringify(&addr),
+ "rtt", rtp->rtcp->rtt);
+ ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_received_type(),
+ rtcp_report,
+ message_blob);
break;
case RTCP_PT_FUR:
if (rtcp_debug_test_addr(&addr)) {
@@ -3408,7 +3377,6 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
}
position += (length + 1);
}
-
rtp->rtcp->rtcp_info = 1;
return f;
@@ -4111,6 +4079,7 @@ static int ast_rtp_get_stat(struct ast_rtp_instance *instance, struct ast_rtp_in
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_SSRC, -1, stats->local_ssrc, rtp->ssrc);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_SSRC, -1, stats->remote_ssrc, rtp->themssrc);
+ AST_RTP_STAT_STRCPY(AST_RTP_INSTANCE_STAT_CHANNEL_UNIQUEID, -1, stats->channel_uniqueid, ast_rtp_instance_get_channel_id(instance));
return 0;
}