mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 04:11:08 +00:00
Issue #2863 - Improved RTCP support (John Martin, Fredrik Olsson)
Thanks to everyone involved in working with this! git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@32230 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -18,3 +18,5 @@ rtpend=20000
|
||||
; allowed to continue (in 'samples', 1/8000 of a second)
|
||||
;
|
||||
;dtmftimeout=3000
|
||||
; rtcpinterval = 5000 ; Milliseconds between rtcp reports
|
||||
;(min 500, max 60000, default 5000)
|
||||
|
@@ -166,6 +166,12 @@ int ast_rtp_early_media(struct ast_channel *dest, struct ast_channel *src);
|
||||
|
||||
void ast_rtp_stop(struct ast_rtp *rtp);
|
||||
|
||||
/*! \brief Return RTCP quality string */
|
||||
char *ast_rtp_get_quality(struct ast_rtp *rtp);
|
||||
|
||||
/*! \brief Send an H.261 fast update request. Some devices need this rather than the XML message in SIP */
|
||||
int ast_rtcp_send_h261fur(void *data);
|
||||
|
||||
void ast_rtp_init(void);
|
||||
|
||||
int ast_rtp_reload(void);
|
||||
|
733
rtp.c
733
rtp.c
@@ -59,6 +59,18 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#define MAX_TIMESTAMP_SKEW 640
|
||||
|
||||
#define RTP_SEQ_MOD (1<<16) /*!< A sequence number can't be more than 16 bits */
|
||||
#define RTCP_DEFAULT_INTERVALMS 5000 /*!< Default milli-seconds between RTCP reports we send */
|
||||
#define RTCP_MIN_INTERVALMS 500 /*!< Min milli-seconds between RTCP reports we send */
|
||||
#define RTCP_MAX_INTERVALMS 60000 /*!< Max milli-seconds between RTCP reports we send */
|
||||
|
||||
#define RTCP_PT_FUR 192
|
||||
#define RTCP_PT_SR 200
|
||||
#define RTCP_PT_RR 201
|
||||
#define RTCP_PT_SDES 202
|
||||
#define RTCP_PT_BYE 203
|
||||
#define RTCP_PT_APP 204
|
||||
|
||||
#define RTP_MTU 1200
|
||||
|
||||
#define DEFAULT_DTMF_TIMEOUT 3000 /*!< samples */
|
||||
@@ -68,12 +80,23 @@ static int dtmftimeout = DEFAULT_DTMF_TIMEOUT;
|
||||
static int rtpstart = 0; /*!< First port for RTP sessions (set in rtp.conf) */
|
||||
static int rtpend = 0; /*!< Last port for RTP sessions (set in rtp.conf) */
|
||||
static int rtpdebug = 0; /*!< Are we debugging? */
|
||||
static int rtcpdebug = 0; /*!< Are we debugging RTCP? */
|
||||
static int rtcpstats = 0; /*!< Are we debugging RTCP? */
|
||||
static int rtcpinterval = RTCP_DEFAULT_INTERVALMS; /*!< Time between rtcp reports in millisecs */
|
||||
static int stundebug = 0; /*!< Are we debugging stun? */
|
||||
static struct sockaddr_in rtpdebugaddr; /*!< Debug packets to/from this host */
|
||||
static struct sockaddr_in rtcpdebugaddr; /*!< Debug RTCP packets to/from this host */
|
||||
#ifdef SO_NO_CHECK
|
||||
static int nochecksums = 0;
|
||||
#endif
|
||||
|
||||
/* Forward declarations */
|
||||
static int ast_rtcp_write(void *data);
|
||||
static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw);
|
||||
static int ast_rtcp_write_sr(void *data);
|
||||
static int ast_rtcp_write_rr(void *data);
|
||||
static unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp);
|
||||
|
||||
/*! \brief The value of each payload format mapping: */
|
||||
struct rtpPayloadType {
|
||||
int isAstFormat; /*!< whether the following code is an AST_FORMAT */
|
||||
@@ -95,6 +118,7 @@ struct ast_rtp {
|
||||
struct ast_frame f;
|
||||
unsigned char rawdata[8192 + AST_FRIENDLY_OFFSET];
|
||||
unsigned int ssrc; /*!< Synchronization source, RFC 3550, page 10. */
|
||||
unsigned int themssrc; /*!< Their SSRC */
|
||||
unsigned int rxssrc;
|
||||
unsigned int lastts;
|
||||
unsigned int lastdigitts;
|
||||
@@ -102,6 +126,16 @@ struct ast_rtp {
|
||||
unsigned int lastividtimestamp;
|
||||
unsigned int lastovidtimestamp;
|
||||
unsigned int lasteventseqn;
|
||||
int lastrxseqno; /*!< Last received sequence number */
|
||||
unsigned short seedrxseqno; /*!< What sequence number did they start with?*/
|
||||
unsigned int seedrxts; /*!< What RTP timestamp did they start with? */
|
||||
unsigned int rxcount; /*!< How many packets have we received? */
|
||||
unsigned int rxoctetcount; /*!< How many octets have we received? should be rxcount *160*/
|
||||
unsigned int txcount; /*!< How many packets have we sent? */
|
||||
unsigned int txoctetcount; /*!< How many octets have we sent? (txcount*160)*/
|
||||
unsigned int cycles; /*!< Shifted count of sequence number cycles */
|
||||
double rxjitter; /*!< Interarrival jitter at the moment */
|
||||
double rxtransit; /*!< Relative transit time for previous packet */
|
||||
unsigned int lasteventendseqn;
|
||||
int lasttxformat;
|
||||
int lastrxformat;
|
||||
@@ -113,6 +147,8 @@ struct ast_rtp {
|
||||
struct sockaddr_in them; /*!< Socket representation of the remote endpoint. */
|
||||
struct timeval rxcore;
|
||||
struct timeval txcore;
|
||||
double drxcore; /*!< The double representation of the first received packet */
|
||||
struct timeval lastrx; /*!< timeval when we last received a packet */
|
||||
struct timeval dtmfmute;
|
||||
struct ast_smoother *smoother;
|
||||
int *ioid;
|
||||
@@ -143,6 +179,27 @@ struct ast_rtcp {
|
||||
int s; /*!< Socket */
|
||||
struct sockaddr_in us; /*!< Socket representation of the local endpoint. */
|
||||
struct sockaddr_in them; /*!< Socket representation of the remote endpoint. */
|
||||
unsigned int soc; /*!< What they told us */
|
||||
unsigned int spc; /*!< What they told us */
|
||||
unsigned int themrxlsr; /*!< The middle 32 bits of the NTP timestamp in the last received SR*/
|
||||
struct timeval rxlsr; /*!< Time when we got their last SR */
|
||||
struct timeval txlsr; /*!< Time when we sent or last SR*/
|
||||
unsigned int expected_prior; /*!< no. packets in previous interval */
|
||||
unsigned int received_prior; /*!< no. packets received in previous interval */
|
||||
int schedid; /*!< Schedid returned from ast_sched_add() to schedule RTCP-transmissions*/
|
||||
unsigned int rr_count; /*!< number of RRs we've sent, not including report blocks in SR's */
|
||||
unsigned int sr_count; /*!< number of SRs we've sent */
|
||||
unsigned int lastsrtxcount; /*!< Transmit packet count when last SR sent */
|
||||
double accumulated_transit; /*!< accumulated a-dlsr-lsr */
|
||||
double rtt; /*!< Last reported rtt */
|
||||
unsigned int reported_jitter; /*!< The contents of their last jitter entry in the RR */
|
||||
unsigned int reported_lost; /*!< Reported lost packets in their RR */
|
||||
char quality[AST_MAX_USER_FIELD];
|
||||
double maxrxjitter;
|
||||
double minrxjitter;
|
||||
double maxrtt;
|
||||
double minrtt;
|
||||
int sendfur;
|
||||
};
|
||||
|
||||
|
||||
@@ -408,6 +465,16 @@ static int stun_handle_packet(int s, struct sockaddr_in *src, unsigned char *dat
|
||||
/*! \brief List of current sessions */
|
||||
static AST_LIST_HEAD_STATIC(protos, ast_rtp_protocol);
|
||||
|
||||
static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw)
|
||||
{
|
||||
unsigned int sec, usec, frac;
|
||||
sec = tv.tv_sec + 2208988800u; /* Sec between 1900 and 1970 */
|
||||
usec = tv.tv_usec;
|
||||
frac = (usec << 12) + (usec << 8) - ((usec * 3650) >> 6);
|
||||
*msw = sec;
|
||||
*lsw = frac;
|
||||
}
|
||||
|
||||
int ast_rtp_fd(struct ast_rtp *rtp)
|
||||
{
|
||||
return rtp->s;
|
||||
@@ -420,6 +487,15 @@ int ast_rtcp_fd(struct ast_rtp *rtp)
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void ast_rtp_set_data(struct ast_rtp *rtp, void *data)
|
||||
{
|
||||
rtp->data = data;
|
||||
@@ -483,6 +559,20 @@ static inline int rtp_debug_test_addr(struct sockaddr_in *addr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int rtcp_debug_test_addr(struct sockaddr_in *addr)
|
||||
{
|
||||
if (rtcpdebug == 0)
|
||||
return 0;
|
||||
if (rtcpdebugaddr.sin_addr.s_addr) {
|
||||
if (((ntohs(rtcpdebugaddr.sin_port) != 0)
|
||||
&& (rtcpdebugaddr.sin_port != addr->sin_port))
|
||||
|| (rtcpdebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static struct ast_frame *process_cisco_dtmf(struct ast_rtp *rtp, unsigned char *data, int len)
|
||||
{
|
||||
unsigned int event;
|
||||
@@ -632,33 +722,44 @@ static int rtpread(int *id, int fd, short events, void *cbdata)
|
||||
struct ast_frame *ast_rtcp_read(struct ast_rtp *rtp)
|
||||
{
|
||||
socklen_t len;
|
||||
int hdrlen = 8;
|
||||
int position, i, packetwords;
|
||||
int res;
|
||||
struct sockaddr_in sin;
|
||||
unsigned int rtcpdata[1024];
|
||||
unsigned int rtcpdata[8192 + AST_FRIENDLY_OFFSET];
|
||||
char iabuf[INET_ADDRSTRLEN];
|
||||
unsigned int *rtcpheader;
|
||||
int pt;
|
||||
struct timeval now;
|
||||
unsigned int length;
|
||||
int rc;
|
||||
double rtt = 0;
|
||||
double a;
|
||||
double dlsr;
|
||||
double lsr;
|
||||
unsigned int msw;
|
||||
unsigned int lsw;
|
||||
unsigned int comp;
|
||||
struct ast_frame *f = &ast_null_frame;
|
||||
|
||||
if (!rtp || !rtp->rtcp)
|
||||
return &ast_null_frame;
|
||||
|
||||
len = sizeof(sin);
|
||||
|
||||
res = recvfrom(rtp->rtcp->s, rtcpdata, sizeof(rtcpdata),
|
||||
res = recvfrom(rtp->rtcp->s, rtcpdata + AST_FRIENDLY_OFFSET, sizeof(rtcpdata) - sizeof(unsigned int) * AST_FRIENDLY_OFFSET,
|
||||
0, (struct sockaddr *)&sin, &len);
|
||||
rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET);
|
||||
|
||||
if (res < 0) {
|
||||
if (errno != EAGAIN)
|
||||
ast_log(LOG_WARNING, "RTP Read error: %s\n", strerror(errno));
|
||||
ast_log(LOG_WARNING, "RTCP Read error: %s\n", strerror(errno));
|
||||
if (errno == EBADF)
|
||||
CRASH;
|
||||
return &ast_null_frame;
|
||||
}
|
||||
|
||||
if (res < hdrlen) {
|
||||
ast_log(LOG_WARNING, "RTP Read too short\n");
|
||||
return &ast_null_frame;
|
||||
}
|
||||
|
||||
packetwords = res / 4;
|
||||
|
||||
if (rtp->nat) {
|
||||
/* Send to whoever sent to us */
|
||||
if ((rtp->rtcp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
|
||||
@@ -670,18 +771,154 @@ struct ast_frame *ast_rtcp_read(struct ast_rtp *rtp)
|
||||
}
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Got RTCP report of %d bytes\n", res);
|
||||
return &ast_null_frame;
|
||||
|
||||
/* Process a compound packet */
|
||||
position = 0;
|
||||
while (position < packetwords) {
|
||||
i = position;
|
||||
length = ntohl(rtcpheader[i]);
|
||||
pt = (length & 0xff0000) >> 16;
|
||||
rc = (length & 0x1f000000) >> 24;
|
||||
length &= 0xffff;
|
||||
|
||||
if ((i + length) > packetwords) {
|
||||
ast_log(LOG_WARNING, "RTCP Read too short\n");
|
||||
return &ast_null_frame;
|
||||
}
|
||||
|
||||
if(rtcp_debug_test_addr(&sin)){
|
||||
ast_verbose("\n\nGot RTCP from %s:%d\n",ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr),ntohs(sin.sin_port));
|
||||
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 */
|
||||
|
||||
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]) & 0xffff) >> 16); /* Going to LSR in RR*/
|
||||
|
||||
if(rtcp_debug_test_addr(&sin)){
|
||||
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:
|
||||
/* This is the place to calculate RTT */
|
||||
/* Don't handle multiple reception reports (rc > 1) yet */
|
||||
gettimeofday(&now, NULL);
|
||||
timeval2ntp(now, &msw, &lsw);
|
||||
/* Use the one we sent them in our SR instead, rtcp->txlsr could have been rewritten if the dlsr is large */
|
||||
if(ntohl(rtcpheader[i+4])){ /* We must have the LSR */
|
||||
comp = ((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16);
|
||||
a = (double)((comp & 0xffff0000) >> 16) + (double)((double)(comp & 0xffff)/1000000.);
|
||||
lsr = (double)((ntohl(rtcpheader[i+4]) & 0xffff0000) >> 16) + (double)((double)(ntohl(rtcpheader[i+4]) & 0xffff)/1000000.);
|
||||
dlsr = (double)(ntohl(rtcpheader[i+5])/65536.);
|
||||
rtt = a - dlsr - lsr;
|
||||
rtp->rtcp->accumulated_transit += rtt;
|
||||
rtp->rtcp->rtt = rtt;
|
||||
if(rtp->rtcp->maxrtt<rtt)
|
||||
rtp->rtcp->maxrtt = rtt;
|
||||
if(rtp->rtcp->minrtt>rtt)
|
||||
rtp->rtcp->minrtt = rtt;
|
||||
}
|
||||
rtp->rtcp->reported_jitter = ntohl(rtcpheader[i+3]);
|
||||
rtp->rtcp->reported_lost = ntohl(rtcpheader[i+1]) & 0xffffff;
|
||||
if(rtcp_debug_test_addr(&sin)){
|
||||
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: %f(sec)\n", rtt);
|
||||
}
|
||||
break;
|
||||
case RTCP_PT_FUR:
|
||||
if(rtcp_debug_test_addr(&sin))
|
||||
ast_verbose("Received an RTCP Fast Update Request\n");
|
||||
rtp->f.frametype = AST_FRAME_CONTROL;
|
||||
rtp->f.subclass = 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(&sin))
|
||||
ast_verbose("Received an SDES from %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
|
||||
break;
|
||||
case RTCP_PT_BYE:
|
||||
if(rtcp_debug_test_addr(&sin))
|
||||
ast_verbose("Received a BYE from %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_NOTICE, "Unknown RTCP packet (pt=%d) received from %s:%d\n", pt, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
|
||||
break;
|
||||
}
|
||||
position += (length + 1);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int timestamp, int mark)
|
||||
{
|
||||
struct timeval ts = ast_samp2tv( timestamp, 8000);
|
||||
if (ast_tvzero(rtp->rxcore) || mark) {
|
||||
rtp->rxcore = ast_tvsub(ast_tvnow(), ts);
|
||||
/* Round to 20ms for nice, pretty timestamps */
|
||||
rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 20000;
|
||||
struct timeval now;
|
||||
double transit;
|
||||
double current_time;
|
||||
double d;
|
||||
double dtv;
|
||||
double prog;
|
||||
|
||||
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 */
|
||||
rtp->rxcore.tv_sec -= timestamp / 8000;
|
||||
rtp->rxcore.tv_usec -= (timestamp % 8000) * 125;
|
||||
/* Round to 0.1ms for nice, pretty timestamps */
|
||||
rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 100;
|
||||
if (rtp->rxcore.tv_usec < 0) {
|
||||
/* Adjust appropriately if necessary */
|
||||
rtp->rxcore.tv_usec += 1000000;
|
||||
rtp->rxcore.tv_sec -= 1;
|
||||
}
|
||||
}
|
||||
*tv = ast_tvadd(rtp->rxcore, ts);
|
||||
|
||||
gettimeofday(&now,NULL);
|
||||
/* rxcore is the mapping between the RTP timestamp and _our_ real time from gettimeofday() */
|
||||
tv->tv_sec = rtp->rxcore.tv_sec + timestamp / 8000;
|
||||
tv->tv_usec = rtp->rxcore.tv_usec + (timestamp % 8000) * 125;
|
||||
if (tv->tv_usec >= 1000000) {
|
||||
tv->tv_usec -= 1000000;
|
||||
tv->tv_sec += 1;
|
||||
}
|
||||
prog = (double)((timestamp-rtp->seedrxts)/8000.);
|
||||
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->rxjitter > rtp->rtcp->maxrxjitter)
|
||||
rtp->rtcp->maxrxjitter = rtp->rxjitter;
|
||||
if(rtp->rxjitter < rtp->rtcp->minrxjitter)
|
||||
rtp->rtcp->minrxjitter = rtp->rxjitter;
|
||||
}
|
||||
|
||||
struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
@@ -692,6 +929,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
unsigned int seqno;
|
||||
int version;
|
||||
int payloadtype;
|
||||
int tseqno;
|
||||
int hdrlen = 12;
|
||||
int padding;
|
||||
int mark;
|
||||
@@ -716,6 +954,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
CRASH;
|
||||
return &ast_null_frame;
|
||||
}
|
||||
|
||||
if (res < hdrlen) {
|
||||
ast_log(LOG_WARNING, "RTP Read too short\n");
|
||||
return &ast_null_frame;
|
||||
@@ -746,6 +985,10 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
if ((rtp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
|
||||
(rtp->them.sin_port != sin.sin_port)) {
|
||||
rtp->them = sin;
|
||||
if(rtp->rtcp) {
|
||||
memcpy(&rtp->rtcp->them, &sin, sizeof(rtp->rtcp->them));
|
||||
rtp->rtcp->them.sin_port = htons(ntohs(rtp->them.sin_port)+1);
|
||||
}
|
||||
rtp->rxseqno = 0;
|
||||
ast_set_flag(rtp, FLAG_NAT_ACTIVE);
|
||||
if (option_debug || rtpdebug)
|
||||
@@ -785,11 +1028,35 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
return &ast_null_frame;
|
||||
}
|
||||
|
||||
rtp->rxcount++; /* Only count reasonably valid packets, this'll make the rtcp stats more accurate */
|
||||
|
||||
tseqno = rtp->lastrxseqno +1;
|
||||
|
||||
if(rtp->rxcount==1){
|
||||
/* This is the first RTP packet successfully received from source */
|
||||
rtp->seedrxseqno = seqno;
|
||||
}
|
||||
|
||||
if(rtp->rtcp->schedid<1){
|
||||
/* Schedule transmission of Receiver Report */
|
||||
rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, rtp);
|
||||
}
|
||||
|
||||
if(tseqno > RTP_SEQ_MOD){ /* if tseqno is greater than RTP_SEQ_MOD it would indicate that the sender cycled */
|
||||
rtp->cycles += RTP_SEQ_MOD;
|
||||
ast_verbose("SEQNO cycled: %u\t%d\n", rtp->cycles, seqno);
|
||||
}
|
||||
|
||||
rtp->lastrxseqno = seqno;
|
||||
|
||||
if(rtp->themssrc==0)
|
||||
rtp->themssrc = ntohl(rtpheader[2]); /* Record their SSRC to put in future RR */
|
||||
|
||||
if(rtp_debug_test_addr(&sin))
|
||||
ast_verbose("Got RTP packet from %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
|
||||
ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp,res - hdrlen);
|
||||
|
||||
rtpPT = ast_rtp_lookup_pt(rtp, payloadtype);
|
||||
rtpPT = ast_rtp_lookup_pt(rtp, payloadtype);
|
||||
if (!rtpPT.isAstFormat) {
|
||||
struct ast_frame *f = NULL;
|
||||
|
||||
@@ -1202,7 +1469,7 @@ struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt)
|
||||
if (pt < 0 || pt > MAX_RTP_PT)
|
||||
return result; /* bogus payload type */
|
||||
|
||||
/* Start with the negotiated codecs */
|
||||
/* Start with negotiated codecs */
|
||||
result = rtp->current_RTP_PT[pt];
|
||||
|
||||
/* If it doesn't exist, check our static RTP type list, just in case */
|
||||
@@ -1225,7 +1492,7 @@ int ast_rtp_lookup_code(struct ast_rtp* rtp, const int isAstFormat, const int co
|
||||
|
||||
/* Check the dynamic list first */
|
||||
for (pt = 0; pt < MAX_RTP_PT; ++pt) {
|
||||
if (rtp->current_RTP_PT[pt].code == code && rtp->current_RTP_PT[pt].isAstFormat == isAstFormat) {
|
||||
if (rtp->current_RTP_PT[pt].code == code && rtp->current_RTP_PT[pt].isAstFormat == isAstFormat) {
|
||||
rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
|
||||
rtp->rtp_lookup_code_cache_code = code;
|
||||
rtp->rtp_lookup_code_cache_result = pt;
|
||||
@@ -1321,9 +1588,11 @@ static struct ast_rtcp *ast_rtcp_new(void)
|
||||
return NULL;
|
||||
rtcp->s = rtp_socket();
|
||||
rtcp->us.sin_family = AF_INET;
|
||||
rtcp->them.sin_family = AF_INET;
|
||||
|
||||
if (rtcp->s < 0) {
|
||||
free(rtcp);
|
||||
ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
|
||||
ast_log(LOG_WARNING, "Unable to allocate RTCP socket: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1465,11 +1734,16 @@ void ast_rtp_get_us(struct ast_rtp *rtp, struct sockaddr_in *us)
|
||||
|
||||
void ast_rtp_stop(struct ast_rtp *rtp)
|
||||
{
|
||||
if(rtp->rtcp->schedid>0){
|
||||
ast_sched_del(rtp->sched, rtp->rtcp->schedid);
|
||||
rtp->rtcp->schedid = -1;
|
||||
}
|
||||
|
||||
memset(&rtp->them.sin_addr, 0, sizeof(rtp->them.sin_addr));
|
||||
memset(&rtp->them.sin_port, 0, sizeof(rtp->them.sin_port));
|
||||
if (rtp->rtcp) {
|
||||
memset(&rtp->rtcp->them.sin_addr, 0, sizeof(rtp->them.sin_addr));
|
||||
memset(&rtp->rtcp->them.sin_port, 0, sizeof(rtp->them.sin_port));
|
||||
memset(&rtp->rtcp->them.sin_addr, 0, sizeof(rtp->rtcp->them.sin_addr));
|
||||
memset(&rtp->rtcp->them.sin_port, 0, sizeof(rtp->rtcp->them.sin_port));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1493,8 +1767,50 @@ void ast_rtp_reset(struct ast_rtp *rtp)
|
||||
rtp->rxseqno = 0;
|
||||
}
|
||||
|
||||
char *ast_rtp_get_quality(struct ast_rtp *rtp)
|
||||
{
|
||||
/*
|
||||
*ssrc our ssrc
|
||||
*themssrc their ssrc
|
||||
*lp lost packets
|
||||
*rxjitter our calculated jitter(rx)
|
||||
*rxcount no. received packets
|
||||
*txjitter reported jitter of the other end
|
||||
*txcount transmitted packets
|
||||
*rlp remote lost packets
|
||||
*/
|
||||
|
||||
snprintf(rtp->rtcp->quality, sizeof(rtp->rtcp->quality), "ssrc=%u;themssrc=%u;lp=%u;rxjitter=%f;rxcount=%u;txjitter=%f;txcount=%u;rlp=%u;rtt=%f", rtp->ssrc, rtp->themssrc, rtp->rtcp->expected_prior - rtp->rtcp->received_prior, rtp->rxjitter, rtp->rxcount, (double)rtp->rtcp->reported_jitter/65536., rtp->txcount, rtp->rtcp->reported_lost, rtp->rtcp->rtt);
|
||||
|
||||
return rtp->rtcp->quality;
|
||||
}
|
||||
|
||||
void ast_rtp_destroy(struct ast_rtp *rtp)
|
||||
{
|
||||
if(rtcp_debug_test_addr(&rtp->them) || rtcpstats){
|
||||
/*Print some info on the call here */
|
||||
ast_verbose(" RTP-stats\n");
|
||||
ast_verbose("* Our Receiver:\n");
|
||||
ast_verbose(" SSRC: %u\n", rtp->themssrc);
|
||||
ast_verbose(" Received packets: %u\n", rtp->rxcount);
|
||||
ast_verbose(" Lost packets: %u\n", rtp->rtcp->expected_prior - rtp->rtcp->received_prior);
|
||||
ast_verbose(" Jitter: %.4f\n", rtp->rxjitter);
|
||||
ast_verbose(" Transit: %.4f\n", rtp->rxtransit);
|
||||
ast_verbose(" RR-count: %u\n", rtp->rtcp->rr_count);
|
||||
ast_verbose("* Our Sender:\n");
|
||||
ast_verbose(" SSRC: %u\n", rtp->ssrc);
|
||||
ast_verbose(" Sent packets: %u\n", rtp->txcount);
|
||||
ast_verbose(" Lost packets: %u\n", rtp->rtcp->reported_lost);
|
||||
ast_verbose(" Jitter: %u\n", rtp->rtcp->reported_jitter);
|
||||
ast_verbose(" SR-count: %u\n", rtp->rtcp->sr_count);
|
||||
ast_verbose(" RTT: %f\n", rtp->rtcp->rtt);
|
||||
}
|
||||
|
||||
if(rtp->rtcp->schedid>0){
|
||||
ast_sched_del(rtp->sched, rtp->rtcp->schedid);
|
||||
rtp->rtcp->schedid = -1;
|
||||
}
|
||||
|
||||
if (rtp->smoother)
|
||||
ast_smoother_free(rtp->smoother);
|
||||
if (rtp->ioid)
|
||||
@@ -1504,6 +1820,7 @@ void ast_rtp_destroy(struct ast_rtp *rtp)
|
||||
if (rtp->rtcp) {
|
||||
close(rtp->rtcp->s);
|
||||
free(rtp->rtcp);
|
||||
rtp->rtcp=NULL;
|
||||
}
|
||||
free(rtp);
|
||||
}
|
||||
@@ -1596,7 +1913,7 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
|
||||
rtpheader[3] |= htonl((1 << 23));
|
||||
}
|
||||
}
|
||||
/* Increment the digit timestamp by 120ms, to ensure that digits
|
||||
/*! \note Increment the digit timestamp by 120ms, to ensure that digits
|
||||
sent sequentially with no intervening non-digit packets do not
|
||||
get sent with the same timestamp, and that sequential digits
|
||||
have some 'dead air' in between them
|
||||
@@ -1609,6 +1926,244 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* \brief Public function: Send an H.261 fast update request, some devices need this rather than SIP XML */
|
||||
int ast_rtcp_send_h261fur(void *data)
|
||||
{
|
||||
struct ast_rtp *rtp = data;
|
||||
int res;
|
||||
|
||||
rtp->rtcp->sendfur = 1;
|
||||
res = ast_rtcp_write(data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Send RTCP sender's report */
|
||||
static int ast_rtcp_write_sr(void *data)
|
||||
{
|
||||
struct ast_rtp *rtp = data;
|
||||
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];
|
||||
char iabuf[INET_ADDRSTRLEN];
|
||||
|
||||
if(!rtp || !rtp->rtcp || (&rtp->rtcp->them.sin_addr == 0))
|
||||
return 0;
|
||||
|
||||
if(!rtp->rtcp->them.sin_addr.s_addr) { /* This'll stop rtcp for this rtp session */
|
||||
ast_verbose("RTCP SR transmission error, rtcp halted %s\n",strerror(errno));
|
||||
ast_sched_del(rtp->sched, rtp->rtcp->schedid);
|
||||
rtp->rtcp->schedid = -1;
|
||||
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);
|
||||
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));
|
||||
|
||||
if (rtp->rtcp->sendfur) {
|
||||
rtcpheader[13] = htonl((2 << 30) | (0 << 24) | (RTCP_PT_FUR << 16) | 1);
|
||||
rtcpheader[14] = htonl(rtp->ssrc); /* Our SSRC */
|
||||
len += 8;
|
||||
rtp->rtcp->sendfur = 0;
|
||||
}
|
||||
|
||||
/* 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 = sendto(rtp->rtcp->s, (unsigned int *)rtcpheader, len, 0, (struct sockaddr *)&rtp->rtcp->them, sizeof(rtp->rtcp->them));
|
||||
if (res < 0) {
|
||||
ast_log(LOG_ERROR, "RTCP SR transmission error to %s:%d, rtcp halted %s\n",ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port), strerror(errno));
|
||||
ast_sched_del(rtp->sched, rtp->rtcp->schedid);
|
||||
rtp->rtcp->schedid = -1;
|
||||
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:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
|
||||
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));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Send RTCP recepient's report */
|
||||
static int ast_rtcp_write_rr(void *data)
|
||||
{
|
||||
struct ast_rtp *rtp = data;
|
||||
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];
|
||||
char iabuf[INET_ADDRSTRLEN];
|
||||
struct timeval dlsr;
|
||||
int fraction;
|
||||
|
||||
if (!rtp || !rtp->rtcp || (&rtp->rtcp->them.sin_addr == 0))
|
||||
return 0;
|
||||
|
||||
if (!rtp->rtcp->them.sin_addr.s_addr){
|
||||
ast_log(LOG_ERROR, "RTCP RR transmission error to, rtcp halted %s\n",strerror(errno));
|
||||
ast_sched_del(rtp->sched, rtp->rtcp->schedid);
|
||||
rtp->rtcp->schedid = -1;
|
||||
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 (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);
|
||||
rtcpheader[6] = htonl(rtp->rtcp->themrxlsr);
|
||||
rtcpheader[7] = htonl((((dlsr.tv_sec * 1000) + (dlsr.tv_usec / 1000)) * 65536) / 1000);
|
||||
|
||||
if (rtp->rtcp->sendfur) {
|
||||
rtcpheader[8] = htonl((2 << 30) | (0 << 24) | (RTCP_PT_FUR << 16) | 1); /* Header from page 36 in RFC 3550 */
|
||||
rtcpheader[9] = htonl(rtp->ssrc); /* Our SSRC */
|
||||
len += 8;
|
||||
rtp->rtcp->sendfur = 0;
|
||||
}
|
||||
|
||||
/*! \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 = sendto(rtp->rtcp->s, (unsigned int *)rtcpheader, len, 0, (struct sockaddr *)&rtp->rtcp->them, sizeof(rtp->rtcp->them));
|
||||
|
||||
if (res < 0) {
|
||||
ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted: %s\n",strerror(errno));
|
||||
/* Remove the scheduler */
|
||||
ast_sched_del(rtp->sched, rtp->rtcp->schedid);
|
||||
rtp->rtcp->schedid = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtp->rtcp->rr_count++;
|
||||
|
||||
if (rtcp_debug_test_addr(&rtp->rtcp->them)) {
|
||||
ast_verbose("\n* Sending RTCP RR to %s:%d\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_inet_ntoa(iabuf, sizeof(iabuf),
|
||||
rtp->rtcp->them.sin_addr),
|
||||
ntohs(rtp->rtcp->them.sin_port),
|
||||
rtp->ssrc, rtp->themssrc, fraction, lost,
|
||||
rtp->rxjitter,
|
||||
rtp->rtcp->themrxlsr,
|
||||
(double)(ntohl(rtcpheader[7])/65536.0));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Write and RTCP packet to the far end
|
||||
* \note Decide if we are going to send an SR (with Reception Block) or RR
|
||||
* RR is sent if we have not sent any rtp packets in the previous interval */
|
||||
static int ast_rtcp_write(void *data)
|
||||
{
|
||||
struct ast_rtp *rtp = data;
|
||||
int res;
|
||||
|
||||
if (rtp->txcount > rtp->rtcp->lastsrtxcount)
|
||||
res = ast_rtcp_write_sr(data);
|
||||
else
|
||||
res = ast_rtcp_write_rr(data);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief generate comfort noice (CNG) */
|
||||
int ast_rtp_sendcng(struct ast_rtp *rtp, int level)
|
||||
{
|
||||
unsigned int *rtpheader;
|
||||
@@ -1637,7 +2192,7 @@ int ast_rtp_sendcng(struct ast_rtp *rtp, int level)
|
||||
if (res <0)
|
||||
ast_log(LOG_ERROR, "RTP Comfort Noise Transmission error to %s:%d: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
|
||||
if(rtp_debug_test_addr(&rtp->them))
|
||||
ast_verbose("Sent Comfort Noise RTP packet to %s:%d (type %d, seq %d, ts %d, len %d)\n"
|
||||
ast_verbose("Sent Comfort Noise RTP packet to %s:%d (type %d, seq %d, ts %u, len %d)\n"
|
||||
, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastts,res - hdrlen);
|
||||
|
||||
}
|
||||
@@ -1716,11 +2271,17 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
|
||||
ast_log(LOG_DEBUG, "RTP NAT: Can't write RTP to private address %s:%d, waiting for other end to send audio...\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port));
|
||||
ast_set_flag(rtp, FLAG_NAT_INACTIVE_NOWARN);
|
||||
}
|
||||
} else {
|
||||
rtp->txcount++;
|
||||
rtp->txoctetcount +=(res - hdrlen);
|
||||
|
||||
if (rtp->rtcp->schedid < 1)
|
||||
rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, rtp);
|
||||
}
|
||||
|
||||
if(rtp_debug_test_addr(&rtp->them))
|
||||
ast_verbose("Sent RTP packet to %s:%d (type %d, seq %u, ts %u, len %u)\n",
|
||||
ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), codec, rtp->seqno, rtp->lastts,res - hdrlen);
|
||||
ast_verbose("Sent RTP packet to %s:%d (type %d, seq %u, ts %u, len %u)\n",
|
||||
ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), codec, rtp->seqno, rtp->lastts,res - hdrlen);
|
||||
}
|
||||
|
||||
rtp->seqno++;
|
||||
@@ -2176,6 +2737,37 @@ static int rtp_do_debug_ip(int fd, int argc, char *argv[])
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static int rtcp_do_debug_ip(int fd, int argc, char *argv[])
|
||||
{
|
||||
struct hostent *hp;
|
||||
struct ast_hostent ahp;
|
||||
char iabuf[INET_ADDRSTRLEN];
|
||||
int port = 0;
|
||||
char *p, *arg;
|
||||
if (argc != 5)
|
||||
return RESULT_SHOWUSAGE;
|
||||
|
||||
arg = argv[4];
|
||||
p = strstr(arg, ":");
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
p++;
|
||||
port = atoi(p);
|
||||
}
|
||||
hp = ast_gethostbyname(arg, &ahp);
|
||||
if (hp == NULL)
|
||||
return RESULT_SHOWUSAGE;
|
||||
rtcpdebugaddr.sin_family = AF_INET;
|
||||
memcpy(&rtcpdebugaddr.sin_addr, hp->h_addr, sizeof(rtcpdebugaddr.sin_addr));
|
||||
rtcpdebugaddr.sin_port = htons(port);
|
||||
if (port == 0)
|
||||
ast_cli(fd, "RTCP Debugging Enabled for IP: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtcpdebugaddr.sin_addr));
|
||||
else
|
||||
ast_cli(fd, "RTCP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtcpdebugaddr.sin_addr), port);
|
||||
rtcpdebug = 1;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static int rtp_do_debug(int fd, int argc, char *argv[])
|
||||
{
|
||||
if(argc != 2) {
|
||||
@@ -2189,6 +2781,27 @@ static int rtp_do_debug(int fd, int argc, char *argv[])
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static int rtcp_do_debug(int fd, int argc, char *argv[]){
|
||||
if(argc != 3){
|
||||
if(argc != 5)
|
||||
return RESULT_SHOWUSAGE;
|
||||
return rtcp_do_debug_ip(fd, argc, argv);
|
||||
}
|
||||
rtcpdebug = 1;
|
||||
memset(&rtcpdebugaddr,0,sizeof(rtcpdebugaddr));
|
||||
ast_cli(fd, "RTCP Debugging Enabled\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static int rtcp_do_stats(int fd, int argc, char *argv[]){
|
||||
if(argc != 3){
|
||||
return RESULT_SHOWUSAGE;
|
||||
}
|
||||
rtcpstats = 1;
|
||||
ast_cli(fd, "RTCP Stats Enabled\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static int rtp_no_debug(int fd, int argc, char *argv[])
|
||||
{
|
||||
if(argc !=3)
|
||||
@@ -2198,6 +2811,25 @@ static int rtp_no_debug(int fd, int argc, char *argv[])
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static int rtcp_no_debug(int fd, int argc, char *argv[])
|
||||
{
|
||||
if(argc !=4)
|
||||
return RESULT_SHOWUSAGE;
|
||||
rtcpdebug = 0;
|
||||
ast_cli(fd,"RTCP Debugging Disabled\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static int rtcp_no_stats(int fd, int argc, char *argv[])
|
||||
{
|
||||
if(argc !=4)
|
||||
return RESULT_SHOWUSAGE;
|
||||
rtcpstats = 0;
|
||||
ast_cli(fd,"RTCP Stats Disabled\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int stun_do_debug(int fd, int argc, char *argv[])
|
||||
{
|
||||
if(argc != 2) {
|
||||
@@ -2244,6 +2876,37 @@ static struct ast_cli_entry cli_debug =
|
||||
static struct ast_cli_entry cli_no_debug =
|
||||
{{ "rtp", "no", "debug", NULL } , rtp_no_debug, "Disable RTP debugging", no_debug_usage };
|
||||
|
||||
static char rtcp_debug_usage[] =
|
||||
"Usage: rtp rtcp debug [ip host[:port]]\n"
|
||||
" Enable dumping of all RTCP packets to and from host.\n";
|
||||
|
||||
static char rtcp_no_debug_usage[] =
|
||||
"Usage: rtp rtcp no debug\n"
|
||||
" Disable all RTCP debugging\n";
|
||||
|
||||
static char rtcp_stats_usage[] =
|
||||
"Usage: rtp rtcp stats\n"
|
||||
" Enable dumping of RTCP stats.\n";
|
||||
|
||||
static char rtcp_no_stats_usage[] =
|
||||
"Usage: rtp rtcp no stats\n"
|
||||
" Disable all RTCP stats\n";
|
||||
|
||||
static struct ast_cli_entry cli_debug_ip_rtcp =
|
||||
{{ "rtp", "rtcp", "debug", "ip", NULL } , rtcp_do_debug, "Enable RTCP debugging on IP", rtcp_debug_usage };
|
||||
|
||||
static struct ast_cli_entry cli_debug_rtcp =
|
||||
{{ "rtp", "rtcp", "debug", NULL } , rtcp_do_debug, "Enable RTCP debugging", rtcp_debug_usage };
|
||||
|
||||
static struct ast_cli_entry cli_no_debug_rtcp =
|
||||
{{ "rtp", "rtcp", "no", "debug", NULL } , rtcp_no_debug, "Disable RTCP debugging", rtcp_no_debug_usage };
|
||||
|
||||
static struct ast_cli_entry cli_stats_rtcp =
|
||||
{{ "rtp", "rtcp", "stats", NULL } , rtcp_do_stats, "Enable RTCP stats", rtcp_stats_usage };
|
||||
|
||||
static struct ast_cli_entry cli_no_stats_rtcp =
|
||||
{{ "rtp", "rtcp", "no", "stats", NULL } , rtcp_no_stats, "Disable RTCP stats", rtcp_no_stats_usage };
|
||||
|
||||
static struct ast_cli_entry cli_stun_debug =
|
||||
{{ "stun", "debug", NULL } , stun_do_debug, "Enable STUN debugging", stun_debug_usage };
|
||||
|
||||
@@ -2274,6 +2937,15 @@ int ast_rtp_reload(void)
|
||||
if (rtpend > 65535)
|
||||
rtpend = 65535;
|
||||
}
|
||||
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
|
||||
if (ast_false(s))
|
||||
@@ -2311,7 +2983,16 @@ void ast_rtp_init(void)
|
||||
ast_cli_register(&cli_debug);
|
||||
ast_cli_register(&cli_debug_ip);
|
||||
ast_cli_register(&cli_no_debug);
|
||||
|
||||
ast_cli_register(&cli_debug_rtcp);
|
||||
ast_cli_register(&cli_debug_ip_rtcp);
|
||||
ast_cli_register(&cli_no_debug_rtcp);
|
||||
|
||||
ast_cli_register(&cli_stats_rtcp);
|
||||
ast_cli_register(&cli_no_stats_rtcp);
|
||||
|
||||
ast_cli_register(&cli_stun_debug);
|
||||
ast_cli_register(&cli_stun_no_debug);
|
||||
ast_rtp_reload();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user