diff --git a/CHANGES b/CHANGES index a8564b8455..299489e8cc 100644 --- a/CHANGES +++ b/CHANGES @@ -245,6 +245,11 @@ res_pjsip created for an endpoint with this setting will have its accountcode set to the specified value. +res_hep_rtcp +------------------ + * A new module, res_hep_rtcp, has been added that will forward RTCP call + statistics to a HEP capture server. See res_hep for more information. + Functions ------------------ * Function AUDIOHOOK_INHERIT has been deprecated. Audiohooks are now diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 92a96eb0e5..c958f80864 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -353,6 +353,16 @@ static struct ast_rtp_glue chan_pjsip_rtp_glue = { .update_peer = chan_pjsip_set_rtp_peer, }; +static void set_channel_on_rtp_instance(struct chan_pjsip_pvt *pvt, const char *channel_id) +{ + if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) { + ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, channel_id); + } + if (pvt->media[SIP_MEDIA_VIDEO] && pvt->media[SIP_MEDIA_VIDEO]->rtp) { + ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_VIDEO]->rtp, channel_id); + } +} + /*! \brief Function called to create a new PJSIP Asterisk channel */ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int state, const char *exten, const char *title, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *cid_name) { @@ -452,12 +462,7 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s * these will need to be recaptured as well */ pvt->media[SIP_MEDIA_AUDIO] = ao2_find(session->media, "audio", OBJ_KEY); pvt->media[SIP_MEDIA_VIDEO] = ao2_find(session->media, "video", OBJ_KEY); - if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) { - ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, ast_channel_uniqueid(chan)); - } - if (pvt->media[SIP_MEDIA_VIDEO] && pvt->media[SIP_MEDIA_VIDEO]->rtp) { - ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_VIDEO]->rtp, ast_channel_uniqueid(chan)); - } + set_channel_on_rtp_instance(pvt, ast_channel_uniqueid(chan)); return chan; } @@ -685,12 +690,7 @@ static int fixup(void *data) struct chan_pjsip_pvt *pvt = channel->pvt; channel->session->channel = fix_data->chan; - if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) { - ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, ast_channel_uniqueid(fix_data->chan)); - } - if (pvt->media[SIP_MEDIA_VIDEO] && pvt->media[SIP_MEDIA_VIDEO]->rtp) { - ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_VIDEO]->rtp, ast_channel_uniqueid(fix_data->chan)); - } + set_channel_on_rtp_instance(pvt, ast_channel_uniqueid(fix_data->chan)); return 0; } @@ -1523,7 +1523,9 @@ static void update_initial_connected_line(struct ast_sip_session *session) static int call(void *data) { - struct ast_sip_session *session = data; + struct ast_sip_channel_pvt *channel = data; + struct ast_sip_session *session = channel->session; + struct chan_pjsip_pvt *pvt = channel->pvt; pjsip_tx_data *tdata; int res = ast_sip_session_create_invite(session, &tdata); @@ -1532,10 +1534,11 @@ static int call(void *data) ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0); ast_queue_hangup(session->channel); } else { + set_channel_on_rtp_instance(pvt, ast_channel_uniqueid(session->channel)); update_initial_connected_line(session); ast_sip_session_send_request(session, tdata); } - ao2_ref(session, -1); + ao2_ref(channel, -1); return res; } @@ -1544,10 +1547,10 @@ static int chan_pjsip_call(struct ast_channel *ast, const char *dest, int timeou { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); - ao2_ref(channel->session, +1); - if (ast_sip_push_task(channel->session->serializer, call, channel->session)) { + ao2_ref(channel, +1); + if (ast_sip_push_task(channel->session->serializer, call, channel)) { ast_log(LOG_WARNING, "Error attempting to place outbound call to call '%s'\n", dest); - ao2_cleanup(channel->session); + ao2_cleanup(channel); return -1; } @@ -1632,12 +1635,7 @@ static struct hangup_data *hangup_data_alloc(int cause, struct ast_channel *chan static void clear_session_and_channel(struct ast_sip_session *session, struct ast_channel *ast, struct chan_pjsip_pvt *pvt) { session->channel = NULL; - if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) { - ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, ""); - } - if (pvt->media[SIP_MEDIA_VIDEO] && pvt->media[SIP_MEDIA_VIDEO]->rtp) { - ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_VIDEO]->rtp, ""); - } + set_channel_on_rtp_instance(pvt, ""); ast_channel_tech_pvt_set(ast, NULL); } diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 07ef1f697e..52be8b90e2 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -1909,13 +1909,15 @@ static struct ast_json *rtcp_report_to_json(struct stasis_message *msg, for (i = 0; i < payload->report->reception_report_count; i++) { struct ast_json *json_report_block; - json_report_block = ast_json_pack("{s: i, s: i, s: i, s: i, s: i, s: i, s: i}", + char str_lsr[32]; + snprintf(str_lsr, sizeof(str_lsr), "%u", payload->report->report_block[i]->lsr); + json_report_block = ast_json_pack("{s: i, s: i, s: i, s: i, s: i, s: s, s: i}", "source_ssrc", payload->report->report_block[i]->source_ssrc, "fraction_lost", payload->report->report_block[i]->lost_count.fraction, "packets_lost", payload->report->report_block[i]->lost_count.packets, "highest_seq_no", payload->report->report_block[i]->highest_seq_no, "ia_jitter", payload->report->report_block[i]->ia_jitter, - "lsr", payload->report->report_block[i]->lsr, + "lsr", str_lsr, "dlsr", payload->report->report_block[i]->dlsr); if (!json_report_block) { return NULL; @@ -1927,9 +1929,13 @@ static struct ast_json *rtcp_report_to_json(struct stasis_message *msg, } if (payload->report->type == AST_RTP_RTCP_SR) { - json_rtcp_sender_info = ast_json_pack("{s: i, s: i, s: i, s: i, s: i}", - "ntp_timestamp_sec", payload->report->sender_information.ntp_timestamp.tv_sec, - "ntp_timestamp_usec", payload->report->sender_information.ntp_timestamp.tv_usec, + char sec[32]; + char usec[32]; + snprintf(sec, sizeof(sec), "%ld", payload->report->sender_information.ntp_timestamp.tv_sec); + snprintf(usec, sizeof(usec), "%ld", payload->report->sender_information.ntp_timestamp.tv_usec); + json_rtcp_sender_info = ast_json_pack("{s: s, s: s, s: i, s: i, s: i}", + "ntp_timestamp_sec", sec, + "ntp_timestamp_usec", usec, "rtp_timestamp", payload->report->sender_information.rtp_timestamp, "packets", payload->report->sender_information.packet_count, "octets", payload->report->sender_information.octet_count); diff --git a/res/res_hep_rtcp.c b/res/res_hep_rtcp.c new file mode 100644 index 0000000000..63df1c8b06 --- /dev/null +++ b/res/res_hep_rtcp.c @@ -0,0 +1,147 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2014, Digium, Inc. + * + * Matt Jordan + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief RTCP logging with Homer + * + * \author Matt Jordan + * + */ + +/*** MODULEINFO + res_hep + no + extended + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include + +#include "asterisk/res_hep.h" +#include "asterisk/module.h" +#include "asterisk/netsock2.h" +#include "asterisk/stasis.h" +#include "asterisk/rtp_engine.h" +#include "asterisk/json.h" +#include "asterisk/config.h" + +static struct stasis_subscription *stasis_rtp_subscription; + +static void rtcp_message_handler(struct stasis_message *message) +{ + + RAII_VAR(struct ast_json *, json_payload, NULL, ast_json_unref); + RAII_VAR(char *, payload, NULL, ast_json_free); + struct ast_json *json_blob; + struct ast_json *json_channel; + struct ast_json *json_rtcp; + struct hepv3_capture_info *capture_info; + struct ast_json *from; + struct ast_json *to; + struct timeval current_time = ast_tvnow(); + + json_payload = stasis_message_to_json(message, NULL); + if (!json_payload) { + return; + } + + json_blob = ast_json_object_get(json_payload, "blob"); + if (!json_blob) { + return; + } + + json_channel = ast_json_object_get(json_payload, "channel"); + if (!json_channel) { + return; + } + + json_rtcp = ast_json_object_get(json_payload, "rtcp_report"); + if (!json_rtcp) { + return; + } + + from = ast_json_object_get(json_blob, "from"); + to = ast_json_object_get(json_blob, "to"); + if (!from || !to) { + return; + } + + payload = ast_json_dump_string(json_rtcp); + if (ast_strlen_zero(payload)) { + return; + } + + capture_info = hepv3_create_capture_info(payload, strlen(payload)); + if (!capture_info) { + return; + } + ast_sockaddr_parse(&capture_info->src_addr, ast_json_string_get(from), PARSE_PORT_REQUIRE); + ast_sockaddr_parse(&capture_info->dst_addr, ast_json_string_get(to), PARSE_PORT_REQUIRE); + + capture_info->uuid = ast_strdup(ast_json_string_get(ast_json_object_get(json_channel, "name"))); + if (!capture_info->uuid) { + ao2_ref(capture_info, -1); + return; + } + capture_info->capture_time = current_time; + capture_info->capture_type = HEPV3_CAPTURE_TYPE_RTCP; + capture_info->zipped = 0; + + hepv3_send_packet(capture_info); +} + +static void rtp_topic_handler(void *data, struct stasis_subscription *sub, struct stasis_message *message) +{ + struct stasis_message_type *message_type = stasis_message_type(message); + + if ((message_type == ast_rtp_rtcp_sent_type()) || + (message_type == ast_rtp_rtcp_received_type())) { + rtcp_message_handler(message); + } +} + +static int load_module(void) +{ + + stasis_rtp_subscription = stasis_subscribe(ast_rtp_topic(), + rtp_topic_handler, NULL); + if (!stasis_rtp_subscription) { + return AST_MODULE_LOAD_FAILURE; + } + + return AST_MODULE_LOAD_SUCCESS; +} + +static int unload_module(void) +{ + if (stasis_rtp_subscription) { + stasis_rtp_subscription = stasis_unsubscribe(stasis_rtp_subscription); + } + + return 0; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RTCP HEPv3 Logger", + .load = load_module, + .unload = unload_module, + .load_pri = AST_MODPRI_DEFAULT, + ); diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 55abf61543..f192bacb8e 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -2637,10 +2637,15 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) 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; + char *str_remote_address; + char *str_local_address; + struct ast_sockaddr remote_address = { { 0, } }; + struct ast_sockaddr local_address = { { 0, } }; + struct ast_sockaddr real_remote_address = { { 0, } }; + struct ast_sockaddr real_local_address = { { 0, } }; + struct ast_rtp_rtcp_report_block *report_block = NULL; RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report, - ast_rtp_rtcp_report_alloc(1), + ast_rtp_rtcp_report_alloc(rtp->themssrc ? 1 : 0), ao2_cleanup); if (!rtp || !rtp->rtcp) { @@ -2656,16 +2661,11 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) 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); - rtcp_report->reception_report_count = 1; + rtcp_report->reception_report_count = rtp->themssrc ? 1 : 0; rtcp_report->ssrc = rtp->ssrc; rtcp_report->type = sr ? RTCP_PT_SR : RTCP_PT_RR; if (sr) { @@ -2674,17 +2674,25 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) 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; + + if (rtp->themssrc) { + report_block = ast_calloc(1, sizeof(*report_block)); + if (!report_block) { + return 1; + } + + 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; @@ -2699,14 +2707,17 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) 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) | ((sr ? RTCP_PT_SR : RTCP_PT_RR) << 16) | ((len/4)-1)); + if (report_block) { + 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) | (rtcp_report->reception_report_count << 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) */ @@ -2758,8 +2769,22 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr) 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_instance_get_local_address(instance, &local_address); + if (!ast_find_ourip(&real_local_address, &local_address, 0)) { + str_local_address = ast_strdupa(ast_sockaddr_stringify(&real_local_address)); + } else { + str_local_address = ast_strdupa(ast_sockaddr_stringify(&local_address)); + } + + if (!ast_find_ourip(&real_remote_address, &remote_address, 0)) { + str_remote_address = ast_strdupa(ast_sockaddr_stringify(&real_remote_address)); + } else { + str_remote_address = ast_strdupa(ast_sockaddr_stringify(&remote_address)); + } + + message_blob = ast_json_pack("{s: s, s: s}", + "to", str_remote_address, + "from", str_local_address); ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_sent_type(), rtcp_report, message_blob); @@ -3574,6 +3599,11 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) int report_counter = 0; struct ast_rtp_rtcp_report_block *report_block; struct ast_frame *f = &ast_null_frame; + char *str_local_address; + char *str_remote_address; + struct ast_sockaddr local_address = { { 0,} }; + struct ast_sockaddr real_local_address = { { 0, } }; + struct ast_sockaddr real_remote_address = { { 0, } }; /* Read in RTCP data from the socket */ if ((res = rtcp_recvfrom(instance, rtcpdata + AST_FRIENDLY_OFFSET, @@ -3630,6 +3660,8 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) ast_debug(1, "Got RTCP report of %d bytes\n", res); + ast_rtp_instance_get_local_address(instance, &local_address); + while (position < packetwords) { int i, pt, rc; unsigned int length; @@ -3667,11 +3699,6 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) } 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 */ - position += (length + 1); - continue; - } switch (pt) { case RTCP_PT_SR: gettimeofday(&rtp->rtcp->rxlsr, NULL); @@ -3696,64 +3723,75 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance) rtcp_report->sender_information.octet_count); } i += 5; - if (rc < 1) { - break; - } /* Intentional fall through */ case RTCP_PT_RR: if (rtcp_report->type != RTCP_PT_SR) { rtcp_report->type = RTCP_PT_RR; } - /* 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 (rc > 0) { + /* Don't handle multiple reception reports (rc > 1) yet */ + report_block = ast_calloc(1, sizeof(*report_block)); + if (!report_block) { + return &ast_null_frame; + } + 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 (%u:%03ums), " + "diff=%u\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)); + } + 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: %d\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++; } - 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 (%u:%03ums), " - "diff=%u\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)); + /* If and when we handle more than one report block, this should occur outside + * this loop. + */ + if (!ast_find_ourip(&real_local_address, &local_address, 0)) { + str_local_address = ast_strdupa(ast_sockaddr_stringify(&real_local_address)); + } else { + str_local_address = ast_strdupa(ast_sockaddr_stringify(&local_address)); } - 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: %d\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); + if (!ast_find_ourip(&real_remote_address, &addr, 0)) { + str_remote_address = ast_strdupa(ast_sockaddr_stringify(&real_remote_address)); + } else { + str_remote_address = ast_strdupa(ast_sockaddr_stringify(&addr)); } - 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), + message_blob = ast_json_pack("{s: s, s: s, s: f}", + "from", str_remote_address, + "to", str_local_address, "rtt", rtp->rtcp->rtt); ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_received_type(), rtcp_report,