Newer
Older
rtp->txcore.tv_usec -= rtp->txcore.tv_usec % 20000;
if (delivery && (delivery->tv_sec || delivery->tv_usec)) {
/* Use previous txcore */
ms = (delivery->tv_sec - rtp->txcore.tv_sec) * 1000;
ms += (1000000 + delivery->tv_usec - rtp->txcore.tv_usec) / 1000 - 1000;
rtp->txcore.tv_sec = delivery->tv_sec;
rtp->txcore.tv_usec = delivery->tv_usec;
} else {
gettimeofday(&now, NULL);
ms = (now.tv_sec - rtp->txcore.tv_sec) * 1000;
ms += (1000000 + now.tv_usec - rtp->txcore.tv_usec) / 1000 - 1000;
/* Use what we just got for next time */
rtp->txcore.tv_sec = now.tv_sec;
rtp->txcore.tv_usec = now.tv_usec;
}
int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
{
unsigned int *rtpheader;
int hdrlen = 12;
int res;
int x;
char iabuf[INET_ADDRSTRLEN];
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;
}
payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_DTMF);
/* If we have no peer, return immediately */
if (!rtp->them.sin_addr.s_addr)
return 0;
gettimeofday(&rtp->dtmfmute, NULL);
rtp->dtmfmute.tv_usec += (500 * 1000);
if (rtp->dtmfmute.tv_usec > 1000000) {
rtp->dtmfmute.tv_usec -= 1000000;
rtp->dtmfmute.tv_sec += 1;
}
/* 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);
rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
for (x=0;x<4;x++) {
if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
res = sendto(rtp->s, (void *)rtpheader, hdrlen + 4, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
Mark Spencer
committed
ast_log(LOG_NOTICE, "RTP 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 RTP packet to %s:%d (type %d, seq %d, ts %d, 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);
}
if (x ==0) {
/* Clear marker bit and increment seqno */
rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno++));
/* Make duration 800 (100ms) */
rtpheader[3] |= htonl((800));
/* Set the End bit for the last 3 */
rtpheader[3] |= htonl((1 << 23));
} else if ( x < 3) {
rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno++));
#ifdef SOLARIS
static void put_uint32(unsigned char *buf, int i)
{
unsigned char *c = (unsigned char *)&i;
buf[0] = (i>>24) & 0xff;
buf[1] = (i>>16) & 0xff;
buf[2] = (i>>8) & 0xff;
buf[3] = i & 0xff;
}
#else
#define put_uint32(p,v) ((*((unsigned int *)(p))) = (v))
#endif
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) {
pred = rtp->lastts + ms * 8;
switch(f->subclass) {
case AST_FORMAT_ULAW:
case AST_FORMAT_ALAW:
/* If we're within +/- 20ms from when where we
predict we should be, use that */
break;
case AST_FORMAT_ADPCM:
case AST_FORMAT_G726:
/* If we're within +/- 20ms from when where we
predict we should be, use that */
pred = rtp->lastts + f->datalen * 2;
break;
case AST_FORMAT_G729A:
pred = rtp->lastts + f->datalen * 8;
break;
case AST_FORMAT_GSM:
pred = rtp->lastts + (f->datalen * 160 / 33);
break;
case AST_FORMAT_ILBC:
pred = rtp->lastts + (f->datalen * 240 / 50);
break;
case AST_FORMAT_G723_1:
pred = rtp->lastts + g723_samples(f->data, f->datalen);
break;
case AST_FORMAT_SPEEX:
pred = rtp->lastts + 160;
/* assumes that the RTP packet contains one Speex frame */
case AST_FORMAT_LPC10:
/* assumes that the RTP packet contains one LPC10 frame */
pred = rtp->lastts + 22 * 8;
pred += (((char *)(f->data))[7] & 0x1) * 8;
break;
default:
ast_log(LOG_WARNING, "Not sure about timestamp format for codec format %s\n", ast_getformatname(f->subclass));
}
/* Re-calculate last TS */
rtp->lastts = rtp->lastts + ms * 8;
if (!f->delivery.tv_sec && !f->delivery.tv_usec) {
/* 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)
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 */
Mark Spencer
committed
if (!f->delivery.tv_sec && !f->delivery.tv_usec) {
if (abs(rtp->lastts - pred) < 7200) {
rtp->lastts = pred;
rtp->lastovidtimestamp += f->samples;
} else {
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);
rtp->lastovidtimestamp = rtp->lastts;
}
}
/* Get a pointer to the header */
rtpheader = (unsigned char *)(f->data - hdrlen);
put_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (rtp->seqno) | (mark << 23)));
put_uint32(rtpheader + 4, htonl(rtp->lastts));
put_uint32(rtpheader + 8, htonl(rtp->ssrc));
rtp->seqno++;
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));
Mark Spencer
committed
ast_log(LOG_NOTICE, "RTP 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 RTP packet to %s:%d (type %d, seq %d, ts %d, len %d)\n"
, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), codec, rtp->seqno, rtp->lastts,res - hdrlen);
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\n");
return -1;
}
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));
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;
}
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;
}
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
void ast_rtp_proto_unregister(struct ast_rtp_protocol *proto)
{
struct ast_rtp_protocol *cur, *prev;
cur = protos;
prev = NULL;
while(cur) {
if (cur == proto) {
if (prev)
prev->next = proto->next;
else
protos = proto->next;
return;
}
prev = cur;
cur = cur->next;
}
}
int ast_rtp_proto_register(struct ast_rtp_protocol *proto)
{
struct ast_rtp_protocol *cur;
cur = protos;
while(cur) {
if (cur->type == proto->type) {
ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
return -1;
}
cur = cur->next;
}
proto->next = protos;
protos = proto;
return 0;
}
static struct ast_rtp_protocol *get_proto(struct ast_channel *chan)
{
struct ast_rtp_protocol *cur;
cur = protos;
while(cur) {
if (cur->type == chan->type) {
return cur;
}
cur = cur->next;
}
return NULL;
}
int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
{
struct ast_frame *f;
struct ast_channel *who, *cs[3];
struct ast_rtp *p0, *p1;
struct ast_rtp *vp0, *vp1;
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));
/* if need DTMF, cant native bridge */
if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
return -2;
ast_mutex_lock(&c0->lock);
while(ast_mutex_trylock(&c1->lock)) {
ast_mutex_unlock(&c0->lock);
usleep(1);
ast_mutex_lock(&c0->lock);
}
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);
ast_mutex_unlock(&c0->lock);
ast_mutex_unlock(&c1->lock);
return -1;
}
if (!pr1) {
ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name);
ast_mutex_unlock(&c0->lock);
ast_mutex_unlock(&c1->lock);
return -1;
}
pvt0 = c0->pvt->pvt;
pvt1 = c1->pvt->pvt;
p0 = pr0->get_rtp_info(c0);
if (pr0->get_vrtp_info)
vp0 = pr0->get_vrtp_info(c0);
else
vp0 = NULL;
if (pr1->get_vrtp_info)
vp1 = pr1->get_vrtp_info(c1);
else
vp1 = NULL;
if (!p0 || !p1) {
/* Somebody doesn't want to play... */
ast_mutex_unlock(&c0->lock);
ast_mutex_unlock(&c1->lock);
codec0 = pr0->get_codec(c0);
else
codec0 = 0;
if (pr1->get_codec)
codec1 = pr1->get_codec(c1);
else
codec1 = 0;
if (pr0->get_codec && pr1->get_codec) {
/* Hey, we can't do reinvite if both parties speak diffrent codecs */
if (!(codec0 & codec1)) {
Martin Pycko
committed
ast_log(LOG_WARNING, "codec0 = %d is not codec1 = %d, cannot native bridge.\n",codec0,codec1);
Martin Pycko
committed
ast_mutex_unlock(&c0->lock);
ast_mutex_unlock(&c1->lock);
return -2;
Martin Pycko
committed
}
if (pr0->set_rtp_peer(c0, p1, vp1, codec1))
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)
if (pr1->set_rtp_peer(c1, p0, vp0, codec0))
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)
ast_mutex_unlock(&c0->lock);
ast_mutex_unlock(&c1->lock);
cs[0] = c0;
cs[1] = c1;
cs[2] = NULL;
oldcodec0 = codec0;
oldcodec1 = codec1;
for (;;) {
if ((c0->pvt->pvt != pvt0) ||
(c1->pvt->pvt != pvt1) ||
(c0->masq || c0->masqr || c1->masq || c1->masqr)) {
ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n");
if (c0->pvt->pvt == pvt0) {
if (pr0->set_rtp_peer(c0, NULL, NULL, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
}
if (c1->pvt->pvt == pvt1) {
if (pr1->set_rtp_peer(c1, NULL, NULL, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
}
/* Tell it to try again later */
return -3;
}
to = -1;
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",
Mark Spencer
committed
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",
Mark Spencer
committed
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",
Mark Spencer
committed
c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), ac1.sin_addr), ntohs(ac1.sin_port), oldcodec1);
ast_log(LOG_DEBUG, "Oooh, '%s' wasv %s:%d/(format %d)\n",
Mark Spencer
committed
c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), vac1.sin_addr), ntohs(vac1.sin_port), oldcodec1);
if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, codec1))
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))) {
ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n",
Mark Spencer
committed
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",
Mark Spencer
committed
c0->name, ast_inet_ntoa(iabuf, sizeof(iabuf), ac0.sin_addr), ntohs(ac0.sin_port), oldcodec0);
if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, codec0))
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, &to);
if (!who) {
ast_log(LOG_DEBUG, "Ooh, empty read...\n");
/* check for hagnup / whentohangup */
if (ast_check_hangup(c0) || ast_check_hangup(c1))
break;
continue;
}
f = ast_read(who);
if (!f || ((f->frametype == AST_FRAME_DTMF) &&
(((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) ||
((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
*fo = f;
*rc = who;
ast_log(LOG_DEBUG, "Oooh, got a %s\n", f ? "digit" : "hangup");
if ((c0->pvt->pvt == pvt0) && (!c0->_softhangup)) {
if (pr0->set_rtp_peer(c0, NULL, NULL, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
}
if ((c1->pvt->pvt == pvt1) && (!c1->_softhangup)) {
if (pr1->set_rtp_peer(c1, NULL, NULL, 0))
ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
}
/* That's all we needed */
return 0;
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 */
if (who == c0) {
ast_write(c1, f);
} else if (who == c1) {
ast_write(c0, f);
}
}
/* Swap priority not that it's a big deal at this point */
cs[2] = cs[0];
cs[0] = cs[1];
cs[1] = cs[2];
}
return -1;
}
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
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, ":");
if (p){
*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;
}
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 rtp_no_debug(int fd, int argc, char *argv[])
{
if(argc !=3)
return RESULT_SHOWUSAGE;
rtpdebug = 0;
ast_cli(fd,"RTP 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 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 };
void ast_rtp_reload(void)
{
struct ast_config *cfg;
char *s;
rtpstart = 5000;
rtpend = 31000;
#ifdef SO_NO_CHECK
checksums = 1;
#endif
cfg = ast_load("rtp.conf");
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", "rtpchecksums"))) {
#ifdef SO_NO_CHECK
if (ast_true(s))
checksums = 1;
else
checksums = 0;
#else
if (ast_true(s))
ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
#endif
ast_destroy(cfg);
}
if (rtpstart >= rtpend) {
ast_log(LOG_WARNING, "Unreasonable values for RTP start/end\n");
rtpstart = 5000;
rtpend = 31000;
}
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "RTP Allocating from port range %d -> %d\n", rtpstart, rtpend);
ast_cli_register(&cli_debug);
ast_cli_register(&cli_debug_ip);
ast_cli_register(&cli_no_debug);