res_hep_rtcp: Add module that sends RTCP information to a Homer Server

This patch adds a new module to Asterisk, res_hep_rtcp. The module subscribes
to the RTCP topics in Stasis and receives RTCP information back from the
message bus. It encodes into HEPv3 packets and sends the information to the
res_hep module for transmission.

Using this, someone with a Homer server can get live call quality monitoring
for all RTP-based channels in their Asterisk 12+ systems.

In addition, there were a few bugs in the RTP engine, res_rtp_asterisk, and
chan_pjsip that were uncovered by the tests written for the Asterisk Test
Suite. This patch fixes the following:
1) chan_pjsip failed to set its channel unique ids on its RTP instance on
   outbound calls. It now does this in the appropriate location, in the
   serialized call callback.
2) The rtp_engine was overflowing some values when packed into JSON.
   Specifically, some longs and unsigned ints can't be be packed into integer
   values, for obvious reasons. Since libjansson only supports integers,
   floats, strings, booleans, and objects, we print these values into strings.
3) res_rtp_asterisk had a few problems:
   (a) it would emit a source IP address of 0.0.0.0 if bound to that IP
       address. We now use ast_find_ourip to get a better IP address, and
       properly marshal the result into an ast_strdupa'd string.
   (b) Reports can be generated with no report bodies. In particular, this
       occurs when a sender is transmitting information to a receiver (who
       will send no RTP back to the sender). As such, the sender has no report
       body for what it received. We now properly handle this case, and the
       sender will emit SR reports with no body. Likewise, if we receive an
       RTCP packet with no report body, we will still generate the appropriate
       events.

ASTERISK-24119 #close
........

Merged revisions 419823 from http://svn.asterisk.org/svn/asterisk/branches/12


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@419825 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Matthew Jordan
2014-07-31 11:57:51 +00:00
parent 922e3203a9
commit bbeaeea1a3
5 changed files with 304 additions and 110 deletions

147
res/res_hep_rtcp.c Normal file
View File

@@ -0,0 +1,147 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2014, Digium, Inc.
*
* Matt Jordan <mjordan@digium.com>
*
* 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 <mjordan@digium.com>
*
*/
/*** MODULEINFO
<depend>res_hep</depend>
<defaultenabled>no</defaultenabled>
<support_level>extended</support_level>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <pjsip.h>
#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,
);