Newer
Older
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) {
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
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;
int hdrlen = 12;
int res;
int payload;
char data[256];
char iabuf[INET_ADDRSTRLEN];
level = 127 - (level & 0x7f);
payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_CN);
/* If we have no peer, return immediately */
if (!rtp->them.sin_addr.s_addr)
return 0;
Kevin P. Fleming
committed
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 << 16) | (rtp->seqno++));
rtpheader[1] = htonl(rtp->lastts);
rtpheader[2] = htonl(rtp->ssrc);
data[12] = level;
if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
res = sendto(rtp->s, (void *)rtpheader, hdrlen + 1, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
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 %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);
}
return 0;
}
static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec)
unsigned char *rtpheader;
char iabuf[INET_ADDRSTRLEN];
int mark = 0;
ms = calc_txstamp(rtp, &f->delivery);
if (f->subclass < AST_FORMAT_MAX_AUDIO) {
/* Re-calculate last TS */
rtp->lastts = rtp->lastts + ms * 8;
Kevin P. Fleming
committed
if (ast_tvzero(f->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)
if (option_debug > 2)
ast_log(LOG_DEBUG, "Difference is %d, ms is %d\n", abs(rtp->lastts - pred), ms);
} else {
pred = rtp->lastovidtimestamp + f->samples;
/* Re-calculate last TS */
rtp->lastts = rtp->lastts + ms * 90;
/* If it's close to our prediction, go for it */
Kevin P. Fleming
committed
if (ast_tvzero(f->delivery)) {
Mark Spencer
committed
if (abs(rtp->lastts - pred) < 7200) {
rtp->lastts = pred;
rtp->lastovidtimestamp += f->samples;
} else {
if (option_debug > 2)
ast_log(LOG_DEBUG, "Difference is %d, ms is %d (%d), pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, f->samples);
Mark Spencer
committed
rtp->lastovidtimestamp = rtp->lastts;
}
/* If the timestamp for non-digit packets has moved beyond the timestamp
for digits, update the digit timestamp.
*/
if (rtp->lastts > rtp->lastdigitts)
rtp->lastdigitts = rtp->lastts;
Russell Bryant
committed
if (f->has_timing_info)
rtp->lastts = f->ts * 8;
rtpheader = (unsigned char *)(f->data - 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 (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
res = sendto(rtp->s, (void *)rtpheader, f->datalen + hdrlen, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
Kevin P. Fleming
committed
if (res <0) {
if (!rtp->nat || (rtp->nat && (ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
ast_log(LOG_DEBUG, "RTP Transmission error of packet %d to %s:%d: %s\n", rtp->seqno, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
} else if ((ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) {
/* Only give this error message once if we are not RTP debugging */
if (option_debug || rtpdebug)
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);
Kevin P. Fleming
committed
}
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);
rtp->seqno++;
int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
{
struct ast_frame *f;
int codec;
int hdrlen = 12;
/* If we have no peer, return immediately */
if (!rtp->them.sin_addr.s_addr)
return 0;
/* If there is no data length, return immediately */
if (!_f->datalen)
return 0;
/* Make sure we have enough space for RTP header */
if ((_f->frametype != AST_FRAME_VOICE) && (_f->frametype != AST_FRAME_VIDEO)) {
ast_log(LOG_WARNING, "RTP can only send voice and video\n");
subclass = _f->subclass;
if (_f->frametype == AST_FRAME_VIDEO)
subclass &= ~0x1;
codec = ast_rtp_lookup_code(rtp, 1, subclass);
ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", ast_getformatname(_f->subclass));
if (option_debug)
ast_log(LOG_DEBUG, "Ooh, format changed from %s to %s\n", ast_getformatname(rtp->lasttxformat), ast_getformatname(subclass));
if (rtp->smoother)
ast_smoother_free(rtp->smoother);
rtp->smoother = NULL;
}
Kevin P. Fleming
committed
case AST_FORMAT_SLINEAR:
if (!rtp->smoother) {
rtp->smoother = ast_smoother_new(320);
}
if (!rtp->smoother) {
ast_log(LOG_WARNING, "Unable to create smoother :(\n");
return -1;
}
ast_smoother_feed_be(rtp->smoother, _f);
while((f = ast_smoother_read(rtp->smoother)))
ast_rtp_raw_write(rtp, f, codec);
break;
case AST_FORMAT_ULAW:
case AST_FORMAT_ALAW:
if (!rtp->smoother) {
rtp->smoother = ast_smoother_new(160);
}
if (!rtp->smoother) {
ast_log(LOG_WARNING, "Unable to create smoother :(\n");
return -1;
}
ast_smoother_feed(rtp->smoother, _f);
while((f = ast_smoother_read(rtp->smoother)))
ast_rtp_raw_write(rtp, f, codec);
break;
case AST_FORMAT_G726:
if (!rtp->smoother) {
rtp->smoother = ast_smoother_new(80);
}
if (!rtp->smoother) {
ast_log(LOG_WARNING, "Unable to create smoother :(\n");
return -1;
}
ast_smoother_feed(rtp->smoother, _f);
while((f = ast_smoother_read(rtp->smoother)))
ast_rtp_raw_write(rtp, f, codec);
break;
case AST_FORMAT_G729A:
if (!rtp->smoother) {
rtp->smoother = ast_smoother_new(20);
if (rtp->smoother)
ast_smoother_set_flags(rtp->smoother, AST_SMOOTHER_FLAG_G729);
}
if (!rtp->smoother) {
ast_log(LOG_WARNING, "Unable to create g729 smoother :(\n");
return -1;
}
ast_smoother_feed(rtp->smoother, _f);
while((f = ast_smoother_read(rtp->smoother)))
ast_rtp_raw_write(rtp, f, codec);
break;
case AST_FORMAT_GSM:
if (!rtp->smoother) {
rtp->smoother = ast_smoother_new(33);
}
if (!rtp->smoother) {
ast_log(LOG_WARNING, "Unable to create GSM smoother :(\n");
return -1;
}
ast_smoother_feed(rtp->smoother, _f);
while((f = ast_smoother_read(rtp->smoother)))
ast_rtp_raw_write(rtp, f, codec);
break;
}
if (!rtp->smoother) {
ast_log(LOG_WARNING, "Unable to create ILBC smoother :(\n");
return -1;
}
ast_smoother_feed(rtp->smoother, _f);
while((f = ast_smoother_read(rtp->smoother)))
ast_rtp_raw_write(rtp, f, codec);
break;
ast_log(LOG_WARNING, "Not sure about sending format %s packets\n", ast_getformatname(subclass));
case AST_FORMAT_H261:
case AST_FORMAT_H263:
/* Don't buffer outgoing frames; send them one-per-packet: */
if (_f->offset < hdrlen) {
f = ast_frdup(_f);
} else {
f = _f;
}
ast_rtp_raw_write(rtp, f, codec);
}
return 0;
}
Olle Johansson
committed
/*! \brief Unregister interface to channel driver */
void ast_rtp_proto_unregister(struct ast_rtp_protocol *proto)
{
Olle Johansson
committed
AST_LIST_LOCK(&protos);
AST_LIST_REMOVE(&protos, proto, list);
Olle Johansson
committed
AST_LIST_UNLOCK(&protos);
Olle Johansson
committed
/*! \brief Register interface to channel driver */
int ast_rtp_proto_register(struct ast_rtp_protocol *proto)
{
struct ast_rtp_protocol *cur;
Olle Johansson
committed
AST_LIST_LOCK(&protos);
AST_LIST_TRAVERSE(&protos, cur, list) {
if (!strcmp(cur->type, proto->type)) {
ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
Olle Johansson
committed
AST_LIST_UNLOCK(&protos);
Olle Johansson
committed
AST_LIST_INSERT_HEAD(&protos, proto, list);
AST_LIST_UNLOCK(&protos);
Olle Johansson
committed
/*! \brief Bridge calls. If possible and allowed, initiate
re-invite so the peers exchange media directly outside
of Asterisk. */
enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
struct ast_channel *who, *other, *cs[3];
struct ast_rtp *p0, *p1; /* Audio RTP Channels */
struct ast_rtp *vp0, *vp1; /* Video RTP channels */
struct sockaddr_in vac0, vac1;
struct sockaddr_in vt0, vt1;
char iabuf[INET_ADDRSTRLEN];
int codec0,codec1, oldcodec0, oldcodec1;
memset(&vt0, 0, sizeof(vt0));
memset(&vt1, 0, sizeof(vt1));
memset(&vac0, 0, sizeof(vac0));
memset(&vac1, 0, sizeof(vac1));
Joshua Colp
committed
ast_channel_lock(c0);
while(ast_channel_trylock(c1)) {
ast_channel_unlock(c0);
Joshua Colp
committed
ast_channel_lock(c0);
/* Find channel driver interfaces */
pr0 = get_proto(c0);
pr1 = get_proto(c1);
if (!pr0) {
ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name);
Joshua Colp
committed
ast_channel_unlock(c0);
ast_channel_unlock(c1);
}
if (!pr1) {
ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name);
Joshua Colp
committed
ast_channel_unlock(c0);
ast_channel_unlock(c1);
/* Get channel specific interface structures */
pvt0 = c0->tech_pvt;
pvt1 = c1->tech_pvt;
/* Get audio and video interface (if native bridge is possible) */
vp0 = pr0->get_vrtp_info ? pr0->get_vrtp_info(c0) : NULL;
vp1 = pr1->get_vrtp_info ? pr1->get_vrtp_info(c1) : NULL;
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
if (!p0 || !p1) {
/* Somebody doesn't want to play... */
Joshua Colp
committed
ast_channel_unlock(c0);
ast_channel_unlock(c1);
if (ast_test_flag(p0, FLAG_HAS_DTMF) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
/* can't bridge, we are carrying DTMF for this channel and the bridge
needs it
*/
ast_channel_unlock(c0);
ast_channel_unlock(c1);
return AST_BRIDGE_FAILED_NOWARN;
}
if (ast_test_flag(p1, FLAG_HAS_DTMF) && (flags & AST_BRIDGE_DTMF_CHANNEL_1)) {
/* can't bridge, we are carrying DTMF for this channel and the bridge
needs it
*/
ast_channel_unlock(c0);
ast_channel_unlock(c1);
return AST_BRIDGE_FAILED_NOWARN;
}
/* Get codecs from both sides */
codec0 = pr0->get_codec ? pr0->get_codec(c0) : 0;
codec1 = pr1->get_codec ? pr1->get_codec(c1) : 0;
if (pr0->get_codec && pr1->get_codec) {
/* Hey, we can't do reinvite if both parties speak different codecs */
if (!(codec0 & codec1)) {
if (option_debug)
ast_log(LOG_DEBUG, "Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP.\n", codec0, codec1);
Joshua Colp
committed
ast_channel_unlock(c0);
ast_channel_unlock(c1);
Martin Pycko
committed
}
Kevin P. Fleming
committed
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Native bridging %s and %s\n", c0->name, c1->name);
/* Ok, we should be able to redirect the media. Start with one channel */
Kevin P. Fleming
committed
if (pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))
ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
else {
/* Store RTP peer */
ast_rtp_get_peer(p1, &ac1);
if (vp1)
/* Then test the other channel */
Kevin P. Fleming
committed
if (pr1->set_rtp_peer(c1, p0, vp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name);
else {
/* Store RTP peer */
ast_rtp_get_peer(p0, &ac0);
if (vp0)
Joshua Colp
committed
ast_channel_unlock(c0);
ast_channel_unlock(c1);
/* External RTP Bridge up, now loop and see if something happes that force us to take the
media back to Asterisk */
cs[0] = c0;
cs[1] = c1;
cs[2] = NULL;
oldcodec0 = codec0;
oldcodec1 = codec1;
/* Check if something changed... */
if ((c0->tech_pvt != pvt0) ||
(c1->tech_pvt != pvt1) ||
(c0->masq || c0->masqr || c1->masq || c1->masqr)) {
ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n");
if (c0->tech_pvt == pvt0) {
Kevin P. Fleming
committed
if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
if (c1->tech_pvt == pvt1) {
Kevin P. Fleming
committed
if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
/* Now check if they have changed address */
if (pr0->get_codec)
codec0 = pr0->get_codec(c0);
if (pr1->get_codec)
codec1 = pr1->get_codec(c1);
if (vp1)
ast_rtp_get_peer(vp1, &vt1);
if (vp0)
ast_rtp_get_peer(vp0, &vt0);
if (inaddrcmp(&t1, &ac1) || (vp1 && inaddrcmp(&vt1, &vac1)) || (codec1 != oldcodec1)) {
ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n",
c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), t1.sin_addr), ntohs(t1.sin_port), codec1);
ast_log(LOG_DEBUG, "Oooh, '%s' changed end vaddress to %s:%d (format %d)\n",
c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), vt1.sin_addr), ntohs(vt1.sin_port), codec1);
ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n",
c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), ac1.sin_addr), ntohs(ac1.sin_port), oldcodec1);
Kevin P. Fleming
committed
ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n",
c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), vac1.sin_addr), ntohs(vac1.sin_port), oldcodec1);
}
Kevin P. Fleming
committed
if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))
ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
memcpy(&ac1, &t1, sizeof(ac1));
memcpy(&vac1, &vt1, sizeof(vac1));
if (inaddrcmp(&t0, &ac0) || (vp0 && inaddrcmp(&vt0, &vac0))) {
if (option_debug) {
ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n",
c0->name, ast_inet_ntoa(iabuf, sizeof(iabuf), t0.sin_addr), ntohs(t0.sin_port), codec0);
ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n",
c0->name, ast_inet_ntoa(iabuf, sizeof(iabuf), ac0.sin_addr), ntohs(ac0.sin_port), oldcodec0);
}
Kevin P. Fleming
committed
if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
memcpy(&ac0, &t0, sizeof(ac0));
memcpy(&vac0, &vt0, sizeof(vac0));
who = ast_waitfor_n(cs, 2, &timeoutms);
Mark Spencer
committed
if (!timeoutms)
return AST_BRIDGE_RETRY;
if (option_debug)
ast_log(LOG_DEBUG, "Ooh, empty read...\n");
/* check for hangup / whentohangup */
if (ast_check_hangup(c0) || ast_check_hangup(c1))
break;
continue;
}
f = ast_read(who);
other = (who == c0) ? c1 : c0; /* the other channel */
if (!f || ((f->frametype == AST_FRAME_DTMF) &&
(((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) ||
((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
/* breaking out of the bridge. */
if (option_debug)
ast_log(LOG_DEBUG, "Oooh, got a %s\n", f ? "digit" : "hangup");
if ((c0->tech_pvt == pvt0)) {
Kevin P. Fleming
committed
if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
if ((c1->tech_pvt == pvt1)) {
Kevin P. Fleming
committed
if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
} else if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD) ||
(f->subclass == AST_CONTROL_VIDUPDATE)) {
ast_indicate(other, f->subclass);
ast_frfree(f);
} else {
*fo = f;
*rc = who;
ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
return AST_BRIDGE_COMPLETE;
}
if ((f->frametype == AST_FRAME_DTMF) ||
(f->frametype == AST_FRAME_VOICE) ||
(f->frametype == AST_FRAME_VIDEO)) {
/* Forward voice or DTMF frames if they happen upon us */
/* Swap priority not that it's a big deal at this point */
cs[2] = cs[0];
cs[0] = cs[1];
cs[1] = cs[2];
}
static int rtp_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 != 4)
return RESULT_SHOWUSAGE;
arg = argv[3];
p = strstr(arg, ":");
*p = '\0';
p++;
port = atoi(p);
}
hp = ast_gethostbyname(arg, &ahp);
if (hp == NULL)
return RESULT_SHOWUSAGE;
rtpdebugaddr.sin_family = AF_INET;
memcpy(&rtpdebugaddr.sin_addr, hp->h_addr, sizeof(rtpdebugaddr.sin_addr));
rtpdebugaddr.sin_port = htons(port);
if (port == 0)
ast_cli(fd, "RTP Debugging Enabled for IP: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtpdebugaddr.sin_addr));
else
ast_cli(fd, "RTP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtpdebugaddr.sin_addr), port);
rtpdebug = 1;
return RESULT_SUCCESS;
}
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
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) {
if (argc != 4)
return RESULT_SHOWUSAGE;
return rtp_do_debug_ip(fd, argc, argv);
}
rtpdebug = 1;
memset(&rtpdebugaddr,0,sizeof(rtpdebugaddr));
ast_cli(fd, "RTP Debugging Enabled\n");
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[])
{
return RESULT_SHOWUSAGE;
rtpdebug = 0;
ast_cli(fd,"RTP Debugging Disabled\n");
return RESULT_SUCCESS;
}
static int rtcp_no_debug(int fd, int argc, char *argv[])
{
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[])
{
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[])
{
return RESULT_SHOWUSAGE;
}
stundebug = 1;
ast_cli(fd, "STUN Debugging Enabled\n");
return RESULT_SUCCESS;
}
static int stun_no_debug(int fd, int argc, char *argv[])
{
return RESULT_SHOWUSAGE;
stundebug = 0;
ast_cli(fd,"STUN Debugging Disabled\n");
return RESULT_SUCCESS;
}
static char debug_usage[] =
"Usage: rtp debug [ip host[:port]]\n"
" Enable dumping of all RTP packets to and from host.\n";
static char no_debug_usage[] =
"Usage: rtp no debug\n"
" Disable all RTP debugging\n";
static char stun_debug_usage[] =
"Usage: stun debug\n"
" Enable STUN (Simple Traversal of UDP through NATs) debugging\n";
static char stun_no_debug_usage[] =
"Usage: stun no debug\n"
" Disable STUN debugging\n";
static struct ast_cli_entry cli_debug_ip =
{{ "rtp", "debug", "ip", NULL } , rtp_do_debug, "Enable RTP debugging on IP", debug_usage };
static struct ast_cli_entry cli_debug =
{{ "rtp", "debug", NULL } , rtp_do_debug, "Enable RTP debugging", debug_usage };
static struct ast_cli_entry cli_no_debug =
{{ "rtp", "no", "debug", NULL } , rtp_no_debug, "Disable RTP debugging", no_debug_usage };
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
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 };
static struct ast_cli_entry cli_stun_no_debug =
{{ "stun", "no", "debug", NULL } , stun_no_debug, "Disable STUN debugging", stun_no_debug_usage };
{
struct ast_config *cfg;
char *s;
dtmftimeout = DEFAULT_DTMF_TIMEOUT;
if (cfg) {
if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) {
rtpstart = atoi(s);
if (rtpstart < 1024)
rtpstart = 1024;
if (rtpstart > 65535)
rtpstart = 65535;
}
if ((s = ast_variable_retrieve(cfg, "general", "rtpend"))) {
rtpend = atoi(s);
if (rtpend < 1024)
rtpend = 1024;
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))
nochecksums = 1;
nochecksums = 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 > 20000)) {
ast_log(LOG_WARNING, "DTMF timeout of '%d' outside range, using default of '%d' instead\n",
dtmftimeout, DEFAULT_DTMF_TIMEOUT);
dtmftimeout = DEFAULT_DTMF_TIMEOUT;
};
}
ast_log(LOG_WARNING, "Unreasonable values for RTP start/end port in rtp.conf\n");
rtpstart = 5000;
rtpend = 31000;
}
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "RTP Allocating from port range %d -> %d\n", rtpstart, rtpend);
Olle Johansson
committed
/*! \brief Initialize the RTP system in Asterisk */
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);