Supports RTP and RTCP with Symmetric RTP support for NAT traversal. More...
#include "asterisk.h"#include <sys/time.h>#include <signal.h>#include <fcntl.h>#include "asterisk/stun.h"#include "asterisk/pbx.h"#include "asterisk/frame.h"#include "asterisk/channel.h"#include "asterisk/acl.h"#include "asterisk/config.h"#include "asterisk/lock.h"#include "asterisk/utils.h"#include "asterisk/cli.h"#include "asterisk/manager.h"#include "asterisk/unaligned.h"#include "asterisk/module.h"#include "asterisk/rtp_engine.h"
Go to the source code of this file.
Data Structures | |
| struct | ast_rtcp |
| Structure defining an RTCP session. More... | |
| struct | ast_rtp |
| RTP session description. More... | |
| struct | frame_list |
| struct | rtp_red |
Defines | |
| #define | DEFAULT_DTMF_TIMEOUT (150 * (8000 / 1000)) |
| #define | DEFAULT_RTP_END 31000 |
| #define | DEFAULT_RTP_START 5000 |
| #define | FLAG_3389_WARNING (1 << 0) |
| #define | FLAG_DTMF_COMPENSATE (1 << 4) |
| #define | FLAG_NAT_ACTIVE (3 << 1) |
| #define | FLAG_NAT_INACTIVE (0 << 1) |
| #define | FLAG_NAT_INACTIVE_NOWARN (1 << 1) |
| #define | FLAG_NEED_MARKER_BIT (1 << 3) |
| #define | MAX_TIMESTAMP_SKEW 640 |
| #define | MAXIMUM_RTP_PORT 65535 |
| #define | MINIMUM_RTP_PORT 1024 |
| #define | RTCP_DEFAULT_INTERVALMS 5000 |
| #define | RTCP_MAX_INTERVALMS 60000 |
| #define | RTCP_MIN_INTERVALMS 500 |
| #define | RTCP_PT_APP 204 |
| #define | RTCP_PT_BYE 203 |
| #define | RTCP_PT_FUR 192 |
| #define | RTCP_PT_RR 201 |
| #define | RTCP_PT_SDES 202 |
| #define | RTCP_PT_SR 200 |
| #define | RTP_MTU 1200 |
| #define | RTP_SEQ_MOD (1<<16) |
| #define | SQUARE(x) ((x) * (x)) |
| #define | ZFONE_PROFILE_ID 0x505a |
Enumerations | |
| enum | strict_rtp_state { STRICT_RTP_OPEN = 0, STRICT_RTP_LEARN, STRICT_RTP_CLOSED } |
Functions | |
| static void | __reg_module (void) |
| static int | __rtp_recvfrom (struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp) |
| static int | __rtp_sendto (struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp) |
| static void | __unreg_module (void) |
| static unsigned int | ast_rtcp_calc_interval (struct ast_rtp *rtp) |
| static struct ast_frame * | ast_rtcp_read (struct ast_rtp_instance *instance) |
| static int | ast_rtcp_write (const void *data) |
| Write and RTCP packet to the far end. | |
| static int | ast_rtcp_write_rr (struct ast_rtp_instance *instance) |
| Send RTCP recipient's report. | |
| static int | ast_rtcp_write_sr (struct ast_rtp_instance *instance) |
| Send RTCP sender's report. | |
| static void | ast_rtp_alt_remote_address_set (struct ast_rtp_instance *instance, struct ast_sockaddr *addr) |
| static void | ast_rtp_change_source (struct ast_rtp_instance *instance) |
| static int | ast_rtp_destroy (struct ast_rtp_instance *instance) |
| static int | ast_rtp_dtmf_begin (struct ast_rtp_instance *instance, char digit) |
| static int | ast_rtp_dtmf_compatible (struct ast_channel *chan0, struct ast_rtp_instance *instance0, struct ast_channel *chan1, struct ast_rtp_instance *instance1) |
| static int | ast_rtp_dtmf_continuation (struct ast_rtp_instance *instance) |
| static int | ast_rtp_dtmf_end (struct ast_rtp_instance *instance, char digit) |
| static int | ast_rtp_dtmf_end_with_duration (struct ast_rtp_instance *instance, char digit, unsigned int duration) |
| static enum ast_rtp_dtmf_mode | ast_rtp_dtmf_mode_get (struct ast_rtp_instance *instance) |
| static int | ast_rtp_dtmf_mode_set (struct ast_rtp_instance *instance, enum ast_rtp_dtmf_mode dtmf_mode) |
| static int | ast_rtp_fd (struct ast_rtp_instance *instance, int rtcp) |
| static int | ast_rtp_get_stat (struct ast_rtp_instance *instance, struct ast_rtp_instance_stats *stats, enum ast_rtp_instance_stat stat) |
| static int | ast_rtp_local_bridge (struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1) |
| static int | ast_rtp_new (struct ast_rtp_instance *instance, struct sched_context *sched, struct ast_sockaddr *addr, void *data) |
| static void | ast_rtp_prop_set (struct ast_rtp_instance *instance, enum ast_rtp_property property, int value) |
| static int | ast_rtp_qos_set (struct ast_rtp_instance *instance, int tos, int cos, const char *desc) |
| static int | ast_rtp_raw_write (struct ast_rtp_instance *instance, struct ast_frame *frame, int codec) |
| static struct ast_frame * | ast_rtp_read (struct ast_rtp_instance *instance, int rtcp) |
| static void | ast_rtp_remote_address_set (struct ast_rtp_instance *instance, struct ast_sockaddr *addr) |
| static int | ast_rtp_sendcng (struct ast_rtp_instance *instance, int level) |
| generate comfort noice (CNG) | |
| static void | ast_rtp_stop (struct ast_rtp_instance *instance) |
| static void | ast_rtp_stun_request (struct ast_rtp_instance *instance, struct ast_sockaddr *suggestion, const char *username) |
| static void | ast_rtp_update_source (struct ast_rtp_instance *instance) |
| static int | ast_rtp_write (struct ast_rtp_instance *instance, struct ast_frame *frame) |
| static int | bridge_p2p_rtp_write (struct ast_rtp_instance *instance, unsigned int *rtpheader, int len, int hdrlen) |
| static void | calc_rxstamp (struct timeval *tv, struct ast_rtp *rtp, unsigned int timestamp, int mark) |
| static unsigned int | calc_txstamp (struct ast_rtp *rtp, struct timeval *delivery) |
| static struct ast_frame * | create_dtmf_frame (struct ast_rtp_instance *instance, enum ast_frame_type type, int compensate) |
| static int | create_new_socket (const char *type, int af) |
| static char * | handle_cli_rtcp_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_cli_rtcp_set_stats (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_cli_rtp_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | load_module (void) |
| static double | normdev_compute (double normdev, double sample, unsigned int sample_count) |
| Calculate normal deviation. | |
| static struct ast_frame * | process_cn_rfc3389 (struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark) |
| static struct ast_frame * | process_dtmf_cisco (struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark) |
| static void | process_dtmf_rfc2833 (struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark, struct frame_list *frames) |
| static struct ast_frame * | red_t140_to_red (struct rtp_red *red) |
| static int | red_write (const void *data) |
| Write t140 redundacy frame. | |
| static int | reload_module (void) |
| static int | rtcp_debug_test_addr (struct ast_sockaddr *addr) |
| static char * | rtcp_do_debug_ip (struct ast_cli_args *a) |
| static int | rtcp_recvfrom (struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa) |
| static int | rtcp_sendto (struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa) |
| static int | rtp_debug_test_addr (struct ast_sockaddr *addr) |
| static char * | rtp_do_debug_ip (struct ast_cli_args *a) |
| static int | rtp_get_rate (format_t subclass) |
| static int | rtp_recvfrom (struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa) |
| static int | rtp_red_buffer (struct ast_rtp_instance *instance, struct ast_frame *frame) |
| static int | rtp_red_init (struct ast_rtp_instance *instance, int buffer_time, int *payloads, int generations) |
| static int | rtp_reload (int reload) |
| static int | rtp_sendto (struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa) |
| static double | stddev_compute (double stddev, double sample, double normdev, double normdev_curent, unsigned int sample_count) |
| static void | timeval2ntp (struct timeval tv, unsigned int *msw, unsigned int *lsw) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk RTP Stack" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_rtp_engine | asterisk_rtp_engine |
| static struct ast_cli_entry | cli_rtp [] |
| static int | dtmftimeout = DEFAULT_DTMF_TIMEOUT |
| struct ast_srtp_res * | res_srtp |
| static int | rtcpdebug |
| static struct ast_sockaddr | rtcpdebugaddr |
| static int | rtcpdebugport |
| static int | rtcpinterval = RTCP_DEFAULT_INTERVALMS |
| static int | rtcpstats |
| static int | rtpdebug |
| static struct ast_sockaddr | rtpdebugaddr |
| static int | rtpdebugport |
| static int | rtpend = DEFAULT_RTP_END |
| static int | rtpstart = DEFAULT_RTP_START |
| static int | strictrtp |
Supports RTP and RTCP with Symmetric RTP support for NAT traversal.
Definition in file res_rtp_asterisk.c.
| #define DEFAULT_DTMF_TIMEOUT (150 * (8000 / 1000)) |
| #define DEFAULT_RTP_END 31000 |
Default maximum port number to end allocating RTP ports at
Definition at line 65 of file res_rtp_asterisk.c.
Referenced by rtp_reload().
| #define DEFAULT_RTP_START 5000 |
Default port number to start allocating RTP ports from
Definition at line 64 of file res_rtp_asterisk.c.
Referenced by rtp_reload().
| #define FLAG_3389_WARNING (1 << 0) |
Definition at line 107 of file res_rtp_asterisk.c.
Referenced by process_cn_rfc3389().
| #define FLAG_DTMF_COMPENSATE (1 << 4) |
Definition at line 112 of file res_rtp_asterisk.c.
| #define FLAG_NAT_ACTIVE (3 << 1) |
Definition at line 108 of file res_rtp_asterisk.c.
Referenced by ast_rtp_raw_write(), ast_rtp_read(), and bridge_p2p_rtp_write().
| #define FLAG_NAT_INACTIVE (0 << 1) |
Definition at line 109 of file res_rtp_asterisk.c.
Referenced by ast_rtp_raw_write(), and bridge_p2p_rtp_write().
| #define FLAG_NAT_INACTIVE_NOWARN (1 << 1) |
Definition at line 110 of file res_rtp_asterisk.c.
Referenced by ast_rtp_raw_write(), and bridge_p2p_rtp_write().
| #define FLAG_NEED_MARKER_BIT (1 << 3) |
Definition at line 111 of file res_rtp_asterisk.c.
Referenced by ast_rtp_change_source(), ast_rtp_local_bridge(), ast_rtp_raw_write(), ast_rtp_stop(), ast_rtp_update_source(), and bridge_p2p_rtp_write().
| #define MAX_TIMESTAMP_SKEW 640 |
Definition at line 57 of file res_rtp_asterisk.c.
Referenced by ast_rtp_raw_write().
| #define MAXIMUM_RTP_PORT 65535 |
Maximum port number to accept
Definition at line 68 of file res_rtp_asterisk.c.
Referenced by rtp_reload().
| #define MINIMUM_RTP_PORT 1024 |
Minimum port number to accept
Definition at line 67 of file res_rtp_asterisk.c.
Referenced by rtp_reload().
| #define RTCP_DEFAULT_INTERVALMS 5000 |
Default milli-seconds between RTCP reports we send
Definition at line 60 of file res_rtp_asterisk.c.
| #define RTCP_MAX_INTERVALMS 60000 |
Max milli-seconds between RTCP reports we send
Definition at line 62 of file res_rtp_asterisk.c.
Referenced by rtp_reload().
| #define RTCP_MIN_INTERVALMS 500 |
Min milli-seconds between RTCP reports we send
Definition at line 61 of file res_rtp_asterisk.c.
Referenced by rtp_reload().
| #define RTCP_PT_APP 204 |
Definition at line 75 of file res_rtp_asterisk.c.
| #define RTCP_PT_BYE 203 |
Definition at line 74 of file res_rtp_asterisk.c.
Referenced by ast_rtcp_read().
| #define RTCP_PT_FUR 192 |
Definition at line 70 of file res_rtp_asterisk.c.
Referenced by ast_rtcp_read().
| #define RTCP_PT_RR 201 |
Definition at line 72 of file res_rtp_asterisk.c.
Referenced by ast_rtcp_read(), and ast_rtcp_write_rr().
| #define RTCP_PT_SDES 202 |
Definition at line 73 of file res_rtp_asterisk.c.
Referenced by ast_rtcp_read(), ast_rtcp_write_rr(), and ast_rtcp_write_sr().
| #define RTCP_PT_SR 200 |
Definition at line 71 of file res_rtp_asterisk.c.
Referenced by ast_rtcp_read(), and ast_rtcp_write_sr().
| #define RTP_MTU 1200 |
Definition at line 77 of file res_rtp_asterisk.c.
| #define RTP_SEQ_MOD (1<<16) |
A sequence number can't be more than 16 bits
Definition at line 59 of file res_rtp_asterisk.c.
Referenced by ast_rtp_read().
| #define SQUARE | ( | x | ) | ((x) * (x)) |
Referenced by stddev_compute().
| #define ZFONE_PROFILE_ID 0x505a |
Definition at line 81 of file res_rtp_asterisk.c.
| enum strict_rtp_state |
| STRICT_RTP_OPEN | |
| STRICT_RTP_LEARN |
No RTP packets should be dropped, all sources accepted |
| STRICT_RTP_CLOSED |
Accept next packet as source |
Definition at line 101 of file res_rtp_asterisk.c.
{
STRICT_RTP_OPEN = 0, /*! No RTP packets should be dropped, all sources accepted */
STRICT_RTP_LEARN, /*! Accept next packet as source */
STRICT_RTP_CLOSED, /*! Drop all RTP packets not coming from source that was learned */
};
| static void __reg_module | ( | void | ) | [static] |
Definition at line 2975 of file res_rtp_asterisk.c.
| static int __rtp_recvfrom | ( | struct ast_rtp_instance * | instance, |
| void * | buf, | ||
| size_t | size, | ||
| int | flags, | ||
| struct ast_sockaddr * | sa, | ||
| int | rtcp | ||
| ) | [static] |
Definition at line 347 of file res_rtp_asterisk.c.
References ast_recvfrom(), ast_rtp_instance_get_data(), ast_rtp_instance_get_srtp(), len(), ast_rtp::rtcp, ast_rtp::s, ast_rtcp::s, and ast_srtp_res::unprotect.
Referenced by rtcp_recvfrom(), and rtp_recvfrom().
{
int len;
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance);
if ((len = ast_recvfrom(rtcp ? rtp->rtcp->s : rtp->s, buf, size, flags, sa)) < 0) {
return len;
}
if (res_srtp && srtp && res_srtp->unprotect(srtp, buf, &len, rtcp) < 0) {
return -1;
}
return len;
}
| static int __rtp_sendto | ( | struct ast_rtp_instance * | instance, |
| void * | buf, | ||
| size_t | size, | ||
| int | flags, | ||
| struct ast_sockaddr * | sa, | ||
| int | rtcp | ||
| ) | [static] |
Definition at line 374 of file res_rtp_asterisk.c.
References ast_rtp_instance_get_data(), ast_rtp_instance_get_srtp(), ast_sendto(), ast_srtp::buf, len(), ast_srtp_res::protect, ast_rtp::rtcp, ast_rtp::s, and ast_rtcp::s.
Referenced by rtcp_sendto(), and rtp_sendto().
{
int len = size;
void *temp = buf;
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance);
if (res_srtp && srtp && res_srtp->protect(srtp, &temp, &len, rtcp) < 0) {
return -1;
}
return ast_sendto(rtcp ? rtp->rtcp->s : rtp->s, temp, len, flags, sa);
}
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 2975 of file res_rtp_asterisk.c.
| static unsigned int ast_rtcp_calc_interval | ( | struct ast_rtp * | rtp | ) | [static] |
Definition at line 403 of file res_rtp_asterisk.c.
References rtcpinterval.
Referenced by ast_rtp_raw_write(), and ast_rtp_read().
{
unsigned int interval;
/*! \todo XXX Do a more reasonable calculation on this one
* Look in RFC 3550 Section A.7 for an example*/
interval = rtcpinterval;
return interval;
}
| static struct ast_frame* ast_rtcp_read | ( | struct ast_rtp_instance * | instance | ) | [static, read] |
Definition at line 1699 of file res_rtp_asterisk.c.
References ast_rtcp::accumulated_transit, ast_assert, AST_CONTROL_VIDUPDATE, ast_debug, AST_FRAME_CONTROL, AST_FRIENDLY_OFFSET, ast_log(), ast_null_frame, ast_rtp_instance_get_data(), ast_rtp_instance_get_prop(), AST_RTP_PROPERTY_NAT, ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_stringify(), ast_verbose(), ast_frame::datalen, errno, EVENT_FLAG_REPORTING, ast_rtp::f, f, ast_frame::frametype, ast_frame_subclass::integer, LOG_DEBUG, LOG_WARNING, ast_frame::mallocd, manager_event, ast_rtcp::maxrtt, ast_rtcp::minrtt, normdev_compute(), ast_rtcp::normdevrtt, option_debug, ast_rtcp::reported_jitter, ast_rtcp::reported_jitter_count, ast_rtcp::reported_lost, ast_rtcp::reported_maxjitter, ast_rtcp::reported_maxlost, ast_rtcp::reported_minjitter, ast_rtcp::reported_minlost, ast_rtcp::reported_normdev_jitter, ast_rtcp::reported_normdev_lost, ast_rtcp::reported_stdev_jitter, ast_rtcp::reported_stdev_lost, ast_rtp::rtcp, rtcp_debug_test_addr(), ast_rtcp::rtcp_info, RTCP_PT_BYE, RTCP_PT_FUR, RTCP_PT_RR, RTCP_PT_SDES, RTCP_PT_SR, rtcp_recvfrom(), ast_rtcp::rtt, ast_rtcp::rtt_count, ast_rtcp::rxlsr, ast_frame::samples, ast_rtcp::soc, ast_rtcp::spc, ast_frame::src, stddev_compute(), ast_rtcp::stdevrtt, ast_frame::subclass, ast_rtcp::them, ast_rtcp::themrxlsr, and timeval2ntp().
Referenced by ast_rtp_read().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr addr;
unsigned int rtcpdata[8192 + AST_FRIENDLY_OFFSET];
unsigned int *rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET);
int res, packetwords, position = 0;
struct ast_frame *f = &ast_null_frame;
/* Read in RTCP data from the socket */
if ((res = rtcp_recvfrom(instance, rtcpdata + AST_FRIENDLY_OFFSET,
sizeof(rtcpdata) - sizeof(unsigned int) * AST_FRIENDLY_OFFSET,
0, &addr)) < 0) {
ast_assert(errno != EBADF);
if (errno != EAGAIN) {
ast_log(LOG_WARNING, "RTCP Read error: %s. Hanging up.\n", strerror(errno));
return NULL;
}
return &ast_null_frame;
}
packetwords = res / 4;
if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {
/* Send to whoever sent to us */
if (ast_sockaddr_cmp(&rtp->rtcp->them, &addr)) {
ast_sockaddr_copy(&rtp->rtcp->them, &addr);
if (option_debug || rtpdebug)
ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n",
ast_sockaddr_stringify(&rtp->rtcp->them));
}
}
ast_debug(1, "Got RTCP report of %d bytes\n", res);
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;
i = position;
length = ntohl(rtcpheader[i]);
pt = (length & 0xff0000) >> 16;
rc = (length & 0x1f000000) >> 24;
length &= 0xffff;
if ((i + length) > packetwords) {
if (option_debug || rtpdebug)
ast_log(LOG_DEBUG, "RTCP Read too short\n");
return &ast_null_frame;
}
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("Reception reports: %d\n", rc);
ast_verbose("SSRC of sender: %u\n", rtcpheader[i + 1]);
}
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); /* To be able to populate the dlsr */
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*/
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]));
}
i += 5;
if (rc < 1)
break;
/* 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 (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;
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]) & 0xffff) >> 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]) & 0xffff) >> 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]) & 0xffff) >> 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);
}
break;
case RTCP_PT_FUR:
if (rtcp_debug_test_addr(&addr))
ast_verbose("Received an RTCP Fast Update Request\n");
rtp->f.frametype = AST_FRAME_CONTROL;
rtp->f.subclass.integer = AST_CONTROL_VIDUPDATE;
rtp->f.datalen = 0;
rtp->f.samples = 0;
rtp->f.mallocd = 0;
rtp->f.src = "RTP";
f = &rtp->f;
break;
case RTCP_PT_SDES:
if (rtcp_debug_test_addr(&addr))
ast_verbose("Received an SDES from %s\n",
ast_sockaddr_stringify(&rtp->rtcp->them));
break;
case RTCP_PT_BYE:
if (rtcp_debug_test_addr(&addr))
ast_verbose("Received a BYE from %s\n",
ast_sockaddr_stringify(&rtp->rtcp->them));
break;
default:
ast_debug(1, "Unknown RTCP packet (pt=%d) received from %s\n",
pt, ast_sockaddr_stringify(&rtp->rtcp->them));
break;
}
position += (length + 1);
}
rtp->rtcp->rtcp_info = 1;
return f;
}
| static int ast_rtcp_write | ( | const void * | data | ) | [static] |
Write and RTCP packet to the far end.
Definition at line 1060 of file res_rtp_asterisk.c.
References ao2_ref, ast_rtcp_write_rr(), ast_rtcp_write_sr(), ast_rtp_instance_get_data(), ast_rtcp::lastsrtxcount, ast_rtp::rtcp, ast_rtcp::schedid, and ast_rtp::txcount.
Referenced by ast_rtp_raw_write(), and ast_rtp_read().
{
struct ast_rtp_instance *instance = (struct ast_rtp_instance *) data;
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
int res;
if (!rtp || !rtp->rtcp || rtp->rtcp->schedid == -1) {
ao2_ref(instance, -1);
return 0;
}
if (rtp->txcount > rtp->rtcp->lastsrtxcount) {
res = ast_rtcp_write_sr(instance);
} else {
res = ast_rtcp_write_rr(instance);
}
if (!res) {
/*
* Not being rescheduled.
*/
ao2_ref(instance, -1);
rtp->rtcp->schedid = -1;
}
return res;
}
| static int ast_rtcp_write_rr | ( | struct ast_rtp_instance * | instance | ) | [static] |
Send RTCP recipient's report.
Definition at line 830 of file res_rtp_asterisk.c.
References ast_log(), ast_rtp_instance_get_data(), ast_sockaddr_isnull(), ast_sockaddr_stringify(), ast_verbose(), ast_rtp::cycles, errno, ast_rtcp::expected_prior, ast_rtp::lastrxseqno, len(), LOG_ERROR, ast_rtcp::maxrxlost, ast_rtcp::minrxlost, normdev_compute(), ast_rtcp::normdev_rxlost, ast_rtcp::received_prior, ast_rtcp::rr_count, ast_rtp::rtcp, rtcp_debug_test_addr(), RTCP_PT_RR, RTCP_PT_SDES, rtcp_sendto(), ast_rtp::rxcount, ast_rtp::rxjitter, ast_rtcp::rxlost, ast_rtcp::rxlost_count, ast_rtcp::rxlsr, ast_rtp::seedrxseqno, ast_rtp::ssrc, stddev_compute(), ast_rtcp::stdev_rxlost, ast_rtcp::them, ast_rtcp::themrxlsr, ast_rtp::themssrc, and timersub().
Referenced by ast_rtcp_write().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
int res;
int len = 32;
unsigned int lost;
unsigned int extended;
unsigned int expected;
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;
double rxlost_current;
if (!rtp || !rtp->rtcp)
return 0;
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;
received_interval = rtp->rxcount - rtp->rtcp->received_prior;
rtp->rtcp->received_prior = rtp->rxcount;
lost_interval = expected_interval - received_interval;
if (lost_interval <= 0)
rtp->rtcp->rxlost = 0;
else rtp->rtcp->rxlost = rtp->rtcp->rxlost;
if (rtp->rtcp->rxlost_count == 0)
rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
if (lost_interval < rtp->rtcp->minrxlost)
rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
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);
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 * 65536.));
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;
res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &rtp->rtcp->them);
if (res < 0) {
ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted: %s\n",strerror(errno));
return 0;
}
rtp->rtcp->rr_count++;
if (rtcp_debug_test_addr(&rtp->rtcp->them)) {
ast_verbose("\n* Sending RTCP RR to %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(&rtp->rtcp->them),
rtp->ssrc, rtp->themssrc, fraction, lost,
rtp->rxjitter,
rtp->rtcp->themrxlsr,
(double)(ntohl(rtcpheader[7])/65536.0));
}
return res;
}
| static int ast_rtcp_write_sr | ( | struct ast_rtp_instance * | instance | ) | [static] |
Send RTCP sender's report.
Definition at line 931 of file res_rtp_asterisk.c.
References ast_log(), ast_rtp_instance_get_data(), ast_sockaddr_isnull(), ast_sockaddr_stringify(), ast_verbose(), ast_rtp::cycles, errno, EVENT_FLAG_REPORTING, ast_rtcp::expected_prior, ast_rtp::lastrxseqno, ast_rtcp::lastsrtxcount, ast_rtp::lastts, len(), LOG_ERROR, manager_event, ast_rtcp::received_prior, ast_rtp::rtcp, rtcp_debug_test_addr(), RTCP_PT_SDES, RTCP_PT_SR, rtcp_sendto(), ast_rtp::rxcount, ast_rtp::rxjitter, ast_rtcp::rxlsr, ast_rtp::seedrxseqno, ast_rtcp::sr_count, ast_rtp::ssrc, ast_rtcp::them, ast_rtcp::themrxlsr, ast_rtp::themssrc, timersub(), timeval2ntp(), ast_rtp::txcount, ast_rtcp::txlsr, and ast_rtp::txoctetcount.
Referenced by ast_rtcp_write().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
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;
char bdata[512];
if (!rtp || !rtp->rtcp)
return 0;
if (ast_sockaddr_isnull(&rtp->rtcp->them)) { /* This'll stop rtcp for this rtp session */
/*
* RTCP was stopped.
*/
return 0;
}
gettimeofday(&now, NULL);
timeval2ntp(now, &now_msw, &now_lsw); /* fill thses ones in from utils.c*/
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 * 65536.));
rtcpheader[11] = htonl(rtp->rtcp->themrxlsr);
rtcpheader[12] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
len += 24;
rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_SR << 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 */
len += 12;
res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &rtp->rtcp->them);
if (res < 0) {
ast_log(LOG_ERROR, "RTCP SR transmission error to %s, rtcp halted %s\n",
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;
if (rtcp_debug_test_addr(&rtp->rtcp->them)) {
ast_verbose("* Sent RTCP SR to %s\n", ast_sockaddr_stringify(&rtp->rtcp->them));
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(" 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(&rtp->rtcp->them),
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));
return res;
}
| static void ast_rtp_alt_remote_address_set | ( | struct ast_rtp_instance * | instance, |
| struct ast_sockaddr * | addr | ||
| ) | [static] |
Definition at line 2504 of file res_rtp_asterisk.c.
References ast_rtp::alt_rtp_address, ast_rtp_instance_get_data(), and ast_sockaddr_copy().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
/* No need to futz with rtp->rtcp here because ast_rtcp_read is already able to adjust if receiving
* RTCP from an "unexpected" source
*/
ast_sockaddr_copy(&rtp->alt_rtp_address, addr);
return;
}
| static void ast_rtp_change_source | ( | struct ast_rtp_instance * | instance | ) | [static] |
Definition at line 774 of file res_rtp_asterisk.c.
References ast_debug, ast_random(), ast_rtp_instance_get_data(), ast_rtp_instance_get_srtp(), ast_set_flag, ast_srtp_res::change_source, FLAG_NEED_MARKER_BIT, ast_rtp::lastts, and ast_rtp::ssrc.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance);
unsigned int ssrc = ast_random();
if (!rtp->lastts) {
ast_debug(3, "Not changing SSRC since we haven't sent any RTP yet\n");
return;
}
/* We simply set this bit so that the next packet sent will have the marker bit turned on */
ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
ast_debug(3, "Changing ssrc from %u to %u due to a source change\n", rtp->ssrc, ssrc);
if (srtp) {
ast_debug(3, "Changing ssrc for SRTP from %u to %u\n", rtp->ssrc, ssrc);
res_srtp->change_source(srtp, rtp->ssrc, ssrc);
}
rtp->ssrc = ssrc;
return;
}
| static int ast_rtp_destroy | ( | struct ast_rtp_instance * | instance | ) | [static] |
Definition at line 525 of file res_rtp_asterisk.c.
References ast_free, ast_rtp_instance_get_data(), AST_SCHED_DEL, ast_smoother_free(), ast_rtp::red, ast_rtp::rtcp, ast_rtp::s, ast_rtcp::s, ast_rtp::sched, rtp_red::schedid, and ast_rtp::smoother.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
/* Destroy the smoother that was smoothing out audio if present */
if (rtp->smoother) {
ast_smoother_free(rtp->smoother);
}
/* Close our own socket so we no longer get packets */
if (rtp->s > -1) {
close(rtp->s);
}
/* Destroy RTCP if it was being used */
if (rtp->rtcp) {
/*
* It is not possible for there to be an active RTCP scheduler
* entry at this point since it holds a reference to the
* RTP instance while it's active.
*/
close(rtp->rtcp->s);
ast_free(rtp->rtcp);
}
/* Destroy RED if it was being used */
if (rtp->red) {
AST_SCHED_DEL(rtp->sched, rtp->red->schedid);
ast_free(rtp->red);
}
/* Finally destroy ourselves */
ast_free(rtp);
return 0;
}
| static int ast_rtp_dtmf_begin | ( | struct ast_rtp_instance * | instance, |
| char | digit | ||
| ) | [static] |
Definition at line 575 of file res_rtp_asterisk.c.
References ast_log(), ast_rtp_codecs_payload_code(), AST_RTP_DTMF, ast_rtp_instance_get_codecs(), ast_rtp_instance_get_data(), ast_rtp_instance_get_remote_address(), ast_sockaddr_isnull(), ast_sockaddr_stringify(), ast_tv(), ast_tvadd(), ast_tvnow(), ast_verbose(), ast_rtp::dtmfmute, errno, ast_rtp::lastdigitts, ast_rtp::lastts, LOG_ERROR, LOG_WARNING, rtp_debug_test_addr(), rtp_sendto(), ast_rtp::send_digit, ast_rtp::send_duration, ast_rtp::send_payload, ast_rtp::sending_digit, ast_rtp::seqno, and ast_rtp::ssrc.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr remote_address = { {0,} };
int hdrlen = 12, res = 0, i = 0, payload = 101;
char data[256];
unsigned int *rtpheader = (unsigned int*)data;
ast_rtp_instance_get_remote_address(instance, &remote_address);
/* If we have no remote address information bail out now */
if (ast_sockaddr_isnull(&remote_address)) {
return -1;
}
/* Convert given digit into what we want to transmit */
if ((digit <= '9') && (digit >= '0')) {
digit -= '0';
} else if (digit == '*') {
digit = 10;
} else if (digit == '#') {
digit = 11;
} else if ((digit >= 'A') && (digit <= 'D')) {
digit = digit - 'A' + 12;
} else if ((digit >= 'a') && (digit <= 'd')) {
digit = digit - 'a' + 12;
} else {
ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
return -1;
}
/* Grab the payload that they expect the RFC2833 packet to be received in */
payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 0, AST_RTP_DTMF);
rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
rtp->send_duration = 160;
rtp->lastdigitts = rtp->lastts + rtp->send_duration;
/* Create the actual packet that we will be sending */
rtpheader[0] = htonl((2 << 30) | (1 << 23) | (payload << 16) | (rtp->seqno));
rtpheader[1] = htonl(rtp->lastdigitts);
rtpheader[2] = htonl(rtp->ssrc);
/* Actually send the packet */
for (i = 0; i < 2; i++) {
rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (rtp->send_duration));
res = rtp_sendto(instance, (void *) rtpheader, hdrlen + 4, 0, &remote_address);
if (res < 0) {
ast_log(LOG_ERROR, "RTP Transmission error to %s: %s\n",
ast_sockaddr_stringify(&remote_address),
strerror(errno));
}
if (rtp_debug_test_addr(&remote_address)) {
ast_verbose("Sent RTP DTMF packet to %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
ast_sockaddr_stringify(&remote_address),
payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
}
rtp->seqno++;
rtp->send_duration += 160;
rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno));
}
/* Record that we are in the process of sending a digit and information needed to continue doing so */
rtp->sending_digit = 1;
rtp->send_digit = digit;
rtp->send_payload = payload;
return 0;
}
| static int ast_rtp_dtmf_compatible | ( | struct ast_channel * | chan0, |
| struct ast_rtp_instance * | instance0, | ||
| struct ast_channel * | chan1, | ||
| struct ast_rtp_instance * | instance1 | ||
| ) | [static] |
Definition at line 2635 of file res_rtp_asterisk.c.
References ast_rtp_instance_get_prop(), AST_RTP_PROPERTY_DTMF, ast_channel_tech::send_digit_begin, and ast_channel::tech.
{
/* If both sides are not using the same method of DTMF transmission
* (ie: one is RFC2833, other is INFO... then we can not do direct media.
* --------------------------------------------------
* | DTMF Mode | HAS_DTMF | Accepts Begin Frames |
* |-----------|------------|-----------------------|
* | Inband | False | True |
* | RFC2833 | True | True |
* | SIP INFO | False | False |
* --------------------------------------------------
*/
return (((ast_rtp_instance_get_prop(instance0, AST_RTP_PROPERTY_DTMF) != ast_rtp_instance_get_prop(instance1, AST_RTP_PROPERTY_DTMF)) ||
(!chan0->tech->send_digit_begin != !chan1->tech->send_digit_begin)) ? 0 : 1);
}
| static int ast_rtp_dtmf_continuation | ( | struct ast_rtp_instance * | instance | ) | [static] |
Definition at line 645 of file res_rtp_asterisk.c.
References ast_log(), ast_rtp_instance_get_data(), ast_rtp_instance_get_remote_address(), ast_sockaddr_isnull(), ast_sockaddr_stringify(), ast_verbose(), errno, ast_rtp::lastdigitts, LOG_ERROR, rtp_debug_test_addr(), rtp_sendto(), ast_rtp::send_digit, ast_rtp::send_duration, ast_rtp::send_payload, ast_rtp::seqno, and ast_rtp::ssrc.
Referenced by ast_rtp_read().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr remote_address = { {0,} };
int hdrlen = 12, res = 0;
char data[256];
unsigned int *rtpheader = (unsigned int*)data;
ast_rtp_instance_get_remote_address(instance, &remote_address);
/* Make sure we know where the other side is so we can send them the packet */
if (ast_sockaddr_isnull(&remote_address)) {
return -1;
}
/* Actually create the packet we will be sending */
rtpheader[0] = htonl((2 << 30) | (1 << 23) | (rtp->send_payload << 16) | (rtp->seqno));
rtpheader[1] = htonl(rtp->lastdigitts);
rtpheader[2] = htonl(rtp->ssrc);
rtpheader[3] = htonl((rtp->send_digit << 24) | (0xa << 16) | (rtp->send_duration));
rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno));
/* Boom, send it on out */
res = rtp_sendto(instance, (void *) rtpheader, hdrlen + 4, 0, &remote_address);
if (res < 0) {
ast_log(LOG_ERROR, "RTP Transmission error to %s: %s\n",
ast_sockaddr_stringify(&remote_address),
strerror(errno));
}
if (rtp_debug_test_addr(&remote_address)) {
ast_verbose("Sent RTP DTMF packet to %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
ast_sockaddr_stringify(&remote_address),
rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
}
/* And now we increment some values for the next time we swing by */
rtp->seqno++;
rtp->send_duration += 160;
return 0;
}
| static int ast_rtp_dtmf_end | ( | struct ast_rtp_instance * | instance, |
| char | digit | ||
| ) | [static] |
Definition at line 758 of file res_rtp_asterisk.c.
References ast_rtp_dtmf_end_with_duration().
{
return ast_rtp_dtmf_end_with_duration(instance, digit, 0);
}
| static int ast_rtp_dtmf_end_with_duration | ( | struct ast_rtp_instance * | instance, |
| char | digit, | ||
| unsigned int | duration | ||
| ) | [static] |
Definition at line 688 of file res_rtp_asterisk.c.
References ast_debug, ast_log(), ast_rtp_instance_get_data(), ast_rtp_instance_get_remote_address(), ast_sockaddr_isnull(), ast_sockaddr_stringify(), ast_tv(), ast_tvadd(), ast_tvnow(), ast_verbose(), ast_frame_subclass::codec, ast_rtp::dtmfmute, errno, ast_rtp::f, ast_rtp::lastdigitts, ast_rtp::lastts, LOG_ERROR, LOG_WARNING, rtp_debug_test_addr(), rtp_get_rate(), rtp_sendto(), ast_rtp::send_digit, ast_rtp::send_duration, ast_rtp::send_payload, ast_rtp::sending_digit, ast_rtp::seqno, ast_rtp::ssrc, and ast_frame::subclass.
Referenced by ast_rtp_dtmf_end().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr remote_address = { {0,} };
int hdrlen = 12, res = 0, i = 0;
char data[256];
unsigned int *rtpheader = (unsigned int*)data;
unsigned int measured_samples;
ast_rtp_instance_get_remote_address(instance, &remote_address);
/* Make sure we know where the remote side is so we can send them the packet we construct */
if (ast_sockaddr_isnull(&remote_address)) {
return -1;
}
/* Convert the given digit to the one we are going to send */
if ((digit <= '9') && (digit >= '0')) {
digit -= '0';
} else if (digit == '*') {
digit = 10;
} else if (digit == '#') {
digit = 11;
} else if ((digit >= 'A') && (digit <= 'D')) {
digit = digit - 'A' + 12;
} else if ((digit >= 'a') && (digit <= 'd')) {
digit = digit - 'a' + 12;
} else {
ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
return -1;
}
rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
if (duration > 0 && (measured_samples = duration * rtp_get_rate(rtp->f.subclass.codec) / 1000) > rtp->send_duration) {
ast_debug(2, "Adjusting final end duration from %u to %u\n", rtp->send_duration, measured_samples);
rtp->send_duration = measured_samples;
}
/* Construct the packet we are going to send */
rtpheader[0] = htonl((2 << 30) | (1 << 23) | (rtp->send_payload << 16) | (rtp->seqno));
rtpheader[1] = htonl(rtp->lastdigitts);
rtpheader[2] = htonl(rtp->ssrc);
rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (rtp->send_duration));
rtpheader[3] |= htonl((1 << 23));
rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno));
/* Send it 3 times, that's the magical number */
for (i = 0; i < 3; i++) {
res = rtp_sendto(instance, (void *) rtpheader, hdrlen + 4, 0, &remote_address);
if (res < 0) {
ast_log(LOG_ERROR, "RTP Transmission error to %s: %s\n",
ast_sockaddr_stringify(&remote_address),
strerror(errno));
}
if (rtp_debug_test_addr(&remote_address)) {
ast_verbose("Sent RTP DTMF packet to %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
ast_sockaddr_stringify(&remote_address),
rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
}
}
/* Oh and we can't forget to turn off the stuff that says we are sending DTMF */
rtp->lastts += rtp->send_duration;
rtp->sending_digit = 0;
rtp->send_digit = 0;
return 0;
}
| static enum ast_rtp_dtmf_mode ast_rtp_dtmf_mode_get | ( | struct ast_rtp_instance * | instance | ) | [static] |
Definition at line 569 of file res_rtp_asterisk.c.
References ast_rtp_instance_get_data(), and ast_rtp::dtmfmode.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
return rtp->dtmfmode;
}
| static int ast_rtp_dtmf_mode_set | ( | struct ast_rtp_instance * | instance, |
| enum ast_rtp_dtmf_mode | dtmf_mode | ||
| ) | [static] |
Definition at line 562 of file res_rtp_asterisk.c.
References ast_rtp_instance_get_data(), and ast_rtp::dtmfmode.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
rtp->dtmfmode = dtmf_mode;
return 0;
}
| static int ast_rtp_fd | ( | struct ast_rtp_instance * | instance, |
| int | rtcp | ||
| ) | [static] |
Definition at line 2475 of file res_rtp_asterisk.c.
References ast_rtp_instance_get_data(), ast_rtp::rtcp, ast_rtp::s, and ast_rtcp::s.
| static int ast_rtp_get_stat | ( | struct ast_rtp_instance * | instance, |
| struct ast_rtp_instance_stats * | stats, | ||
| enum ast_rtp_instance_stat | stat | ||
| ) | [static] |
Definition at line 2587 of file res_rtp_asterisk.c.
References ast_rtp_instance_get_data(), AST_RTP_INSTANCE_STAT_COMBINED_JITTER, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, AST_RTP_INSTANCE_STAT_COMBINED_RTT, AST_RTP_INSTANCE_STAT_LOCAL_MAXJITTER, AST_RTP_INSTANCE_STAT_LOCAL_MAXRXPLOSS, AST_RTP_INSTANCE_STAT_LOCAL_MINJITTER, AST_RTP_INSTANCE_STAT_LOCAL_MINRXPLOSS, AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVJITTER, AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVRXPLOSS, AST_RTP_INSTANCE_STAT_LOCAL_SSRC, AST_RTP_INSTANCE_STAT_LOCAL_STDEVJITTER, AST_RTP_INSTANCE_STAT_LOCAL_STDEVRXPLOSS, AST_RTP_INSTANCE_STAT_MAX_RTT, AST_RTP_INSTANCE_STAT_MIN_RTT, AST_RTP_INSTANCE_STAT_NORMDEVRTT, AST_RTP_INSTANCE_STAT_REMOTE_MAXJITTER, AST_RTP_INSTANCE_STAT_REMOTE_MAXRXPLOSS, AST_RTP_INSTANCE_STAT_REMOTE_MINJITTER, AST_RTP_INSTANCE_STAT_REMOTE_MINRXPLOSS, AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVJITTER, AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVRXPLOSS, AST_RTP_INSTANCE_STAT_REMOTE_SSRC, AST_RTP_INSTANCE_STAT_REMOTE_STDEVJITTER, AST_RTP_INSTANCE_STAT_REMOTE_STDEVRXPLOSS, AST_RTP_INSTANCE_STAT_RTT, AST_RTP_INSTANCE_STAT_RXCOUNT, AST_RTP_INSTANCE_STAT_RXJITTER, AST_RTP_INSTANCE_STAT_RXPLOSS, AST_RTP_INSTANCE_STAT_STDEVRTT, AST_RTP_INSTANCE_STAT_TXCOUNT, AST_RTP_INSTANCE_STAT_TXJITTER, AST_RTP_INSTANCE_STAT_TXPLOSS, AST_RTP_STAT_SET, AST_RTP_STAT_TERMINATOR, ast_rtcp::expected_prior, ast_rtp_instance_stats::local_maxjitter, ast_rtp_instance_stats::local_maxrxploss, ast_rtp_instance_stats::local_minjitter, ast_rtp_instance_stats::local_minrxploss, ast_rtp_instance_stats::local_normdevjitter, ast_rtp_instance_stats::local_normdevrxploss, ast_rtp_instance_stats::local_ssrc, ast_rtp_instance_stats::local_stdevjitter, ast_rtp_instance_stats::local_stdevrxploss, ast_rtcp::maxrtt, ast_rtp_instance_stats::maxrtt, ast_rtcp::maxrxjitter, ast_rtcp::maxrxlost, ast_rtcp::minrtt, ast_rtp_instance_stats::minrtt, ast_rtcp::minrxjitter, ast_rtcp::minrxlost, ast_rtcp::normdev_rxjitter, ast_rtcp::normdev_rxlost, ast_rtcp::normdevrtt, ast_rtp_instance_stats::normdevrtt, ast_rtcp::received_prior, ast_rtp_instance_stats::remote_maxjitter, ast_rtp_instance_stats::remote_maxrxploss, ast_rtp_instance_stats::remote_minjitter, ast_rtp_instance_stats::remote_minrxploss, ast_rtp_instance_stats::remote_normdevjitter, ast_rtp_instance_stats::remote_normdevrxploss, ast_rtp_instance_stats::remote_ssrc, ast_rtp_instance_stats::remote_stdevjitter, ast_rtp_instance_stats::remote_stdevrxploss, ast_rtcp::reported_jitter, ast_rtcp::reported_lost, ast_rtcp::reported_maxjitter, ast_rtcp::reported_maxlost, ast_rtcp::reported_minjitter, ast_rtcp::reported_minlost, ast_rtcp::reported_normdev_jitter, ast_rtcp::reported_normdev_lost, ast_rtcp::reported_stdev_jitter, ast_rtcp::reported_stdev_lost, ast_rtp::rtcp, ast_rtcp::rtt, ast_rtp_instance_stats::rtt, ast_rtp::rxcount, ast_rtp_instance_stats::rxcount, ast_rtp::rxjitter, ast_rtp_instance_stats::rxjitter, ast_rtp_instance_stats::rxploss, ast_rtp::ssrc, ast_rtcp::stdev_rxjitter, ast_rtcp::stdev_rxlost, ast_rtcp::stdevrtt, ast_rtp_instance_stats::stdevrtt, ast_rtp::themssrc, ast_rtp::txcount, ast_rtp_instance_stats::txcount, ast_rtp_instance_stats::txjitter, and ast_rtp_instance_stats::txploss.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
if (!rtp->rtcp) {
return -1;
}
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXCOUNT, -1, stats->txcount, rtp->txcount);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXCOUNT, -1, stats->rxcount, rtp->rxcount);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->txploss, rtp->rtcp->reported_lost);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->rxploss, rtp->rtcp->expected_prior - rtp->rtcp->received_prior);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MAXRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->remote_maxrxploss, rtp->rtcp->reported_maxlost);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MINRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->remote_minrxploss, rtp->rtcp->reported_minlost);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->remote_normdevrxploss, rtp->rtcp->reported_normdev_lost);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_STDEVRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->remote_stdevrxploss, rtp->rtcp->reported_stdev_lost);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MAXRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->local_maxrxploss, rtp->rtcp->maxrxlost);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MINRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->local_minrxploss, rtp->rtcp->minrxlost);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->local_normdevrxploss, rtp->rtcp->normdev_rxlost);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_STDEVRXPLOSS, AST_RTP_INSTANCE_STAT_COMBINED_LOSS, stats->local_stdevrxploss, rtp->rtcp->stdev_rxlost);
AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_LOSS);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_TXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->txjitter, rtp->rxjitter);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->rxjitter, rtp->rtcp->reported_jitter / (unsigned int) 65536.0);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MAXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_maxjitter, rtp->rtcp->reported_maxjitter);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_MINJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_minjitter, rtp->rtcp->reported_minjitter);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_NORMDEVJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_normdevjitter, rtp->rtcp->reported_normdev_jitter);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_REMOTE_STDEVJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->remote_stdevjitter, rtp->rtcp->reported_stdev_jitter);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MAXJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->local_maxjitter, rtp->rtcp->maxrxjitter);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_MINJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->local_minjitter, rtp->rtcp->minrxjitter);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_NORMDEVJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->local_normdevjitter, rtp->rtcp->normdev_rxjitter);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_LOCAL_STDEVJITTER, AST_RTP_INSTANCE_STAT_COMBINED_JITTER, stats->local_stdevjitter, rtp->rtcp->stdev_rxjitter);
AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_JITTER);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_RTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->rtt, rtp->rtcp->rtt);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_MAX_RTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->maxrtt, rtp->rtcp->maxrtt);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_MIN_RTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->minrtt, rtp->rtcp->minrtt);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_NORMDEVRTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->normdevrtt, rtp->rtcp->normdevrtt);
AST_RTP_STAT_SET(AST_RTP_INSTANCE_STAT_STDEVRTT, AST_RTP_INSTANCE_STAT_COMBINED_RTT, stats->stdevrtt, rtp->rtcp->stdevrtt);
AST_RTP_STAT_TERMINATOR(AST_RTP_INSTANCE_STAT_COMBINED_RTT);
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);
return 0;
}
| static int ast_rtp_local_bridge | ( | struct ast_rtp_instance * | instance0, |
| struct ast_rtp_instance * | instance1 | ||
| ) | [static] |
Definition at line 2578 of file res_rtp_asterisk.c.
References ast_rtp_instance_get_data(), ast_set_flag, and FLAG_NEED_MARKER_BIT.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance0);
ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
return 0;
}
| static int ast_rtp_new | ( | struct ast_rtp_instance * | instance, |
| struct sched_context * | sched, | ||
| struct ast_sockaddr * | addr, | ||
| void * | data | ||
| ) | [static] |
Definition at line 463 of file res_rtp_asterisk.c.
References ast_bind(), ast_calloc, ast_debug, ast_free, ast_log(), ast_random(), ast_rtp_instance_set_data(), ast_rtp_instance_set_local_address(), ast_sockaddr_is_ipv4(), ast_sockaddr_is_ipv6(), ast_sockaddr_set_port, create_new_socket(), errno, LOG_ERROR, rtpstart, ast_rtp::s, ast_rtp::sched, sched, ast_rtp::seqno, ast_rtp::ssrc, STRICT_RTP_LEARN, STRICT_RTP_OPEN, and ast_rtp::strict_rtp_state.
{
struct ast_rtp *rtp = NULL;
int x, startplace;
/* Create a new RTP structure to hold all of our data */
if (!(rtp = ast_calloc(1, sizeof(*rtp)))) {
return -1;
}
/* Set default parameters on the newly created RTP structure */
rtp->ssrc = ast_random();
rtp->seqno = ast_random() & 0xffff;
rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN);
/* Create a new socket for us to listen on and use */
if ((rtp->s =
create_new_socket("RTP",
ast_sockaddr_is_ipv4(addr) ? AF_INET :
ast_sockaddr_is_ipv6(addr) ? AF_INET6 : -1)) < 0) {
ast_debug(1, "Failed to create a new socket for RTP instance '%p'\n", instance);
ast_free(rtp);
return -1;
}
/* Now actually find a free RTP port to use */
x = (rtpend == rtpstart) ? rtpstart : (ast_random() % (rtpend - rtpstart)) + rtpstart;
x = x & ~1;
startplace = x;
for (;;) {
ast_sockaddr_set_port(addr, x);
/* Try to bind, this will tell us whether the port is available or not */
if (!ast_bind(rtp->s, addr)) {
ast_debug(1, "Allocated port %d for RTP instance '%p'\n", x, instance);
ast_rtp_instance_set_local_address(instance, addr);
break;
}
x += 2;
if (x > rtpend) {
x = (rtpstart + 1) & ~1;
}
/* See if we ran out of ports or if the bind actually failed because of something other than the address being in use */
if (x == startplace || errno != EADDRINUSE) {
ast_log(LOG_ERROR, "Oh dear... we couldn't allocate a port for RTP instance '%p'\n", instance);
return -1;
}
}
/* Record any information we may need */
rtp->sched = sched;
/* Associate the RTP structure with the RTP instance and be done */
ast_rtp_instance_set_data(instance, rtp);
return 0;
}
| static void ast_rtp_prop_set | ( | struct ast_rtp_instance * | instance, |
| enum ast_rtp_property | property, | ||
| int | value | ||
| ) | [static] |
Definition at line 2406 of file res_rtp_asterisk.c.
References ao2_ref, ast_bind(), ast_calloc, ast_debug, ast_free, ast_rtp_instance_get_data(), ast_rtp_instance_get_local_address(), AST_RTP_PROPERTY_RTCP, ast_sched_del(), ast_sockaddr_is_ipv4(), ast_sockaddr_is_ipv6(), ast_sockaddr_port, ast_sockaddr_set_port, create_new_socket(), ast_rtp::rtcp, ast_rtcp::s, ast_rtp::sched, ast_rtcp::schedid, and ast_rtcp::us.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
if (property == AST_RTP_PROPERTY_RTCP) {
if (value) {
if (rtp->rtcp) {
ast_debug(1, "Ignoring duplicate RTCP property on RTP instance '%p'\n", instance);
return;
}
/* Setup RTCP to be activated on the next RTP write */
if (!(rtp->rtcp = ast_calloc(1, sizeof(*rtp->rtcp)))) {
return;
}
/* Grab the IP address and port we are going to use */
ast_rtp_instance_get_local_address(instance, &rtp->rtcp->us);
ast_sockaddr_set_port(&rtp->rtcp->us,
ast_sockaddr_port(&rtp->rtcp->us) + 1);
if ((rtp->rtcp->s =
create_new_socket("RTCP",
ast_sockaddr_is_ipv4(&rtp->rtcp->us) ?
AF_INET :
ast_sockaddr_is_ipv6(&rtp->rtcp->us) ?
AF_INET6 : -1)) < 0) {
ast_debug(1, "Failed to create a new socket for RTCP on instance '%p'\n", instance);
ast_free(rtp->rtcp);
rtp->rtcp = NULL;
return;
}
/* Try to actually bind to the IP address and port we are going to use for RTCP, if this fails we have to bail out */
if (ast_bind(rtp->rtcp->s, &rtp->rtcp->us)) {
ast_debug(1, "Failed to setup RTCP on RTP instance '%p'\n", instance);
close(rtp->rtcp->s);
ast_free(rtp->rtcp);
rtp->rtcp = NULL;
return;
}
ast_debug(1, "Setup RTCP on RTP instance '%p'\n", instance);
rtp->rtcp->schedid = -1;
return;
} else {
if (rtp->rtcp) {
if (rtp->rtcp->schedid > 0) {
if (!ast_sched_del(rtp->sched, rtp->rtcp->schedid)) {
/* Successfully cancelled scheduler entry. */
ao2_ref(instance, -1);
} else {
/* Unable to cancel scheduler entry */
ast_debug(1, "Failed to tear down RTCP on RTP instance '%p'\n", instance);
return;
}
rtp->rtcp->schedid = -1;
}
close(rtp->rtcp->s);
ast_free(rtp->rtcp);
rtp->rtcp = NULL;
}
return;
}
}
return;
}
| static int ast_rtp_qos_set | ( | struct ast_rtp_instance * | instance, |
| int | tos, | ||
| int | cos, | ||
| const char * | desc | ||
| ) | [static] |
Definition at line 2688 of file res_rtp_asterisk.c.
References ast_rtp_instance_get_data(), ast_set_qos(), and ast_rtp::s.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
return ast_set_qos(rtp->s, tos, cos, desc);
}
| static int ast_rtp_raw_write | ( | struct ast_rtp_instance * | instance, |
| struct ast_frame * | frame, | ||
| int | codec | ||
| ) | [static] |
Definition at line 1088 of file res_rtp_asterisk.c.
References ao2_ref, ast_clear_flag, ast_debug, AST_FORMAT_G722, AST_FRAME_VIDEO, AST_FRAME_VOICE, AST_FRFLAG_HAS_TIMING_INFO, ast_log(), ast_rtcp_calc_interval(), ast_rtcp_write(), ast_rtp_instance_get_data(), ast_rtp_instance_get_prop(), ast_rtp_instance_get_remote_address(), AST_RTP_PROPERTY_NAT, ast_sched_add(), ast_set_flag, ast_sockaddr_isnull(), ast_sockaddr_stringify(), ast_test_flag, ast_tvzero(), ast_verbose(), calc_txstamp(), ast_frame_subclass::codec, ast_frame::data, ast_frame::datalen, ast_frame::delivery, errno, FLAG_NAT_ACTIVE, FLAG_NAT_INACTIVE, FLAG_NAT_INACTIVE_NOWARN, FLAG_NEED_MARKER_BIT, ast_frame::frametype, ast_rtp::lastdigitts, ast_rtp::lastotexttimestamp, ast_rtp::lastovidtimestamp, ast_rtp::lastts, LOG_WARNING, MAX_TIMESTAMP_SKEW, option_debug, ast_frame::ptr, put_unaligned_uint32(), ast_rtp::rtcp, rtp_debug_test_addr(), rtp_get_rate(), rtp_sendto(), ast_frame::samples, ast_rtp::sched, ast_rtcp::schedid, ast_rtp::sending_digit, ast_rtp::seqno, ast_rtp::ssrc, ast_frame::subclass, ast_frame::ts, ast_rtp::txcount, and ast_rtp::txoctetcount.
Referenced by ast_rtp_write().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
int pred, mark = 0;
unsigned int ms = calc_txstamp(rtp, &frame->delivery);
struct ast_sockaddr remote_address = { {0,} };
int rate = rtp_get_rate(frame->subclass.codec) / 1000;
if (frame->subclass.codec == AST_FORMAT_G722) {
frame->samples /= 2;
}
if (rtp->sending_digit) {
return 0;
}
if (frame->frametype == AST_FRAME_VOICE) {
pred = rtp->lastts + frame->samples;
/* Re-calculate last TS */
rtp->lastts = rtp->lastts + ms * rate;
if (ast_tvzero(frame->delivery)) {
/* If this isn't an absolute delivery time, Check if it is close to our prediction,
and if so, go with our prediction */
if (abs(rtp->lastts - pred) < MAX_TIMESTAMP_SKEW) {
rtp->lastts = pred;
} else {
ast_debug(3, "Difference is %d, ms is %d\n", abs(rtp->lastts - pred), ms);
mark = 1;
}
}
} else if (frame->frametype == AST_FRAME_VIDEO) {
mark = frame->subclass.codec & 0x1;
pred = rtp->lastovidtimestamp + frame->samples;
/* Re-calculate last TS */
rtp->lastts = rtp->lastts + ms * 90;
/* If it's close to our prediction, go for it */
if (ast_tvzero(frame->delivery)) {
if (abs(rtp->lastts - pred) < 7200) {
rtp->lastts = pred;
rtp->lastovidtimestamp += frame->samples;
} else {
ast_debug(3, "Difference is %d, ms is %d (%d), pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, frame->samples);
rtp->lastovidtimestamp = rtp->lastts;
}
}
} else {
pred = rtp->lastotexttimestamp + frame->samples;
/* Re-calculate last TS */
rtp->lastts = rtp->lastts + ms;
/* If it's close to our prediction, go for it */
if (ast_tvzero(frame->delivery)) {
if (abs(rtp->lastts - pred) < 7200) {
rtp->lastts = pred;
rtp->lastotexttimestamp += frame->samples;
} else {
ast_debug(3, "Difference is %d, ms is %d, pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, rtp->lastts, pred, frame->samples);
rtp->lastotexttimestamp = rtp->lastts;
}
}
}
/* If we have been explicitly told to set the marker bit then do so */
if (ast_test_flag(rtp, FLAG_NEED_MARKER_BIT)) {
mark = 1;
ast_clear_flag(rtp, FLAG_NEED_MARKER_BIT);
}
/* If the timestamp for non-digt packets has moved beyond the timestamp for digits, update the digit timestamp */
if (rtp->lastts > rtp->lastdigitts) {
rtp->lastdigitts = rtp->lastts;
}
if (ast_test_flag(frame, AST_FRFLAG_HAS_TIMING_INFO)) {
rtp->lastts = frame->ts * rate;
}
ast_rtp_instance_get_remote_address(instance, &remote_address);
/* If we know the remote address construct a packet and send it out */
if (!ast_sockaddr_isnull(&remote_address)) {
int hdrlen = 12, res;
unsigned char *rtpheader = (unsigned char *)(frame->data.ptr - hdrlen);
put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (rtp->seqno) | (mark << 23)));
put_unaligned_uint32(rtpheader + 4, htonl(rtp->lastts));
put_unaligned_uint32(rtpheader + 8, htonl(rtp->ssrc));
if ((res = rtp_sendto(instance, (void *)rtpheader, frame->datalen + hdrlen, 0, &remote_address)) < 0) {
if (!ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT) || (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT) && (ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
ast_debug(1, "RTP Transmission error of packet %d to %s: %s\n",
rtp->seqno,
ast_sockaddr_stringify(&remote_address),
strerror(errno));
} else if (((ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(rtp, FLAG_NAT_INACTIVE_NOWARN)) {
/* Only give this error message once if we are not RTP debugging */
if (option_debug || rtpdebug)
ast_debug(0, "RTP NAT: Can't write RTP to private address %s, waiting for other end to send audio...\n",
ast_sockaddr_stringify(&remote_address));
ast_set_flag(rtp, FLAG_NAT_INACTIVE_NOWARN);
}
} else {
rtp->txcount++;
rtp->txoctetcount += (res - hdrlen);
if (rtp->rtcp && rtp->rtcp->schedid < 1) {
ast_debug(1, "Starting RTCP transmission on RTP instance '%p'\n", instance);
ao2_ref(instance, +1);
rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance);
if (rtp->rtcp->schedid < 0) {
ao2_ref(instance, -1);
ast_log(LOG_WARNING, "scheduling RTCP transmission failed.\n");
}
}
}
if (rtp_debug_test_addr(&remote_address)) {
ast_verbose("Sent RTP packet to %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
ast_sockaddr_stringify(&remote_address),
codec, rtp->seqno, rtp->lastts, res - hdrlen);
}
}
rtp->seqno++;
return 0;
}
| static struct ast_frame * ast_rtp_read | ( | struct ast_rtp_instance * | instance, |
| int | rtcp | ||
| ) | [static, read] |
Definition at line 2039 of file res_rtp_asterisk.c.
References ast_rtp::alt_rtp_address, ao2_ref, ast_assert, ast_codec_get_samples(), AST_CONTROL_SRCCHANGE, ast_debug, AST_FORMAT_AUDIO_MASK, ast_format_rate(), AST_FORMAT_SLINEAR, AST_FORMAT_SLINEAR16, AST_FORMAT_T140, AST_FORMAT_T140RED, AST_FORMAT_VIDEO_MASK, ast_frame_byteswap_be, AST_FRAME_CONTROL, AST_FRAME_DTMF_END, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, AST_FRFLAG_HAS_TIMING_INFO, AST_FRIENDLY_OFFSET, ast_frisolate(), AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, ast_log(), ast_null_frame, ast_rtcp_calc_interval(), ast_rtcp_read(), ast_rtcp_write(), AST_RTP_CISCO_DTMF, AST_RTP_CN, ast_rtp_codecs_payload_lookup(), AST_RTP_DTMF, ast_rtp_dtmf_continuation(), ast_rtp_instance_get_bridged(), ast_rtp_instance_get_codecs(), ast_rtp_instance_get_data(), ast_rtp_instance_get_prop(), ast_rtp_instance_get_remote_address(), ast_rtp_instance_set_remote_address(), AST_RTP_PROPERTY_NAT, ast_samp2tv(), ast_sched_add(), ast_set_flag, ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_from_sin, ast_sockaddr_ipv4_mapped(), ast_sockaddr_is_ipv4(), ast_sockaddr_isnull(), ast_sockaddr_port, ast_sockaddr_set_port, ast_sockaddr_stringify(), ast_sockaddr_to_sin, ast_strdupa, AST_STUN_ACCEPT, ast_stun_handle_packet(), ast_tv(), ast_tvdiff_ms(), ast_verbose(), ast_rtp_payload_type::asterisk_format, bridge_p2p_rtp_write(), calc_rxstamp(), ast_rtp_payload_type::code, ast_frame_subclass::codec, create_dtmf_frame(), ast_rtp::cycles, ast_frame::data, ast_frame::datalen, ast_frame::delivery, ast_rtp::dtmf_duration, ast_rtp::dtmf_timeout, errno, ext, ast_rtp::f, f, FLAG_NAT_ACTIVE, ast_frame::frametype, ast_rtp::lastitexttimestamp, ast_rtp::lastividtimestamp, ast_rtp::lastrxformat, ast_rtp::lastrxseqno, ast_rtp::lastrxts, ast_frame::len, len(), LOG_NOTICE, LOG_WARNING, ast_frame::mallocd, ast_frame::offset, option_debug, process_cn_rfc3389(), process_dtmf_cisco(), process_dtmf_rfc2833(), ast_frame::ptr, ast_rtp::rawdata, ast_rtp::resp, ast_rtp::rtcp, rtp_debug_test_addr(), rtp_get_rate(), rtp_recvfrom(), RTP_SEQ_MOD, ast_rtp::rxcount, ast_rtp::rxseqno, ast_rtp::rxssrc, ast_rtp::s, ast_frame::samples, ast_rtp::sched, ast_rtcp::schedid, ast_rtp::seedrxseqno, ast_rtp::sending_digit, ast_frame::seqno, ast_frame::src, ast_rtp::strict_rtp_address, STRICT_RTP_CLOSED, STRICT_RTP_LEARN, ast_rtp::strict_rtp_state, ast_frame::subclass, ast_rtcp::them, ast_rtp::themssrc, ast_frame::ts, and version.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr addr;
int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno;
unsigned int *rtpheader = (unsigned int*)(rtp->rawdata + AST_FRIENDLY_OFFSET), seqno, ssrc, timestamp;
struct ast_rtp_payload_type payload;
struct ast_sockaddr remote_address = { {0,} };
struct frame_list frames;
/* If this is actually RTCP let's hop on over and handle it */
if (rtcp) {
if (rtp->rtcp) {
return ast_rtcp_read(instance);
}
return &ast_null_frame;
}
/* If we are currently sending DTMF to the remote party send a continuation packet */
if (rtp->sending_digit) {
ast_rtp_dtmf_continuation(instance);
}
/* Actually read in the data from the socket */
if ((res = rtp_recvfrom(instance, rtp->rawdata + AST_FRIENDLY_OFFSET,
sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET, 0,
&addr)) < 0) {
ast_assert(errno != EBADF);
if (errno != EAGAIN) {
ast_log(LOG_WARNING, "RTP Read error: %s. Hanging up.\n", strerror(errno));
return NULL;
}
return &ast_null_frame;
}
/* Make sure the data that was read in is actually enough to make up an RTP packet */
if (res < hdrlen) {
ast_log(LOG_WARNING, "RTP Read too short\n");
return &ast_null_frame;
}
/* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */
if (rtp->strict_rtp_state == STRICT_RTP_LEARN) {
ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
rtp->strict_rtp_state = STRICT_RTP_CLOSED;
} else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) {
if (ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
/* Hmm, not the strict addres. Perhaps we're getting audio from the alternate? */
if (!ast_sockaddr_cmp(&rtp->alt_rtp_address, &addr)) {
/* ooh, we did! You're now the new expected address, son! */
ast_sockaddr_copy(&rtp->strict_rtp_address,
&addr);
} else {
const char *real_addr = ast_strdupa(ast_sockaddr_stringify(&addr));
const char *expected_addr = ast_strdupa(ast_sockaddr_stringify(&rtp->strict_rtp_address));
ast_debug(1, "Received RTP packet from %s, dropping due to strict RTP protection. Expected it to be from %s\n",
real_addr, expected_addr);
return &ast_null_frame;
}
}
}
/* Get fields and verify this is an RTP packet */
seqno = ntohl(rtpheader[0]);
ast_rtp_instance_get_remote_address(instance, &remote_address);
if (!(version = (seqno & 0xC0000000) >> 30)) {
struct sockaddr_in addr_tmp;
struct ast_sockaddr addr_v4;
if (ast_sockaddr_is_ipv4(&addr)) {
ast_sockaddr_to_sin(&addr, &addr_tmp);
} else if (ast_sockaddr_ipv4_mapped(&addr, &addr_v4)) {
ast_debug(1, "Using IPv6 mapped address %s for STUN\n",
ast_sockaddr_stringify(&addr));
ast_sockaddr_to_sin(&addr_v4, &addr_tmp);
} else {
ast_debug(1, "Cannot do STUN for non IPv4 address %s\n",
ast_sockaddr_stringify(&addr));
return &ast_null_frame;
}
if ((ast_stun_handle_packet(rtp->s, &addr_tmp, rtp->rawdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == AST_STUN_ACCEPT) &&
ast_sockaddr_isnull(&remote_address)) {
ast_sockaddr_from_sin(&addr, &addr_tmp);
ast_rtp_instance_set_remote_address(instance, &addr);
}
return &ast_null_frame;
}
/* If symmetric RTP is enabled see if the remote side is not what we expected and change where we are sending audio */
if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {
if (ast_sockaddr_cmp(&remote_address, &addr)) {
ast_rtp_instance_set_remote_address(instance, &addr);
ast_sockaddr_copy(&remote_address, &addr);
if (rtp->rtcp) {
ast_sockaddr_copy(&rtp->rtcp->them, &addr);
ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(&addr) + 1);
}
rtp->rxseqno = 0;
ast_set_flag(rtp, FLAG_NAT_ACTIVE);
if (option_debug || rtpdebug)
ast_debug(0, "RTP NAT: Got audio from other end. Now sending to address %s\n",
ast_sockaddr_stringify(&remote_address));
}
}
/* If we are directly bridged to another instance send the audio directly out */
if (ast_rtp_instance_get_bridged(instance) && !bridge_p2p_rtp_write(instance, rtpheader, res, hdrlen)) {
return &ast_null_frame;
}
/* If the version is not what we expected by this point then just drop the packet */
if (version != 2) {
return &ast_null_frame;
}
/* Pull out the various other fields we will need */
payloadtype = (seqno & 0x7f0000) >> 16;
padding = seqno & (1 << 29);
mark = seqno & (1 << 23);
ext = seqno & (1 << 28);
cc = (seqno & 0xF000000) >> 24;
seqno &= 0xffff;
timestamp = ntohl(rtpheader[1]);
ssrc = ntohl(rtpheader[2]);
AST_LIST_HEAD_INIT_NOLOCK(&frames);
/* Force a marker bit and change SSRC if the SSRC changes */
if (rtp->rxssrc && rtp->rxssrc != ssrc) {
struct ast_frame *f, srcupdate = {
AST_FRAME_CONTROL,
.subclass.integer = AST_CONTROL_SRCCHANGE,
};
if (!mark) {
if (option_debug || rtpdebug) {
ast_debug(1, "Forcing Marker bit, because SSRC has changed\n");
}
mark = 1;
}
f = ast_frisolate(&srcupdate);
AST_LIST_INSERT_TAIL(&frames, f, frame_list);
}
rtp->rxssrc = ssrc;
/* Remove any padding bytes that may be present */
if (padding) {
res -= rtp->rawdata[AST_FRIENDLY_OFFSET + res - 1];
}
/* Skip over any CSRC fields */
if (cc) {
hdrlen += cc * 4;
}
/* Look for any RTP extensions, currently we do not support any */
if (ext) {
hdrlen += (ntohl(rtpheader[hdrlen/4]) & 0xffff) << 2;
hdrlen += 4;
if (option_debug) {
int profile;
profile = (ntohl(rtpheader[3]) & 0xffff0000) >> 16;
if (profile == 0x505a)
ast_debug(1, "Found Zfone extension in RTP stream - zrtp - not supported.\n");
else
ast_debug(1, "Found unknown RTP Extensions %x\n", profile);
}
}
/* Make sure after we potentially mucked with the header length that it is once again valid */
if (res < hdrlen) {
ast_log(LOG_WARNING, "RTP Read too short (%d, expecting %d\n", res, hdrlen);
return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
}
rtp->rxcount++;
if (rtp->rxcount == 1) {
rtp->seedrxseqno = seqno;
}
/* Do not schedule RR if RTCP isn't run */
if (rtp->rtcp && !ast_sockaddr_isnull(&rtp->rtcp->them) && rtp->rtcp->schedid < 1) {
/* Schedule transmission of Receiver Report */
ao2_ref(instance, +1);
rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance);
if (rtp->rtcp->schedid < 0) {
ao2_ref(instance, -1);
ast_log(LOG_WARNING, "scheduling RTCP transmission failed.\n");
}
}
if ((int)rtp->lastrxseqno - (int)seqno > 100) /* if so it would indicate that the sender cycled; allow for misordering */
rtp->cycles += RTP_SEQ_MOD;
prev_seqno = rtp->lastrxseqno;
rtp->lastrxseqno = seqno;
if (!rtp->themssrc) {
rtp->themssrc = ntohl(rtpheader[2]); /* Record their SSRC to put in future RR */
}
if (rtp_debug_test_addr(&addr)) {
ast_verbose("Got RTP packet from %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
ast_sockaddr_stringify(&addr),
payloadtype, seqno, timestamp,res - hdrlen);
}
payload = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(instance), payloadtype);
/* If the payload is not actually an Asterisk one but a special one pass it off to the respective handler */
if (!payload.asterisk_format) {
struct ast_frame *f = NULL;
if (payload.code == AST_RTP_DTMF) {
/* process_dtmf_rfc2833 may need to return multiple frames. We do this
* by passing the pointer to the frame list to it so that the method
* can append frames to the list as needed.
*/
process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark, &frames);
} else if (payload.code == AST_RTP_CISCO_DTMF) {
f = process_dtmf_cisco(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);
} else if (payload.code == AST_RTP_CN) {
f = process_cn_rfc3389(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);
} else {
ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n",
payloadtype,
ast_sockaddr_stringify(&remote_address));
}
if (f) {
AST_LIST_INSERT_TAIL(&frames, f, frame_list);
}
/* Even if no frame was returned by one of the above methods,
* we may have a frame to return in our frame list
*/
if (!AST_LIST_EMPTY(&frames)) {
return AST_LIST_FIRST(&frames);
}
return &ast_null_frame;
}
rtp->lastrxformat = rtp->f.subclass.codec = payload.code;
rtp->f.frametype = (rtp->f.subclass.codec & AST_FORMAT_AUDIO_MASK) ? AST_FRAME_VOICE : (rtp->f.subclass.codec & AST_FORMAT_VIDEO_MASK) ? AST_FRAME_VIDEO : AST_FRAME_TEXT;
rtp->rxseqno = seqno;
if (rtp->dtmf_timeout && rtp->dtmf_timeout < timestamp) {
rtp->dtmf_timeout = 0;
if (rtp->resp) {
struct ast_frame *f;
f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0);
f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.codec)), ast_tv(0, 0));
rtp->resp = 0;
rtp->dtmf_timeout = rtp->dtmf_duration = 0;
AST_LIST_INSERT_TAIL(&frames, f, frame_list);
return AST_LIST_FIRST(&frames);
}
}
rtp->lastrxts = timestamp;
rtp->f.src = "RTP";
rtp->f.mallocd = 0;
rtp->f.datalen = res - hdrlen;
rtp->f.data.ptr = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
rtp->f.seqno = seqno;
if (rtp->f.subclass.codec == AST_FORMAT_T140 && (int)seqno - (prev_seqno+1) > 0 && (int)seqno - (prev_seqno+1) < 10) {
unsigned char *data = rtp->f.data.ptr;
memmove(rtp->f.data.ptr+3, rtp->f.data.ptr, rtp->f.datalen);
rtp->f.datalen +=3;
*data++ = 0xEF;
*data++ = 0xBF;
*data = 0xBD;
}
if (rtp->f.subclass.codec == AST_FORMAT_T140RED) {
unsigned char *data = rtp->f.data.ptr;
unsigned char *header_end;
int num_generations;
int header_length;
int len;
int diff =(int)seqno - (prev_seqno+1); /* if diff = 0, no drop*/
int x;
rtp->f.subclass.codec = AST_FORMAT_T140;
header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen);
if (header_end == NULL) {
return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
}
header_end++;
header_length = header_end - data;
num_generations = header_length / 4;
len = header_length;
if (!diff) {
for (x = 0; x < num_generations; x++)
len += data[x * 4 + 3];
if (!(rtp->f.datalen - len))
return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
rtp->f.data.ptr += len;
rtp->f.datalen -= len;
} else if (diff > num_generations && diff < 10) {
len -= 3;
rtp->f.data.ptr += len;
rtp->f.datalen -= len;
data = rtp->f.data.ptr;
*data++ = 0xEF;
*data++ = 0xBF;
*data = 0xBD;
} else {
for ( x = 0; x < num_generations - diff; x++)
len += data[x * 4 + 3];
rtp->f.data.ptr += len;
rtp->f.datalen -= len;
}
}
if (rtp->f.subclass.codec & AST_FORMAT_AUDIO_MASK) {
rtp->f.samples = ast_codec_get_samples(&rtp->f);
if ((rtp->f.subclass.codec == AST_FORMAT_SLINEAR) || (rtp->f.subclass.codec == AST_FORMAT_SLINEAR16)) {
ast_frame_byteswap_be(&rtp->f);
}
calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
/* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.codec) / 1000);
rtp->f.len = rtp->f.samples / ((ast_format_rate(rtp->f.subclass.codec) / 1000));
} else if (rtp->f.subclass.codec & AST_FORMAT_VIDEO_MASK) {
/* Video -- samples is # of samples vs. 90000 */
if (!rtp->lastividtimestamp)
rtp->lastividtimestamp = timestamp;
rtp->f.samples = timestamp - rtp->lastividtimestamp;
rtp->lastividtimestamp = timestamp;
rtp->f.delivery.tv_sec = 0;
rtp->f.delivery.tv_usec = 0;
/* Pass the RTP marker bit as bit 0 in the subclass field.
* This is ok because subclass is actually a bitmask, and
* the low bits represent audio formats, that are not
* involved here since we deal with video.
*/
if (mark)
rtp->f.subclass.codec |= 0x1;
} else {
/* TEXT -- samples is # of samples vs. 1000 */
if (!rtp->lastitexttimestamp)
rtp->lastitexttimestamp = timestamp;
rtp->f.samples = timestamp - rtp->lastitexttimestamp;
rtp->lastitexttimestamp = timestamp;
rtp->f.delivery.tv_sec = 0;
rtp->f.delivery.tv_usec = 0;
}
AST_LIST_INSERT_TAIL(&frames, &rtp->f, frame_list);
return AST_LIST_FIRST(&frames);
}
| static void ast_rtp_remote_address_set | ( | struct ast_rtp_instance * | instance, |
| struct ast_sockaddr * | addr | ||
| ) | [static] |
Definition at line 2482 of file res_rtp_asterisk.c.
References ast_debug, ast_rtp_instance_get_data(), ast_sockaddr_copy(), ast_sockaddr_isnull(), ast_sockaddr_port, ast_sockaddr_set_port, ast_rtp::rtcp, ast_rtp::rxseqno, STRICT_RTP_LEARN, ast_rtp::strict_rtp_state, and ast_rtcp::them.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
if (rtp->rtcp) {
ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance);
ast_sockaddr_copy(&rtp->rtcp->them, addr);
if (!ast_sockaddr_isnull(addr)) {
ast_sockaddr_set_port(&rtp->rtcp->them,
ast_sockaddr_port(addr) + 1);
}
}
rtp->rxseqno = 0;
if (strictrtp) {
rtp->strict_rtp_state = STRICT_RTP_LEARN;
}
return;
}
| static int ast_rtp_sendcng | ( | struct ast_rtp_instance * | instance, |
| int | level | ||
| ) | [static] |
generate comfort noice (CNG)
Definition at line 2696 of file res_rtp_asterisk.c.
References ast_log(), AST_RTP_CN, ast_rtp_codecs_payload_lookup(), ast_rtp_instance_get_codecs(), ast_rtp_instance_get_data(), ast_rtp_instance_get_remote_address(), ast_sockaddr_isnull(), ast_sockaddr_stringify(), ast_tv(), ast_tvadd(), ast_tvnow(), ast_verbose(), ast_rtp_payload_type::code, ast_rtp::dtmfmute, errno, ast_rtp::lastdigitts, ast_rtp::lastts, LOG_ERROR, rtp_debug_test_addr(), rtp_sendto(), ast_rtp::seqno, and ast_rtp::ssrc.
{
unsigned int *rtpheader;
int hdrlen = 12;
int res;
struct ast_rtp_payload_type payload;
char data[256];
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr remote_address = { {0,} };
ast_rtp_instance_get_remote_address(instance, &remote_address);
if (ast_sockaddr_isnull(&remote_address)) {
return -1;
}
payload = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(instance), AST_RTP_CN);
level = 127 - (level & 0x7f);
rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
/* Get a pointer to the header */
rtpheader = (unsigned int *)data;
rtpheader[0] = htonl((2 << 30) | (1 << 23) | (payload.code << 16) | (rtp->seqno++));
rtpheader[1] = htonl(rtp->lastts);
rtpheader[2] = htonl(rtp->ssrc);
data[12] = level;
res = rtp_sendto(instance, (void *) rtpheader, hdrlen + 1, 0, &remote_address);
if (res < 0) {
ast_log(LOG_ERROR, "RTP Comfort Noise Transmission error to %s: %s\n", ast_sockaddr_stringify(&remote_address), strerror(errno));
} else if (rtp_debug_test_addr(&remote_address)) {
ast_verbose("Sent Comfort Noise RTP packet to %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
ast_sockaddr_stringify(&remote_address),
AST_RTP_CN, rtp->seqno, rtp->lastdigitts, res - hdrlen);
}
return res;
}
| static void ast_rtp_stop | ( | struct ast_rtp_instance * | instance | ) | [static] |
Definition at line 2661 of file res_rtp_asterisk.c.
References ao2_ref, ast_rtp_instance_get_data(), ast_rtp_instance_set_remote_address(), AST_SCHED_DEL, ast_sched_del(), ast_set_flag, ast_sockaddr_setnull(), FLAG_NEED_MARKER_BIT, free, ast_rtp::red, ast_rtp::rtcp, ast_rtp::sched, ast_rtcp::schedid, rtp_red::schedid, and ast_rtcp::them.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr addr = { {0,} };
if (rtp->rtcp && rtp->rtcp->schedid > 0) {
if (!ast_sched_del(rtp->sched, rtp->rtcp->schedid)) {
/* successfully cancelled scheduler entry. */
ao2_ref(instance, -1);
}
rtp->rtcp->schedid = -1;
}
if (rtp->red) {
AST_SCHED_DEL(rtp->sched, rtp->red->schedid);
free(rtp->red);
rtp->red = NULL;
}
ast_rtp_instance_set_remote_address(instance, &addr);
if (rtp->rtcp) {
ast_sockaddr_setnull(&rtp->rtcp->them);
}
ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
}
| static void ast_rtp_stun_request | ( | struct ast_rtp_instance * | instance, |
| struct ast_sockaddr * | suggestion, | ||
| const char * | username | ||
| ) | [static] |
Definition at line 2651 of file res_rtp_asterisk.c.
References ast_rtp_instance_get_data(), ast_sockaddr_from_sin, ast_sockaddr_to_sin, ast_stun_request(), and ast_rtp::s.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct sockaddr_in suggestion_tmp;
ast_sockaddr_to_sin(suggestion, &suggestion_tmp);
ast_stun_request(rtp->s, &suggestion_tmp, username, NULL);
ast_sockaddr_from_sin(suggestion, &suggestion_tmp);
}
| static void ast_rtp_update_source | ( | struct ast_rtp_instance * | instance | ) | [static] |
Definition at line 763 of file res_rtp_asterisk.c.
References ast_debug, ast_rtp_instance_get_data(), ast_set_flag, and FLAG_NEED_MARKER_BIT.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
/* We simply set this bit so that the next packet sent will have the marker bit turned on */
ast_set_flag(rtp, FLAG_NEED_MARKER_BIT);
ast_debug(3, "Setting the marker bit due to a source update\n");
return;
}
| static int ast_rtp_write | ( | struct ast_rtp_instance * | instance, |
| struct ast_frame * | frame | ||
| ) | [static] |
Definition at line 1253 of file res_rtp_asterisk.c.
References ast_codec_pref_getsize(), ast_debug, AST_FORMAT_G719, AST_FORMAT_G723_1, AST_FORMAT_SIREN14, AST_FORMAT_SIREN7, AST_FORMAT_SPEEX, AST_FORMAT_SPEEX16, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frdup(), ast_frfree, ast_getformatname(), ast_log(), ast_rtp_codecs_payload_code(), ast_rtp_instance_get_codecs(), ast_rtp_instance_get_data(), ast_rtp_instance_get_remote_address(), ast_rtp_raw_write(), ast_smoother_feed, ast_smoother_feed_be, AST_SMOOTHER_FLAG_BE, ast_smoother_free(), ast_smoother_new(), ast_smoother_read(), ast_smoother_set_flags(), ast_smoother_test_flag(), ast_sockaddr_isnull(), ast_frame_subclass::codec, ast_format_list::cur_ms, ast_frame::data, ast_frame::datalen, f, ast_format_list::flags, ast_format_list::fr_len, ast_frame::frametype, ast_format_list::inc_ms, ast_rtp::lasttxformat, LOG_WARNING, ast_frame::offset, ast_frame::ptr, ast_rtp::red, red_t140_to_red(), ast_rtp::smoother, and ast_frame::subclass.
Referenced by red_write().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr remote_address = { {0,} };
format_t codec, subclass;
ast_rtp_instance_get_remote_address(instance, &remote_address);
/* If we don't actually know the remote address don't even bother doing anything */
if (ast_sockaddr_isnull(&remote_address)) {
ast_debug(1, "No remote address on RTP instance '%p' so dropping frame\n", instance);
return 0;
}
/* If there is no data length we can't very well send the packet */
if (!frame->datalen) {
ast_debug(1, "Received frame with no data for RTP instance '%p' so dropping frame\n", instance);
return 0;
}
/* If the packet is not one our RTP stack supports bail out */
if (frame->frametype != AST_FRAME_VOICE && frame->frametype != AST_FRAME_VIDEO && frame->frametype != AST_FRAME_TEXT) {
ast_log(LOG_WARNING, "RTP can only send voice, video, and text\n");
return -1;
}
if (rtp->red) {
/* return 0; */
/* no primary data or generations to send */
if ((frame = red_t140_to_red(rtp->red)) == NULL)
return 0;
}
/* Grab the subclass and look up the payload we are going to use */
subclass = frame->subclass.codec;
if (frame->frametype == AST_FRAME_VIDEO) {
subclass &= ~0x1LL;
}
if ((codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance), 1, subclass)) < 0) {
ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", ast_getformatname(frame->subclass.codec));
return -1;
}
/* Oh dear, if the format changed we will have to set up a new smoother */
if (rtp->lasttxformat != subclass) {
ast_debug(1, "Ooh, format changed from %s to %s\n", ast_getformatname(rtp->lasttxformat), ast_getformatname(subclass));
rtp->lasttxformat = subclass;
if (rtp->smoother) {
ast_smoother_free(rtp->smoother);
rtp->smoother = NULL;
}
}
/* If no smoother is present see if we have to set one up */
if (!rtp->smoother) {
struct ast_format_list fmt = ast_codec_pref_getsize(&ast_rtp_instance_get_codecs(instance)->pref, subclass);
switch (subclass) {
case AST_FORMAT_SPEEX:
case AST_FORMAT_SPEEX16:
case AST_FORMAT_G723_1:
case AST_FORMAT_SIREN7:
case AST_FORMAT_SIREN14:
case AST_FORMAT_G719:
/* these are all frame-based codecs and cannot be safely run through
a smoother */
break;
default:
if (fmt.inc_ms) {
if (!(rtp->smoother = ast_smoother_new((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms))) {
ast_log(LOG_WARNING, "Unable to create smoother: format %s ms: %d len: %d\n", ast_getformatname(subclass), fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
return -1;
}
if (fmt.flags) {
ast_smoother_set_flags(rtp->smoother, fmt.flags);
}
ast_debug(1, "Created smoother: format: %s ms: %d len: %d\n", ast_getformatname(subclass), fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
}
}
}
/* Feed audio frames into the actual function that will create a frame and send it */
if (rtp->smoother) {
struct ast_frame *f;
if (ast_smoother_test_flag(rtp->smoother, AST_SMOOTHER_FLAG_BE)) {
ast_smoother_feed_be(rtp->smoother, frame);
} else {
ast_smoother_feed(rtp->smoother, frame);
}
while ((f = ast_smoother_read(rtp->smoother)) && (f->data.ptr)) {
ast_rtp_raw_write(instance, f, codec);
}
} else {
int hdrlen = 12;
struct ast_frame *f = NULL;
if (frame->offset < hdrlen) {
f = ast_frdup(frame);
} else {
f = frame;
}
if (f->data.ptr) {
ast_rtp_raw_write(instance, f, codec);
}
if (f != frame) {
ast_frfree(f);
}
}
return 0;
}
| static int bridge_p2p_rtp_write | ( | struct ast_rtp_instance * | instance, |
| unsigned int * | rtpheader, | ||
| int | len, | ||
| int | hdrlen | ||
| ) | [static] |
Definition at line 1969 of file res_rtp_asterisk.c.
References ast_clear_flag, ast_debug, ast_log(), ast_rtp_codecs_payload_code(), ast_rtp_codecs_payload_lookup(), ast_rtp_instance_get_bridged(), ast_rtp_instance_get_codecs(), ast_rtp_instance_get_data(), ast_rtp_instance_get_prop(), ast_rtp_instance_get_remote_address(), AST_RTP_PROPERTY_NAT, ast_set_flag, ast_sockaddr_isnull(), ast_sockaddr_stringify(), ast_test_flag, ast_verbose(), ast_rtp_payload_type::asterisk_format, ast_rtp::bridged, ast_rtp_payload_type::code, errno, FLAG_NAT_ACTIVE, FLAG_NAT_INACTIVE, FLAG_NAT_INACTIVE_NOWARN, FLAG_NEED_MARKER_BIT, LOG_WARNING, option_debug, reconstruct(), rtp_debug_test_addr(), and rtp_sendto().
Referenced by ast_rtp_read().
{
struct ast_rtp_instance *instance1 = ast_rtp_instance_get_bridged(instance);
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance), *bridged = ast_rtp_instance_get_data(instance1);
int res = 0, payload = 0, bridged_payload = 0, mark;
struct ast_rtp_payload_type payload_type;
int reconstruct = ntohl(rtpheader[0]);
struct ast_sockaddr remote_address = { {0,} };
/* Get fields from packet */
payload = (reconstruct & 0x7f0000) >> 16;
mark = (((reconstruct & 0x800000) >> 23) != 0);
/* Check what the payload value should be */
payload_type = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(instance), payload);
/* Otherwise adjust bridged payload to match */
bridged_payload = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(instance1), payload_type.asterisk_format, payload_type.code);
/* If the payload coming in is not one of the negotiated ones then send it to the core, this will cause formats to change and the bridge to break */
if (!(ast_rtp_instance_get_codecs(instance1)->payloads[bridged_payload].code)) {
return -1;
}
/* If the marker bit has been explicitly set turn it on */
if (ast_test_flag(rtp, FLAG_NEED_MARKER_BIT)) {
mark = 1;
ast_clear_flag(rtp, FLAG_NEED_MARKER_BIT);
}
/* Reconstruct part of the packet */
reconstruct &= 0xFF80FFFF;
reconstruct |= (bridged_payload << 16);
reconstruct |= (mark << 23);
rtpheader[0] = htonl(reconstruct);
ast_rtp_instance_get_remote_address(instance1, &remote_address);
if (ast_sockaddr_isnull(&remote_address)) {
ast_debug(1, "Remote address is null, most likely RTP has been stopped\n");
return 0;
}
/* Send the packet back out */
res = rtp_sendto(instance1, (void *)rtpheader, len, 0, &remote_address);
if (res < 0) {
if (!ast_rtp_instance_get_prop(instance1, AST_RTP_PROPERTY_NAT) || (ast_rtp_instance_get_prop(instance1, AST_RTP_PROPERTY_NAT) && (ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
ast_log(LOG_WARNING,
"RTP Transmission error of packet to %s: %s\n",
ast_sockaddr_stringify(&remote_address),
strerror(errno));
} else if (((ast_test_flag(bridged, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(bridged, FLAG_NAT_INACTIVE_NOWARN)) {
if (option_debug || rtpdebug)
ast_log(LOG_WARNING,
"RTP NAT: Can't write RTP to private "
"address %s, waiting for other end to "
"send audio...\n",
ast_sockaddr_stringify(&remote_address));
ast_set_flag(bridged, FLAG_NAT_INACTIVE_NOWARN);
}
return 0;
} else if (rtp_debug_test_addr(&remote_address)) {
ast_verbose("Sent RTP P2P packet to %s (type %-2.2d, len %-6.6u)\n",
ast_sockaddr_stringify(&remote_address),
bridged_payload, len - hdrlen);
}
return 0;
}
| static void calc_rxstamp | ( | struct timeval * | tv, |
| struct ast_rtp * | rtp, | ||
| unsigned int | timestamp, | ||
| int | mark | ||
| ) | [static] |
Definition at line 1368 of file res_rtp_asterisk.c.
References ast_samp2tv(), ast_tvadd(), ast_tvsub(), ast_frame_subclass::codec, ast_rtp::drxcore, ast_rtp::f, ast_rtcp::maxrxjitter, ast_rtcp::minrxjitter, normdev_compute(), ast_rtcp::normdev_rxjitter, ast_rtp::rtcp, rtp_get_rate(), ast_rtp::rxcore, ast_rtp::rxjitter, ast_rtcp::rxjitter_count, ast_rtp::rxtransit, ast_rtp::seedrxts, stddev_compute(), ast_rtcp::stdev_rxjitter, and ast_frame::subclass.
Referenced by ast_rtp_read().
{
struct timeval now;
struct timeval tmp;
double transit;
double current_time;
double d;
double dtv;
double prog;
int rate = rtp_get_rate(rtp->f.subclass.codec);
double normdev_rxjitter_current;
if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) {
gettimeofday(&rtp->rxcore, NULL);
rtp->drxcore = (double) rtp->rxcore.tv_sec + (double) rtp->rxcore.tv_usec / 1000000;
/* map timestamp to a real time */
rtp->seedrxts = timestamp; /* Their RTP timestamp started with this */
tmp = ast_samp2tv(timestamp, rate);
rtp->rxcore = ast_tvsub(rtp->rxcore, tmp);
/* Round to 0.1ms for nice, pretty timestamps */
rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 100;
}
gettimeofday(&now,NULL);
/* rxcore is the mapping between the RTP timestamp and _our_ real time from gettimeofday() */
tmp = ast_samp2tv(timestamp, rate);
*tv = ast_tvadd(rtp->rxcore, tmp);
prog = (double)((timestamp-rtp->seedrxts)/(float)(rate));
dtv = (double)rtp->drxcore + (double)(prog);
current_time = (double)now.tv_sec + (double)now.tv_usec/1000000;
transit = current_time - dtv;
d = transit - rtp->rxtransit;
rtp->rxtransit = transit;
if (d<0)
d=-d;
rtp->rxjitter += (1./16.) * (d - rtp->rxjitter);
if (rtp->rtcp) {
if (rtp->rxjitter > rtp->rtcp->maxrxjitter)
rtp->rtcp->maxrxjitter = rtp->rxjitter;
if (rtp->rtcp->rxjitter_count == 1)
rtp->rtcp->minrxjitter = rtp->rxjitter;
if (rtp->rtcp && rtp->rxjitter < rtp->rtcp->minrxjitter)
rtp->rtcp->minrxjitter = rtp->rxjitter;
normdev_rxjitter_current = normdev_compute(rtp->rtcp->normdev_rxjitter,rtp->rxjitter,rtp->rtcp->rxjitter_count);
rtp->rtcp->stdev_rxjitter = stddev_compute(rtp->rtcp->stdev_rxjitter,rtp->rxjitter,rtp->rtcp->normdev_rxjitter,normdev_rxjitter_current,rtp->rtcp->rxjitter_count);
rtp->rtcp->normdev_rxjitter = normdev_rxjitter_current;
rtp->rtcp->rxjitter_count++;
}
}
| static unsigned int calc_txstamp | ( | struct ast_rtp * | rtp, |
| struct timeval * | delivery | ||
| ) | [static] |
Definition at line 800 of file res_rtp_asterisk.c.
References ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), and ast_rtp::txcore.
Referenced by ast_rtp_raw_write().
{
struct timeval t;
long ms;
if (ast_tvzero(rtp->txcore)) {
rtp->txcore = ast_tvnow();
rtp->txcore.tv_usec -= rtp->txcore.tv_usec % 20000;
}
t = (delivery && !ast_tvzero(*delivery)) ? *delivery : ast_tvnow();
if ((ms = ast_tvdiff_ms(t, rtp->txcore)) < 0) {
ms = 0;
}
rtp->txcore = t;
return (unsigned int) ms;
}
| static struct ast_frame* create_dtmf_frame | ( | struct ast_rtp_instance * | instance, |
| enum ast_frame_type | type, | ||
| int | compensate | ||
| ) | [static, read] |
Definition at line 1422 of file res_rtp_asterisk.c.
References AST_CONTROL_FLASH, ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_LIST_NEXT, ast_null_frame, ast_rtp_instance_get_data(), ast_rtp_instance_get_remote_address(), ast_sockaddr_stringify(), ast_tvcmp(), ast_tvnow(), ast_frame::datalen, ast_rtp::dtmfmute, ast_rtp::dtmfsamples, ast_rtp::f, ast_frame::frametype, ast_frame_subclass::integer, ast_frame::mallocd, ast_rtp::resp, ast_frame::samples, ast_frame::src, ast_frame::subclass, and type.
Referenced by ast_rtp_read(), process_dtmf_cisco(), and process_dtmf_rfc2833().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr remote_address = { {0,} };
ast_rtp_instance_get_remote_address(instance, &remote_address);
if (((compensate && type == AST_FRAME_DTMF_END) || (type == AST_FRAME_DTMF_BEGIN)) && ast_tvcmp(ast_tvnow(), rtp->dtmfmute) < 0) {
ast_debug(1, "Ignore potential DTMF echo from '%s'\n",
ast_sockaddr_stringify(&remote_address));
rtp->resp = 0;
rtp->dtmfsamples = 0;
return &ast_null_frame;
}
ast_debug(1, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp,
ast_sockaddr_stringify(&remote_address));
if (rtp->resp == 'X') {
rtp->f.frametype = AST_FRAME_CONTROL;
rtp->f.subclass.integer = AST_CONTROL_FLASH;
} else {
rtp->f.frametype = type;
rtp->f.subclass.integer = rtp->resp;
}
rtp->f.datalen = 0;
rtp->f.samples = 0;
rtp->f.mallocd = 0;
rtp->f.src = "RTP";
AST_LIST_NEXT(&rtp->f, frame_list) = NULL;
return &rtp->f;
}
| static int create_new_socket | ( | const char * | type, |
| int | af | ||
| ) | [static] |
Definition at line 441 of file res_rtp_asterisk.c.
References ast_log(), errno, and LOG_WARNING.
Referenced by ast_rtp_new(), and ast_rtp_prop_set().
{
int sock = socket(af, SOCK_DGRAM, 0);
if (sock < 0) {
if (!type) {
type = "RTP/RTCP";
}
ast_log(LOG_WARNING, "Unable to allocate %s socket: %s\n", type, strerror(errno));
} else {
long flags = fcntl(sock, F_GETFL);
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
#ifdef SO_NO_CHECK
if (nochecksums) {
setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
}
#endif
}
return sock;
}
| static char* handle_cli_rtcp_set_debug | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 2805 of file res_rtp_asterisk.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, rtcp_do_debug_ip(), rtcpdebugaddr, and ast_cli_entry::usage.
{
switch (cmd) {
case CLI_INIT:
e->command = "rtcp set debug {on|off|ip}";
e->usage =
"Usage: rtcp set debug {on|off|ip host[:port]}\n"
" Enable/Disable dumping of all RTCP packets. If 'ip' is\n"
" specified, limit the dumped packets to those to and from\n"
" the specified 'host' with optional port.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc == e->args) { /* set on or off */
if (!strncasecmp(a->argv[e->args-1], "on", 2)) {
rtcpdebug = 1;
memset(&rtcpdebugaddr, 0, sizeof(rtcpdebugaddr));
ast_cli(a->fd, "RTCP Debugging Enabled\n");
return CLI_SUCCESS;
} else if (!strncasecmp(a->argv[e->args-1], "off", 3)) {
rtcpdebug = 0;
ast_cli(a->fd, "RTCP Debugging Disabled\n");
return CLI_SUCCESS;
}
} else if (a->argc == e->args +1) { /* ip */
return rtcp_do_debug_ip(a);
}
return CLI_SHOWUSAGE; /* default, failure */
}
| static char* handle_cli_rtcp_set_stats | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 2838 of file res_rtp_asterisk.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.
{
switch (cmd) {
case CLI_INIT:
e->command = "rtcp set stats {on|off}";
e->usage =
"Usage: rtcp set stats {on|off}\n"
" Enable/Disable dumping of RTCP stats.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != e->args)
return CLI_SHOWUSAGE;
if (!strncasecmp(a->argv[e->args-1], "on", 2))
rtcpstats = 1;
else if (!strncasecmp(a->argv[e->args-1], "off", 3))
rtcpstats = 0;
else
return CLI_SHOWUSAGE;
ast_cli(a->fd, "RTCP Stats %s\n", rtcpstats ? "Enabled" : "Disabled");
return CLI_SUCCESS;
}
| static char* handle_cli_rtp_set_debug | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 2772 of file res_rtp_asterisk.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, rtp_do_debug_ip(), rtpdebugaddr, and ast_cli_entry::usage.
{
switch (cmd) {
case CLI_INIT:
e->command = "rtp set debug {on|off|ip}";
e->usage =
"Usage: rtp set debug {on|off|ip host[:port]}\n"
" Enable/Disable dumping of all RTP packets. If 'ip' is\n"
" specified, limit the dumped packets to those to and from\n"
" the specified 'host' with optional port.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc == e->args) { /* set on or off */
if (!strncasecmp(a->argv[e->args-1], "on", 2)) {
rtpdebug = 1;
memset(&rtpdebugaddr, 0, sizeof(rtpdebugaddr));
ast_cli(a->fd, "RTP Debugging Enabled\n");
return CLI_SUCCESS;
} else if (!strncasecmp(a->argv[e->args-1], "off", 3)) {
rtpdebug = 0;
ast_cli(a->fd, "RTP Debugging Disabled\n");
return CLI_SUCCESS;
}
} else if (a->argc == e->args +1) { /* ip */
return rtp_do_debug_ip(a);
}
return CLI_SHOWUSAGE; /* default, failure */
}
| static int load_module | ( | void | ) | [static] |
Definition at line 2946 of file res_rtp_asterisk.c.
References ARRAY_LEN, ast_cli_register_multiple(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_rtp_engine_register, ast_rtp_engine_unregister(), and rtp_reload().
{
if (ast_rtp_engine_register(&asterisk_rtp_engine)) {
return AST_MODULE_LOAD_DECLINE;
}
if (ast_cli_register_multiple(cli_rtp, ARRAY_LEN(cli_rtp))) {
ast_rtp_engine_unregister(&asterisk_rtp_engine);
return AST_MODULE_LOAD_DECLINE;
}
rtp_reload(0);
return AST_MODULE_LOAD_SUCCESS;
}
| static double normdev_compute | ( | double | normdev, |
| double | sample, | ||
| unsigned int | sample_count | ||
| ) | [static] |
Calculate normal deviation.
Definition at line 413 of file res_rtp_asterisk.c.
Referenced by ast_rtcp_read(), ast_rtcp_write_rr(), and calc_rxstamp().
{
normdev = normdev * sample_count + sample;
sample_count++;
return normdev / sample_count;
}
| static struct ast_frame* process_cn_rfc3389 | ( | struct ast_rtp_instance * | instance, |
| unsigned char * | data, | ||
| int | len, | ||
| unsigned int | seqno, | ||
| unsigned int | timestamp, | ||
| struct ast_sockaddr * | addr, | ||
| int | payloadtype, | ||
| int | mark | ||
| ) | [static, read] |
Definition at line 1658 of file res_rtp_asterisk.c.
References ast_debug, AST_FRAME_CNG, AST_FRIENDLY_OFFSET, ast_log(), ast_rtp_instance_get_data(), ast_rtp_instance_get_remote_address(), ast_set_flag, ast_sockaddr_stringify(), ast_test_flag, ast_frame::data, ast_frame::datalen, ast_frame::delivery, ast_rtp::f, FLAG_3389_WARNING, ast_frame::frametype, ast_frame_subclass::integer, ast_rtp::lastrxformat, LOG_NOTICE, ast_frame::offset, ast_frame::ptr, ast_rtp::rawdata, ast_frame::samples, and ast_frame::subclass.
Referenced by ast_rtp_read().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
/* Convert comfort noise into audio with various codecs. Unfortunately this doesn't
totally help us out becuase we don't have an engine to keep it going and we are not
guaranteed to have it every 20ms or anything */
if (rtpdebug)
ast_debug(0, "- RTP 3389 Comfort noise event: Level %" PRId64 " (len = %d)\n", rtp->lastrxformat, len);
if (ast_test_flag(rtp, FLAG_3389_WARNING)) {
struct ast_sockaddr remote_address = { {0,} };
ast_rtp_instance_get_remote_address(instance, &remote_address);
ast_log(LOG_NOTICE, "Comfort noise support incomplete in Asterisk (RFC 3389). Please turn off on client if possible. Client address: %s\n",
ast_sockaddr_stringify(&remote_address));
ast_set_flag(rtp, FLAG_3389_WARNING);
}
/* Must have at least one byte */
if (!len)
return NULL;
if (len < 24) {
rtp->f.data.ptr = rtp->rawdata + AST_FRIENDLY_OFFSET;
rtp->f.datalen = len - 1;
rtp->f.offset = AST_FRIENDLY_OFFSET;
memcpy(rtp->f.data.ptr, data + 1, len - 1);
} else {
rtp->f.data.ptr = NULL;
rtp->f.offset = 0;
rtp->f.datalen = 0;
}
rtp->f.frametype = AST_FRAME_CNG;
rtp->f.subclass.integer = data[0] & 0x7f;
rtp->f.samples = 0;
rtp->f.delivery.tv_usec = rtp->f.delivery.tv_sec = 0;
return &rtp->f;
}
| static struct ast_frame* process_dtmf_cisco | ( | struct ast_rtp_instance * | instance, |
| unsigned char * | data, | ||
| int | len, | ||
| unsigned int | seqno, | ||
| unsigned int | timestamp, | ||
| struct ast_sockaddr * | addr, | ||
| int | payloadtype, | ||
| int | mark | ||
| ) | [static, read] |
Definition at line 1579 of file res_rtp_asterisk.c.
References ast_debug, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_rtp_instance_get_data(), ast_rtp_instance_get_prop(), AST_RTP_PROPERTY_DTMF_COMPENSATE, create_dtmf_frame(), ast_rtp::dtmf_timeout, ast_rtp::dtmfsamples, f, ast_rtp::flags, ast_rtp::lastrxformat, option_debug, ast_rtp::resp, rtp_get_rate(), ast_frame::samples, and seq.
Referenced by ast_rtp_read().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
unsigned int event, flags, power;
char resp = 0;
unsigned char seq;
struct ast_frame *f = NULL;
if (len < 4) {
return NULL;
}
/* The format of Cisco RTP DTMF packet looks like next:
+0 - sequence number of DTMF RTP packet (begins from 1,
wrapped to 0)
+1 - set of flags
+1 (bit 0) - flaps by different DTMF digits delimited by audio
or repeated digit without audio???
+2 (+4,+6,...) - power level? (rises from 0 to 32 at begin of tone
then falls to 0 at its end)
+3 (+5,+7,...) - detected DTMF digit (0..9,*,#,A-D,...)
Repeated DTMF information (bytes 4/5, 6/7) is history shifted right
by each new packet and thus provides some redudancy.
Sample of Cisco RTP DTMF packet is (all data in hex):
19 07 00 02 12 02 20 02
showing end of DTMF digit '2'.
The packets
27 07 00 02 0A 02 20 02
28 06 20 02 00 02 0A 02
shows begin of new digit '2' with very short pause (20 ms) after
previous digit '2'. Bit +1.0 flips at begin of new digit.
Cisco RTP DTMF packets comes as replacement of audio RTP packets
so its uses the same sequencing and timestamping rules as replaced
audio packets. Repeat interval of DTMF packets is 20 ms and not rely
on audio framing parameters. Marker bit isn't used within stream of
DTMFs nor audio stream coming immediately after DTMF stream. Timestamps
are not sequential at borders between DTMF and audio streams,
*/
seq = data[0];
flags = data[1];
power = data[2];
event = data[3] & 0x1f;
if (option_debug > 2 || rtpdebug)
ast_debug(0, "Cisco DTMF Digit: %02x (len=%d, seq=%d, flags=%02x, power=%d, history count=%d)\n", event, len, seq, flags, power, (len - 4) / 2);
if (event < 10) {
resp = '0' + event;
} else if (event < 11) {
resp = '*';
} else if (event < 12) {
resp = '#';
} else if (event < 16) {
resp = 'A' + (event - 12);
} else if (event < 17) {
resp = 'X';
}
if ((!rtp->resp && power) || (rtp->resp && (rtp->resp != resp))) {
rtp->resp = resp;
/* Why we should care on DTMF compensation at reception? */
if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)) {
f = create_dtmf_frame(instance, AST_FRAME_DTMF_BEGIN, 0);
rtp->dtmfsamples = 0;
}
} else if ((rtp->resp == resp) && !power) {
f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE));
f->samples = rtp->dtmfsamples * (rtp->lastrxformat ? (rtp_get_rate(rtp->lastrxformat) / 1000) : 8);
rtp->resp = 0;
} else if (rtp->resp == resp)
rtp->dtmfsamples += 20 * (rtp->lastrxformat ? (rtp_get_rate(rtp->lastrxformat) / 1000) : 8);
rtp->dtmf_timeout = 0;
return f;
}
| static void process_dtmf_rfc2833 | ( | struct ast_rtp_instance * | instance, |
| unsigned char * | data, | ||
| int | len, | ||
| unsigned int | seqno, | ||
| unsigned int | timestamp, | ||
| struct ast_sockaddr * | addr, | ||
| int | payloadtype, | ||
| int | mark, | ||
| struct frame_list * | frames | ||
| ) | [static] |
Definition at line 1454 of file res_rtp_asterisk.c.
References ast_debug, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frdup(), AST_LIST_INSERT_TAIL, ast_log(), ast_rtp_instance_get_data(), ast_rtp_instance_get_prop(), ast_rtp_instance_get_remote_address(), AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_samp2tv(), ast_sockaddr_stringify(), ast_tv(), ast_tvdiff_ms(), ast_verbose(), ast_frame_subclass::codec, create_dtmf_frame(), ast_rtp::dtmf_duration, ast_rtp::dtmf_timeout, ast_rtp::dtmfsamples, dtmftimeout, f, ast_rtp::lastevent, ast_frame::len, LOG_DEBUG, option_debug, ast_rtp::resp, rtp_debug_test_addr(), rtp_get_rate(), ast_frame::samples, ast_frame::seqno, and ast_frame::subclass.
Referenced by ast_rtp_read().
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
struct ast_sockaddr remote_address = { {0,} };
unsigned int event, event_end, samples;
char resp = 0;
struct ast_frame *f = NULL;
ast_rtp_instance_get_remote_address(instance, &remote_address);
/* Figure out event, event end, and samples */
event = ntohl(*((unsigned int *)(data)));
event >>= 24;
event_end = ntohl(*((unsigned int *)(data)));
event_end <<= 8;
event_end >>= 24;
samples = ntohl(*((unsigned int *)(data)));
samples &= 0xFFFF;
if (rtp_debug_test_addr(&remote_address)) {
ast_verbose("Got RTP RFC2833 from %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u, mark %d, event %08x, end %d, duration %-5.5d) \n",
ast_sockaddr_stringify(&remote_address),
payloadtype, seqno, timestamp, len, (mark?1:0), event, ((event_end & 0x80)?1:0), samples);
}
/* Print out debug if turned on */
if (rtpdebug || option_debug > 2)
ast_debug(0, "- RTP 2833 Event: %08x (len = %d)\n", event, len);
/* Figure out what digit was pressed */
if (event < 10) {
resp = '0' + event;
} else if (event < 11) {
resp = '*';
} else if (event < 12) {
resp = '#';
} else if (event < 16) {
resp = 'A' + (event - 12);
} else if (event < 17) { /* Event 16: Hook flash */
resp = 'X';
} else {
/* Not a supported event */
ast_log(LOG_DEBUG, "Ignoring RTP 2833 Event: %08x. Not a DTMF Digit.\n", event);
return;
}
if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)) {
if ((rtp->lastevent != timestamp) || (rtp->resp && rtp->resp != resp)) {
rtp->resp = resp;
rtp->dtmf_timeout = 0;
f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_DTMF_COMPENSATE)));
f->len = 0;
rtp->lastevent = timestamp;
AST_LIST_INSERT_TAIL(frames, f, frame_list);
}
} else {
/* The duration parameter measures the complete
duration of the event (from the beginning) - RFC2833.
Account for the fact that duration is only 16 bits long
(about 8 seconds at 8000 Hz) and can wrap is digit
is hold for too long. */
unsigned int new_duration = rtp->dtmf_duration;
unsigned int last_duration = new_duration & 0xFFFF;
if (last_duration > 64000 && samples < last_duration) {
new_duration += 0xFFFF + 1;
}
new_duration = (new_duration & ~0xFFFF) | samples;
/* The second portion of this check is to not mistakenly
* stop accepting DTMF if the seqno rolls over beyond
* 65535.
*/
if (rtp->lastevent > seqno && rtp->lastevent - seqno < 50) {
/* Out of order frame. Processing this can cause us to
* improperly duplicate incoming DTMF, so just drop
* this.
*/
return;
}
if (event_end & 0x80) {
/* End event */
if ((rtp->lastevent != seqno) && rtp->resp) {
rtp->dtmf_duration = new_duration;
f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0));
f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.codec)), ast_tv(0, 0));
rtp->resp = 0;
rtp->dtmf_duration = rtp->dtmf_timeout = 0;
AST_LIST_INSERT_TAIL(frames, f, frame_list);
}
} else {
/* Begin/continuation */
if (rtp->resp && rtp->resp != resp) {
/* Another digit already began. End it */
f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0));
f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.codec)), ast_tv(0, 0));
rtp->resp = 0;
rtp->dtmf_duration = rtp->dtmf_timeout = 0;
AST_LIST_INSERT_TAIL(frames, f, frame_list);
}
if (rtp->resp) {
/* Digit continues */
rtp->dtmf_duration = new_duration;
} else {
/* New digit began */
rtp->resp = resp;
f = ast_frdup(create_dtmf_frame(instance, AST_FRAME_DTMF_BEGIN, 0));
rtp->dtmf_duration = samples;
AST_LIST_INSERT_TAIL(frames, f, frame_list);
}
rtp->dtmf_timeout = timestamp + rtp->dtmf_duration + dtmftimeout;
}
rtp->lastevent = seqno;
}
rtp->dtmfsamples = samples;
return;
}
Definition at line 1216 of file res_rtp_asterisk.c.
References ast_frame::data, ast_frame::datalen, rtp_red::hdrlen, rtp_red::len, len(), rtp_red::num_gen, ast_frame::ptr, rtp_red::t140, and rtp_red::t140red.
Referenced by ast_rtp_write().
{
unsigned char *data = red->t140red.data.ptr;
int len = 0;
int i;
/* replace most aged generation */
if (red->len[0]) {
for (i = 1; i < red->num_gen+1; i++)
len += red->len[i];
memmove(&data[red->hdrlen], &data[red->hdrlen+red->len[0]], len);
}
/* Store length of each generation and primary data length*/
for (i = 0; i < red->num_gen; i++)
red->len[i] = red->len[i+1];
red->len[i] = red->t140.datalen;
/* write each generation length in red header */
len = red->hdrlen;
for (i = 0; i < red->num_gen; i++)
len += data[i*4+3] = red->len[i];
/* add primary data to buffer */
memcpy(&data[len], red->t140.data.ptr, red->t140.datalen);
red->t140red.datalen = len + red->t140.datalen;
/* no primary data and no generations to send */
if (len == red->hdrlen && !red->t140.datalen)
return NULL;
/* reset t.140 buffer */
red->t140.datalen = 0;
return &red->t140red;
}
| static int red_write | ( | const void * | data | ) | [static] |
Write t140 redundacy frame.
| data | primary data to be buffered |
Definition at line 2519 of file res_rtp_asterisk.c.
References ast_rtp_instance_get_data(), ast_rtp_write(), ast_rtp::red, and rtp_red::t140.
Referenced by rtp_red_init().
{
struct ast_rtp_instance *instance = (struct ast_rtp_instance*) data;
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
ast_rtp_write(instance, &rtp->red->t140);
return 1;
}
| static int reload_module | ( | void | ) | [static] |
Definition at line 2940 of file res_rtp_asterisk.c.
References rtp_reload().
{
rtp_reload(1);
return 0;
}
| static int rtcp_debug_test_addr | ( | struct ast_sockaddr * | addr | ) | [inline, static] |
Definition at line 331 of file res_rtp_asterisk.c.
References ast_sockaddr_cmp(), ast_sockaddr_cmp_addr(), ast_sockaddr_isnull(), and rtcpdebugaddr.
Referenced by ast_rtcp_read(), ast_rtcp_write_rr(), and ast_rtcp_write_sr().
{
if (!rtcpdebug) {
return 0;
}
if (!ast_sockaddr_isnull(&rtcpdebugaddr)) {
if (rtcpdebugport) {
return (ast_sockaddr_cmp(&rtcpdebugaddr, addr) == 0); /* look for RTCP packets from IP+Port */
} else {
return (ast_sockaddr_cmp_addr(&rtcpdebugaddr, addr) == 0); /* only look for RTCP packets from IP */
}
}
return 1;
}
| static char* rtcp_do_debug_ip | ( | struct ast_cli_args * | a | ) | [static] |
Definition at line 2755 of file res_rtp_asterisk.c.
References ast_cli_args::argv, ast_cli(), ast_sockaddr_parse(), ast_sockaddr_split_hostport(), ast_sockaddr_stringify(), ast_strdupa, ast_strlen_zero(), CLI_FAILURE, CLI_SUCCESS, ast_cli_args::fd, and rtcpdebugaddr.
Referenced by handle_cli_rtcp_set_debug().
{
char *arg = ast_strdupa(a->argv[4]);
char *debughost = NULL;
char *debugport = NULL;
if (!ast_sockaddr_parse(&rtcpdebugaddr, arg, 0) || !ast_sockaddr_split_hostport(arg, &debughost, &debugport, 0)) {
ast_cli(a->fd, "Lookup failed for '%s'\n", arg);
return CLI_FAILURE;
}
rtcpdebugport = (!ast_strlen_zero(debugport) && debugport[0] != '0');
ast_cli(a->fd, "RTCP Debugging Enabled for address: %s\n",
ast_sockaddr_stringify(&rtcpdebugaddr));
rtcpdebug = 1;
return CLI_SUCCESS;
}
| static int rtcp_recvfrom | ( | struct ast_rtp_instance * | instance, |
| void * | buf, | ||
| size_t | size, | ||
| int | flags, | ||
| struct ast_sockaddr * | sa | ||
| ) | [static] |
Definition at line 364 of file res_rtp_asterisk.c.
References __rtp_recvfrom().
Referenced by ast_rtcp_read().
{
return __rtp_recvfrom(instance, buf, size, flags, sa, 1);
}
| static int rtcp_sendto | ( | struct ast_rtp_instance * | instance, |
| void * | buf, | ||
| size_t | size, | ||
| int | flags, | ||
| struct ast_sockaddr * | sa | ||
| ) | [static] |
Definition at line 388 of file res_rtp_asterisk.c.
References __rtp_sendto().
Referenced by ast_rtcp_write_rr(), and ast_rtcp_write_sr().
{
return __rtp_sendto(instance, buf, size, flags, sa, 1);
}
| static int rtp_debug_test_addr | ( | struct ast_sockaddr * | addr | ) | [inline, static] |
Definition at line 315 of file res_rtp_asterisk.c.
References ast_sockaddr_cmp(), ast_sockaddr_cmp_addr(), ast_sockaddr_isnull(), and rtpdebugaddr.
Referenced by ast_rtp_dtmf_begin(), ast_rtp_dtmf_continuation(), ast_rtp_dtmf_end_with_duration(), ast_rtp_raw_write(), ast_rtp_read(), ast_rtp_sendcng(), bridge_p2p_rtp_write(), and process_dtmf_rfc2833().
{
if (!rtpdebug) {
return 0;
}
if (!ast_sockaddr_isnull(&rtpdebugaddr)) {
if (rtpdebugport) {
return (ast_sockaddr_cmp(&rtpdebugaddr, addr) == 0); /* look for RTP packets from IP+Port */
} else {
return (ast_sockaddr_cmp_addr(&rtpdebugaddr, addr) == 0); /* only look for RTP packets from IP */
}
}
return 1;
}
| static char* rtp_do_debug_ip | ( | struct ast_cli_args * | a | ) | [static] |
Definition at line 2738 of file res_rtp_asterisk.c.
References ast_cli_args::argv, ast_cli(), ast_sockaddr_parse(), ast_sockaddr_split_hostport(), ast_sockaddr_stringify(), ast_strdupa, ast_strlen_zero(), CLI_FAILURE, CLI_SUCCESS, ast_cli_args::fd, and rtpdebugaddr.
Referenced by handle_cli_rtp_set_debug().
{
char *arg = ast_strdupa(a->argv[4]);
char *debughost = NULL;
char *debugport = NULL;
if (!ast_sockaddr_parse(&rtpdebugaddr, arg, 0) || !ast_sockaddr_split_hostport(arg, &debughost, &debugport, 0)) {
ast_cli(a->fd, "Lookup failed for '%s'\n", arg);
return CLI_FAILURE;
}
rtpdebugport = (!ast_strlen_zero(debugport) && debugport[0] != '0');
ast_cli(a->fd, "RTP Debugging Enabled for address: %s\n",
ast_sockaddr_stringify(&rtpdebugaddr));
rtpdebug = 1;
return CLI_SUCCESS;
}
| static int rtp_get_rate | ( | format_t | subclass | ) | [static] |
Definition at line 398 of file res_rtp_asterisk.c.
References AST_FORMAT_G722, and ast_format_rate().
Referenced by ast_rtp_dtmf_end_with_duration(), ast_rtp_raw_write(), ast_rtp_read(), calc_rxstamp(), process_dtmf_cisco(), and process_dtmf_rfc2833().
{
return (subclass == AST_FORMAT_G722) ? 8000 : ast_format_rate(subclass);
}
| static int rtp_recvfrom | ( | struct ast_rtp_instance * | instance, |
| void * | buf, | ||
| size_t | size, | ||
| int | flags, | ||
| struct ast_sockaddr * | sa | ||
| ) | [static] |
Definition at line 369 of file res_rtp_asterisk.c.
References __rtp_recvfrom().
Referenced by ast_rtp_read().
{
return __rtp_recvfrom(instance, buf, size, flags, sa, 0);
}
| static int rtp_red_buffer | ( | struct ast_rtp_instance * | instance, |
| struct ast_frame * | frame | ||
| ) | [static] |
Definition at line 2564 of file res_rtp_asterisk.c.
References ast_rtp_instance_get_data(), rtp_red::buf_data, ast_frame::data, ast_frame::datalen, ast_frame::ptr, ast_rtp::red, rtp_red::t140, and ast_frame::ts.
| static int rtp_red_init | ( | struct ast_rtp_instance * | instance, |
| int | buffer_time, | ||
| int * | payloads, | ||
| int | generations | ||
| ) | [static] |
Definition at line 2529 of file res_rtp_asterisk.c.
References ast_calloc, AST_FORMAT_T140RED, AST_FRAME_TEXT, ast_rtp_instance_get_data(), ast_sched_add(), rtp_red::buf_data, ast_frame_subclass::codec, ast_frame::data, ast_frame::datalen, ast_frame::frametype, rtp_red::hdrlen, rtp_red::num_gen, rtp_red::prev_ts, rtp_red::pt, ast_frame::ptr, ast_rtp::red, red_write(), ast_rtp::sched, rtp_red::schedid, ast_frame::subclass, rtp_red::t140, rtp_red::t140red, rtp_red::t140red_data, rtp_red::ti, and ast_frame::ts.
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
int x;
if (!(rtp->red = ast_calloc(1, sizeof(*rtp->red)))) {
return -1;
}
rtp->red->t140.frametype = AST_FRAME_TEXT;
rtp->red->t140.subclass.codec = AST_FORMAT_T140RED;
rtp->red->t140.data.ptr = &rtp->red->buf_data;
rtp->red->t140.ts = 0;
rtp->red->t140red = rtp->red->t140;
rtp->red->t140red.data.ptr = &rtp->red->t140red_data;
rtp->red->t140red.datalen = 0;
rtp->red->ti = buffer_time;
rtp->red->num_gen = generations;
rtp->red->hdrlen = generations * 4 + 1;
rtp->red->prev_ts = 0;
for (x = 0; x < generations; x++) {
rtp->red->pt[x] = payloads[x];
rtp->red->pt[x] |= 1 << 7; /* mark redundant generations pt */
rtp->red->t140red_data[x*4] = rtp->red->pt[x];
}
rtp->red->t140red_data[x*4] = rtp->red->pt[x] = payloads[x]; /* primary pt */
rtp->red->schedid = ast_sched_add(rtp->sched, generations, red_write, instance);
rtp->red->t140.datalen = 0;
return 0;
}
| static int rtp_reload | ( | int | reload | ) | [static] |
Definition at line 2871 of file res_rtp_asterisk.c.
References ast_config_destroy(), ast_config_load2(), ast_false(), ast_log(), ast_true(), ast_variable_retrieve(), ast_verb, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_DTMF_TIMEOUT, DEFAULT_RTP_END, DEFAULT_RTP_START, LOG_WARNING, MAXIMUM_RTP_PORT, MINIMUM_RTP_PORT, RTCP_MAX_INTERVALMS, RTCP_MIN_INTERVALMS, and STRICT_RTP_OPEN.
Referenced by load_module(), and reload_module().
{
struct ast_config *cfg;
const char *s;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
cfg = ast_config_load2("rtp.conf", "rtp", config_flags);
if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
return 0;
}
rtpstart = DEFAULT_RTP_START;
rtpend = DEFAULT_RTP_END;
dtmftimeout = DEFAULT_DTMF_TIMEOUT;
strictrtp = STRICT_RTP_OPEN;
if (cfg) {
if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) {
rtpstart = atoi(s);
if (rtpstart < MINIMUM_RTP_PORT)
rtpstart = MINIMUM_RTP_PORT;
if (rtpstart > MAXIMUM_RTP_PORT)
rtpstart = MAXIMUM_RTP_PORT;
}
if ((s = ast_variable_retrieve(cfg, "general", "rtpend"))) {
rtpend = atoi(s);
if (rtpend < MINIMUM_RTP_PORT)
rtpend = MINIMUM_RTP_PORT;
if (rtpend > MAXIMUM_RTP_PORT)
rtpend = MAXIMUM_RTP_PORT;
}
if ((s = ast_variable_retrieve(cfg, "general", "rtcpinterval"))) {
rtcpinterval = atoi(s);
if (rtcpinterval == 0)
rtcpinterval = 0; /* Just so we're clear... it's zero */
if (rtcpinterval < RTCP_MIN_INTERVALMS)
rtcpinterval = RTCP_MIN_INTERVALMS; /* This catches negative numbers too */
if (rtcpinterval > RTCP_MAX_INTERVALMS)
rtcpinterval = RTCP_MAX_INTERVALMS;
}
if ((s = ast_variable_retrieve(cfg, "general", "rtpchecksums"))) {
#ifdef SO_NO_CHECK
nochecksums = ast_false(s) ? 1 : 0;
#else
if (ast_false(s))
ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
#endif
}
if ((s = ast_variable_retrieve(cfg, "general", "dtmftimeout"))) {
dtmftimeout = atoi(s);
if ((dtmftimeout < 0) || (dtmftimeout > 64000)) {
ast_log(LOG_WARNING, "DTMF timeout of '%d' outside range, using default of '%d' instead\n",
dtmftimeout, DEFAULT_DTMF_TIMEOUT);
dtmftimeout = DEFAULT_DTMF_TIMEOUT;
};
}
if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) {
strictrtp = ast_true(s);
}
ast_config_destroy(cfg);
}
if (rtpstart >= rtpend) {
ast_log(LOG_WARNING, "Unreasonable values for RTP start/end port in rtp.conf\n");
rtpstart = DEFAULT_RTP_START;
rtpend = DEFAULT_RTP_END;
}
ast_verb(2, "RTP Allocating from port range %d -> %d\n", rtpstart, rtpend);
return 0;
}
| static int rtp_sendto | ( | struct ast_rtp_instance * | instance, |
| void * | buf, | ||
| size_t | size, | ||
| int | flags, | ||
| struct ast_sockaddr * | sa | ||
| ) | [static] |
Definition at line 393 of file res_rtp_asterisk.c.
References __rtp_sendto().
Referenced by ast_rtp_dtmf_begin(), ast_rtp_dtmf_continuation(), ast_rtp_dtmf_end_with_duration(), ast_rtp_raw_write(), ast_rtp_sendcng(), and bridge_p2p_rtp_write().
{
return __rtp_sendto(instance, buf, size, flags, sa, 0);
}
| static double stddev_compute | ( | double | stddev, |
| double | sample, | ||
| double | normdev, | ||
| double | normdev_curent, | ||
| unsigned int | sample_count | ||
| ) | [static] |
Definition at line 421 of file res_rtp_asterisk.c.
References SQUARE.
Referenced by ast_rtcp_read(), ast_rtcp_write_rr(), and calc_rxstamp().
{
/*
for the formula check http://www.cs.umd.edu/~austinjp/constSD.pdf
return sqrt( (sample_count*pow(stddev,2) + sample_count*pow((sample-normdev)/(sample_count+1),2) + pow(sample-normdev_curent,2)) / (sample_count+1));
we can compute the sigma^2 and that way we would have to do the sqrt only 1 time at the end and would save another pow 2 compute
optimized formula
*/
#define SQUARE(x) ((x) * (x))
stddev = sample_count * stddev;
sample_count++;
return stddev +
( sample_count * SQUARE( (sample - normdev) / sample_count ) ) +
( SQUARE(sample - normdev_curent) / sample_count );
#undef SQUARE
}
| static void timeval2ntp | ( | struct timeval | tv, |
| unsigned int * | msw, | ||
| unsigned int * | lsw | ||
| ) | [static] |
Definition at line 819 of file res_rtp_asterisk.c.
Referenced by ast_rtcp_read(), and ast_rtcp_write_sr().
| static int unload_module | ( | void | ) | [static] |
Definition at line 2962 of file res_rtp_asterisk.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), and ast_rtp_engine_unregister().
{
ast_rtp_engine_unregister(&asterisk_rtp_engine);
ast_cli_unregister_multiple(cli_rtp, ARRAY_LEN(cli_rtp));
return 0;
}
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Asterisk RTP Stack" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static] |
Definition at line 2975 of file res_rtp_asterisk.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2975 of file res_rtp_asterisk.c.
struct ast_rtp_engine asterisk_rtp_engine [static] |
Definition at line 287 of file res_rtp_asterisk.c.
struct ast_cli_entry cli_rtp[] [static] |
{
AST_CLI_DEFINE(handle_cli_rtp_set_debug, "Enable/Disable RTP debugging"),
AST_CLI_DEFINE(handle_cli_rtcp_set_debug, "Enable/Disable RTCP debugging"),
AST_CLI_DEFINE(handle_cli_rtcp_set_stats, "Enable/Disable RTCP stats"),
}
Definition at line 2865 of file res_rtp_asterisk.c.
int dtmftimeout = DEFAULT_DTMF_TIMEOUT [static] |
Definition at line 84 of file res_rtp_asterisk.c.
Referenced by process_dtmf_rfc2833().
| struct ast_srtp_res* res_srtp |
Definition at line 44 of file rtp_engine.c.
int rtcpdebug [static] |
Are we debugging RTCP?
Definition at line 89 of file res_rtp_asterisk.c.
struct ast_sockaddr rtcpdebugaddr [static] |
Debug RTCP packets to/from this host
Definition at line 93 of file res_rtp_asterisk.c.
Referenced by handle_cli_rtcp_set_debug(), rtcp_debug_test_addr(), and rtcp_do_debug_ip().
int rtcpdebugport [static] |
Definition at line 95 of file res_rtp_asterisk.c.
int rtcpinterval = RTCP_DEFAULT_INTERVALMS [static] |
Time between rtcp reports in millisecs
Definition at line 91 of file res_rtp_asterisk.c.
Referenced by ast_rtcp_calc_interval().
int rtcpstats [static] |
Are we debugging RTCP?
Definition at line 90 of file res_rtp_asterisk.c.
int rtpdebug [static] |
Are we debugging?
Definition at line 88 of file res_rtp_asterisk.c.
struct ast_sockaddr rtpdebugaddr [static] |
Debug packets to/from this host
Definition at line 92 of file res_rtp_asterisk.c.
Referenced by handle_cli_rtp_set_debug(), rtp_debug_test_addr(), and rtp_do_debug_ip().
int rtpdebugport [static] |
Definition at line 94 of file res_rtp_asterisk.c.
int rtpend = DEFAULT_RTP_END [static] |
Last port for RTP sessions (set in rtp.conf)
Definition at line 87 of file res_rtp_asterisk.c.
int rtpstart = DEFAULT_RTP_START [static] |
First port for RTP sessions (set in rtp.conf)
Definition at line 86 of file res_rtp_asterisk.c.
Referenced by ast_rtp_new().
int strictrtp [static] |
Definition at line 99 of file res_rtp_asterisk.c.