Newer
Older
rtpheader[3] |= htonl((1 << 23));
}
}
return 0;
}
static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec)
Mark Spencer
committed
char iabuf[80];
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
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) < 640)
rtp->lastts = pred;
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 int *)(f->data - hdrlen);
rtpheader[0] = htonl((2 << 30) | (codec << 16) | (rtp->seqno++) | (mark << 23));
rtpheader[1] = htonl(rtp->lastts);
rtpheader[2] = 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));
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));
Mark Spencer
committed
printf("Sent %d bytes of RTP data to %s:%d\n", res, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port));
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:
case AST_FORMAT_SPEEX:
// 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;
}
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
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;
Mark Spencer
committed
char iabuf[80];
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);
ast_mutex_lock(&c1->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;
}
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
void ast_rtp_reload(void)
{
struct ast_config *cfg;
char *s;
rtpstart = 5000;
rtpend = 31000;
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;
}
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);
}
void ast_rtp_init(void)
{
ast_rtp_reload();
}