Newer
Older
/* This is special in-band data that's not one of our codecs */
if (rtpPT.code == AST_RTP_DTMF) {
/* It's special -- rfc2833 process it */
unsigned char *data;
unsigned int event;
unsigned int event_end;
unsigned int duration;
data = rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen;
event = ntohl(*((unsigned int *)(data)));
event >>= 24;
event_end = ntohl(*((unsigned int *)(data)));
event_end <<= 8;
event_end >>= 24;
duration = ntohl(*((unsigned int *)(data)));
duration &= 0xFFFF;
ast_verbose("Got rfc2833 RTP packet from %s:%d (type %d, seq %d, ts %d, len %d, mark %d, event %08x, end %d, duration %d) \n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp, res - hdrlen, (mark?1:0), event, ((event_end & 0x80)?1:0), duration);
}
if (rtp->lasteventseqn <= seqno || rtp->resp == 0 || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno);
rtp->lasteventseqn = seqno;
} else if (rtpPT.code == AST_RTP_CISCO_DTMF) {
/* It's really special -- process it the Cisco way */
if (rtp->lasteventseqn <= seqno || rtp->resp == 0 || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
f = process_cisco_dtmf(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
rtp->lasteventseqn = seqno;
} else if (rtpPT.code == AST_RTP_CN) {
/* Comfort Noise */
f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
} else {
ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n", payloadtype, ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr));
rtp->lastrxformat = rtp->f.subclass = rtpPT.code;
rtp->f.frametype = (rtp->f.subclass < AST_FORMAT_MAX_AUDIO) ? AST_FRAME_VOICE : AST_FRAME_VIDEO;
if (!rtp->lastrxts)
rtp->lastrxts = timestamp;
Mark Spencer
committed
rtp->rxseqno = seqno;
if (rtp->dtmfcount) {
#if 0
printf("dtmfcount was %d\n", rtp->dtmfcount);
#endif
rtp->dtmfcount -= (timestamp - rtp->lastrxts);
if (rtp->dtmfcount < 0)
rtp->dtmfcount = 0;
#if 0
if (dtmftimeout != rtp->dtmfcount)
printf("dtmfcount is %d\n", rtp->dtmfcount);
#endif
}
rtp->lastrxts = timestamp;
/* Send any pending DTMF */
if (rtp->resp && !rtp->dtmfcount) {
if (option_debug)
ast_log(LOG_DEBUG, "Sending pending DTMF\n");
rtp->f.data = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
if (rtp->f.subclass < AST_FORMAT_MAX_AUDIO) {
rtp->f.samples = ast_codec_get_samples(&rtp->f);
if (rtp->f.subclass == AST_FORMAT_SLINEAR)
Kevin P. Fleming
committed
ast_frame_byteswap_be(&rtp->f);
calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
Russell Bryant
committed
/* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
rtp->f.has_timing_info = 1;
rtp->f.ts = timestamp / 8;
rtp->f.len = rtp->f.samples / 8;
rtp->f.seqno = seqno;
} else {
/* Video -- samples is # of samples vs. 90000 */
if (!rtp->lastividtimestamp)
rtp->lastividtimestamp = timestamp;
rtp->f.samples = timestamp - rtp->lastividtimestamp;
rtp->lastividtimestamp = timestamp;
Mark Spencer
committed
rtp->f.delivery.tv_sec = 0;
rtp->f.delivery.tv_usec = 0;
if (mark)
rtp->f.subclass |= 0x1;
/* The following array defines the MIME Media type (and subtype) for each
of our codecs, or RTP-specific data type. */
Olle Johansson
committed
struct rtpPayloadType payloadType;
char* type;
char* subtype;
Olle Johansson
committed
{{1, AST_FORMAT_G723_1}, "audio", "G723"},
{{1, AST_FORMAT_GSM}, "audio", "GSM"},
{{1, AST_FORMAT_ULAW}, "audio", "PCMU"},
{{1, AST_FORMAT_ALAW}, "audio", "PCMA"},
{{1, AST_FORMAT_G726}, "audio", "G726-32"},
{{1, AST_FORMAT_ADPCM}, "audio", "DVI4"},
{{1, AST_FORMAT_SLINEAR}, "audio", "L16"},
{{1, AST_FORMAT_LPC10}, "audio", "LPC"},
{{1, AST_FORMAT_G729A}, "audio", "G729"},
{{1, AST_FORMAT_SPEEX}, "audio", "speex"},
{{1, AST_FORMAT_ILBC}, "audio", "iLBC"},
{{0, AST_RTP_DTMF}, "audio", "telephone-event"},
{{0, AST_RTP_CISCO_DTMF}, "audio", "cisco-telephone-event"},
{{0, AST_RTP_CN}, "audio", "CN"},
{{1, AST_FORMAT_JPEG}, "video", "JPEG"},
{{1, AST_FORMAT_PNG}, "video", "PNG"},
{{1, AST_FORMAT_H261}, "video", "H261"},
{{1, AST_FORMAT_H263}, "video", "H263"},
{{1, AST_FORMAT_H263_PLUS}, "video", "h263-1998"},
{{1, AST_FORMAT_H264}, "video", "H264"},
Mark Spencer
committed
/* Static (i.e., well-known) RTP payload types for our "AST_FORMAT..."s:
also, our own choices for dynamic payload types. This is our master
table for transmission */
static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
Olle Johansson
committed
[0] = {1, AST_FORMAT_ULAW},
#ifdef USE_DEPRECATED_G726
Olle Johansson
committed
[2] = {1, AST_FORMAT_G726}, /* Technically this is G.721, but if Cisco can do it, so can we... */
Olle Johansson
committed
[3] = {1, AST_FORMAT_GSM},
[4] = {1, AST_FORMAT_G723_1},
[5] = {1, AST_FORMAT_ADPCM}, /* 8 kHz */
[6] = {1, AST_FORMAT_ADPCM}, /* 16 kHz */
[7] = {1, AST_FORMAT_LPC10},
[8] = {1, AST_FORMAT_ALAW},
[10] = {1, AST_FORMAT_SLINEAR}, /* 2 channels */
[11] = {1, AST_FORMAT_SLINEAR}, /* 1 channel */
[13] = {0, AST_RTP_CN},
[16] = {1, AST_FORMAT_ADPCM}, /* 11.025 kHz */
[17] = {1, AST_FORMAT_ADPCM}, /* 22.050 kHz */
[18] = {1, AST_FORMAT_G729A},
[19] = {0, AST_RTP_CN}, /* Also used for CN */
[26] = {1, AST_FORMAT_JPEG},
[31] = {1, AST_FORMAT_H261},
[34] = {1, AST_FORMAT_H263},
[103] = {1, AST_FORMAT_H263_PLUS},
[97] = {1, AST_FORMAT_ILBC},
[99] = {1, AST_FORMAT_H264},
Olle Johansson
committed
[101] = {0, AST_RTP_DTMF},
[110] = {1, AST_FORMAT_SPEEX},
[111] = {1, AST_FORMAT_G726},
[121] = {0, AST_RTP_CISCO_DTMF}, /* Must be type 121 */
void ast_rtp_pt_clear(struct ast_rtp* rtp)
{
Kevin P. Fleming
committed
if (!rtp)
return;
for (i = 0; i < MAX_RTP_PT; ++i) {
rtp->current_RTP_PT[i].isAstFormat = 0;
rtp->current_RTP_PT[i].code = 0;
}
rtp->rtp_lookup_code_cache_isAstFormat = 0;
rtp->rtp_lookup_code_cache_code = 0;
rtp->rtp_lookup_code_cache_result = 0;
void ast_rtp_pt_default(struct ast_rtp* rtp)
{
int i;
/* Initialize to default payload types */
for (i = 0; i < MAX_RTP_PT; ++i) {
rtp->current_RTP_PT[i].isAstFormat = static_RTP_PT[i].isAstFormat;
rtp->current_RTP_PT[i].code = static_RTP_PT[i].code;
}
rtp->rtp_lookup_code_cache_isAstFormat = 0;
rtp->rtp_lookup_code_cache_code = 0;
rtp->rtp_lookup_code_cache_result = 0;
static void ast_rtp_pt_copy(struct ast_rtp *dest, struct ast_rtp *src)
{
int i;
/* Copy payload types from source to destination */
for (i=0; i < MAX_RTP_PT; ++i) {
dest->current_RTP_PT[i].isAstFormat =
src->current_RTP_PT[i].isAstFormat;
dest->current_RTP_PT[i].code =
src->current_RTP_PT[i].code;
}
dest->rtp_lookup_code_cache_isAstFormat = 0;
dest->rtp_lookup_code_cache_code = 0;
dest->rtp_lookup_code_cache_result = 0;
}
Olle Johansson
committed
/*! \brief Get channel driver interface structure */
static struct ast_rtp_protocol *get_proto(struct ast_channel *chan)
{
struct ast_rtp_protocol *cur = NULL;
Olle Johansson
committed
AST_LIST_LOCK(&protos);
AST_LIST_TRAVERSE(&protos, cur, list) {
if (cur->type == chan->tech->type)
break;
}
Olle Johansson
committed
AST_LIST_UNLOCK(&protos);
return cur;
}
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
int ast_rtp_early_media(struct ast_channel *dest, struct ast_channel *src)
{
struct ast_rtp *destp, *srcp=NULL; /* Audio RTP Channels */
struct ast_rtp *vdestp, *vsrcp=NULL; /* Video RTP channels */
struct ast_rtp_protocol *destpr, *srcpr=NULL;
int srccodec;
/* Lock channels */
ast_channel_lock(dest);
if (src) {
while(ast_channel_trylock(src)) {
ast_channel_unlock(dest);
usleep(1);
ast_channel_lock(dest);
}
}
/* Find channel driver interfaces */
destpr = get_proto(dest);
if (src)
srcpr = get_proto(src);
if (!destpr) {
if (option_debug)
ast_log(LOG_DEBUG, "Channel '%s' has no RTP, not doing anything\n", dest->name);
ast_channel_unlock(dest);
if (src)
ast_channel_unlock(src);
return 0;
}
if (!srcpr) {
if (option_debug)
ast_log(LOG_DEBUG, "Channel '%s' has no RTP, not doing anything\n", src ? src->name : "<unspecified>");
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
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
ast_channel_unlock(dest);
if (src)
ast_channel_unlock(src);
return 0;
}
/* Get audio and video interface (if native bridge is possible) */
destp = destpr->get_rtp_info(dest);
vdestp = (destpr->get_vrtp_info) ? destpr->get_vrtp_info(dest) : NULL;
if (srcpr) {
srcp = srcpr->get_rtp_info(src);
vsrcp = (srcpr->get_vrtp_info) ? srcpr->get_vrtp_info(src) : NULL;
}
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
if (!destp) {
/* Somebody doesn't want to play... */
ast_channel_unlock(dest);
if (src)
ast_channel_unlock(src);
return 0;
}
if (srcpr && srcpr->get_codec)
srccodec = srcpr->get_codec(src);
else
srccodec = 0;
/* Consider empty media as non-existant */
if (srcp && !srcp->them.sin_addr.s_addr)
srcp = NULL;
/* Bridge early media */
if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, srcp ? ast_test_flag(srcp, FLAG_NAT_ACTIVE) : 0))
ast_log(LOG_WARNING, "Channel '%s' failed to send early media to '%s'\n", dest->name, src ? src->name : "<unspecified>");
ast_channel_unlock(dest);
if (src)
ast_channel_unlock(src);
if (option_debug)
ast_log(LOG_DEBUG, "Setting early media SDP of '%s' with that of '%s'\n", dest->name, src ? src->name : "<unspecified>");
return 1;
}
int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, int media)
{
struct ast_rtp *destp, *srcp; /* Audio RTP Channels */
struct ast_rtp *vdestp, *vsrcp; /* Video RTP channels */
struct ast_rtp_protocol *destpr, *srcpr;
int srccodec;
/* Lock channels */
Joshua Colp
committed
ast_channel_lock(dest);
while(ast_channel_trylock(src)) {
ast_channel_unlock(dest);
usleep(1);
Joshua Colp
committed
ast_channel_lock(dest);
}
/* Find channel driver interfaces */
destpr = get_proto(dest);
srcpr = get_proto(src);
if (!destpr) {
Olle Johansson
committed
if (option_debug)
ast_log(LOG_DEBUG, "Channel '%s' has no RTP, not doing anything\n", dest->name);
Joshua Colp
committed
ast_channel_unlock(dest);
ast_channel_unlock(src);
return 0;
}
if (!srcpr) {
Olle Johansson
committed
if (option_debug)
ast_log(LOG_DEBUG, "Channel '%s' has no RTP, not doing anything\n", src->name);
Joshua Colp
committed
ast_channel_unlock(dest);
ast_channel_unlock(src);
return 0;
}
/* Get audio and video interface (if native bridge is possible) */
destp = destpr->get_rtp_info(dest);
vdestp = (destpr->get_vrtp_info) ? destpr->get_vrtp_info(dest) : NULL;
srcp = srcpr->get_rtp_info(src);
vsrcp = (srcpr->get_vrtp_info) ? srcpr->get_vrtp_info(src) : NULL;
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
if (!destp || !srcp) {
/* Somebody doesn't want to play... */
Joshua Colp
committed
ast_channel_unlock(dest);
ast_channel_unlock(src);
return 0;
}
ast_rtp_pt_copy(destp, srcp);
if (vdestp && vsrcp)
ast_rtp_pt_copy(vdestp, vsrcp);
if (srcpr->get_codec)
srccodec = srcpr->get_codec(src);
else
srccodec = 0;
if (media) {
/* Bridge early media */
if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
ast_log(LOG_WARNING, "Channel '%s' failed to send early media to '%s'\n", dest->name, src->name);
}
Joshua Colp
committed
ast_channel_unlock(dest);
ast_channel_unlock(src);
Olle Johansson
committed
if (option_debug)
ast_log(LOG_DEBUG, "Seeded SDP of '%s' with that of '%s'\n", dest->name, src->name);
return 1;
}
/*! \brief Make a note of a RTP payload type that was seen in a SDP "m=" line.
Olle Johansson
committed
* By default, use the well-known value for this type (although it may
* still be set to a different value by a subsequent "a=rtpmap:" line)
*/
void ast_rtp_set_m_type(struct ast_rtp* rtp, int pt)
{
if (pt < 0 || pt > MAX_RTP_PT)
return; /* bogus payload type */
if (static_RTP_PT[pt].code != 0)
rtp->current_RTP_PT[pt] = static_RTP_PT[pt];
Olle Johansson
committed
/*! \brief Make a note of a RTP payload type (with MIME type) that was seen in
a SDP "a=rtpmap:" line. */
void ast_rtp_set_rtpmap_type(struct ast_rtp* rtp, int pt,
char* mimeType, char* mimeSubtype)
{
if (pt < 0 || pt > MAX_RTP_PT)
return; /* bogus payload type */
for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
if (strcasecmp(mimeSubtype, mimeTypes[i].subtype) == 0 &&
strcasecmp(mimeType, mimeTypes[i].type) == 0) {
rtp->current_RTP_PT[pt] = mimeTypes[i].payloadType;
Olle Johansson
committed
/*! \brief Return the union of all of the codecs that were set by rtp_set...() calls
* They're returned as two distinct sets: AST_FORMATs, and AST_RTPs */
void ast_rtp_get_current_formats(struct ast_rtp* rtp,
int* astFormats, int* nonAstFormats) {
int pt;
*astFormats = *nonAstFormats = 0;
for (pt = 0; pt < MAX_RTP_PT; ++pt) {
if (rtp->current_RTP_PT[pt].isAstFormat) {
*astFormats |= rtp->current_RTP_PT[pt].code;
} else {
*nonAstFormats |= rtp->current_RTP_PT[pt].code;
}
}
struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt)
{
struct rtpPayloadType result;
result.isAstFormat = result.code = 0;
if (pt < 0 || pt > MAX_RTP_PT)
return result; /* bogus payload type */
/* Start with negotiated codecs */
result = rtp->current_RTP_PT[pt];
/* If it doesn't exist, check our static RTP type list, just in case */
if (!result.code)
result = static_RTP_PT[pt];
return result;
Olle Johansson
committed
/*! \brief Looks up an RTP code out of our *static* outbound list */
int ast_rtp_lookup_code(struct ast_rtp* rtp, const int isAstFormat, const int code) {
Mark Spencer
committed
if (isAstFormat == rtp->rtp_lookup_code_cache_isAstFormat &&
code == rtp->rtp_lookup_code_cache_code) {
/* Use our cached mapping, to avoid the overhead of the loop below */
return rtp->rtp_lookup_code_cache_result;
}
/* 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) {
rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
rtp->rtp_lookup_code_cache_code = code;
rtp->rtp_lookup_code_cache_result = pt;
return pt;
}
}
/* Then the static list */
for (pt = 0; pt < MAX_RTP_PT; ++pt) {
if (static_RTP_PT[pt].code == code && static_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;
return pt;
}
}
return -1;
char* ast_rtp_lookup_mime_subtype(const int isAstFormat, const int code)
{
int i;
for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
if (mimeTypes[i].payloadType.code == code && mimeTypes[i].payloadType.isAstFormat == isAstFormat)
return mimeTypes[i].subtype;
char *ast_rtp_lookup_mime_multiple(char *buf, int size, const int capability, const int isAstFormat)
{
int format;
unsigned len;
char *end = buf;
char *start = buf;
if (!buf || !size)
return NULL;
snprintf(end, size, "0x%x (", capability);
len = strlen(end);
end += len;
size -= len;
start = end;
for (format = 1; format < AST_RTP_MAX; format <<= 1) {
if (capability & format) {
const char *name = ast_rtp_lookup_mime_subtype(isAstFormat, format);
snprintf(end, size, "%s|", name);
len = strlen(end);
end += len;
size -= len;
}
}
if (start == end)
snprintf(start, size, "nothing)");
else if (size > 1)
*(end -1) = ')';
return buf;
}
static int rtp_socket(void)
{
int s;
long flags;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s > -1) {
flags = fcntl(s, F_GETFL);
fcntl(s, F_SETFL, flags | O_NONBLOCK);
#ifdef SO_NO_CHECK
if (nochecksums)
setsockopt(s, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
#endif
/*!
* \brief Initialize a new RTCP session.
*
* \returns The newly initialized RTCP session.
*/
static struct ast_rtcp *ast_rtcp_new(void)
{
struct ast_rtcp *rtcp;
if (!(rtcp = ast_calloc(1, sizeof(*rtcp))))
return NULL;
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 RTCP socket: %s\n", strerror(errno));
return NULL;
}
return rtcp;
}
struct ast_rtp *ast_rtp_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode, struct in_addr addr)
if (!(rtp = ast_calloc(1, sizeof(*rtp))))
return NULL;
rtp->them.sin_family = AF_INET;
rtp->us.sin_family = AF_INET;
Tilghman Lesher
committed
rtp->ssrc = ast_random();
rtp->seqno = ast_random() & 0xffff;
ast_set_flag(rtp, FLAG_HAS_DTMF);
ast_log(LOG_ERROR, "Unable to allocate socket: %s\n", strerror(errno));
if (sched && rtcpenable) {
rtp->sched = sched;
rtp->rtcp = ast_rtcp_new();
}
/* Select a random port number in the range of possible RTP */
Tilghman Lesher
committed
x = (ast_random() % (rtpend-rtpstart)) + rtpstart;
/* Save it for future references. */
/* Iterate tring to bind that port and incrementing it otherwise untill a port was found or no ports are available. */
for (;;) {
/* Must be an even port number by RTP spec */
rtp->us.sin_port = htons(x);
rtp->us.sin_addr = addr;
/* If there's rtcp, initialize it as well. */
if (rtp->rtcp)
rtp->rtcp->us.sin_port = htons(x + 1);
/* Try to bind it/them. */
if (!(first = bind(rtp->s, (struct sockaddr *)&rtp->us, sizeof(rtp->us))) &&
(!rtp->rtcp || !bind(rtp->rtcp->s, (struct sockaddr *)&rtp->rtcp->us, sizeof(rtp->rtcp->us))))
if (!first) {
/* Primary bind succeeded! Gotta recreate it */
close(rtp->s);
rtp->s = rtp_socket();
}
/* We got an error that wasn't expected, abort! */
ast_log(LOG_ERROR, "Unexpected bind error: %s\n", strerror(errno));
if (rtp->rtcp) {
close(rtp->rtcp->s);
free(rtp->rtcp);
}
/* The port was used, increment it (by two). */
/* Did we go over the limit ? */
/* then, start from the begingig. */
/* Check if we reached the place were we started. */
/* If so, there's no ports available. */
ast_log(LOG_ERROR, "No RTP ports remaining. Can't setup media stream for this call.\n");
if (rtp->rtcp) {
close(rtp->rtcp->s);
free(rtp->rtcp);
}
if (io && sched && callbackmode) {
/* Operate this one in a callback mode */
rtp->sched = sched;
rtp->io = io;
rtp->ioid = ast_io_add(rtp->io, rtp->s, rtpread, AST_IO_IN, rtp);
}
struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode)
{
struct in_addr ia;
memset(&ia, 0, sizeof(ia));
return ast_rtp_new_with_bindaddr(sched, io, rtcpenable, callbackmode, ia);
}
int ast_rtp_settos(struct ast_rtp *rtp, int tos)
{
int res;
if ((res = setsockopt(rtp->s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))))
ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
return res;
}
void ast_rtp_set_peer(struct ast_rtp *rtp, struct sockaddr_in *them)
{
rtp->them.sin_port = them->sin_port;
rtp->them.sin_addr = them->sin_addr;
if (rtp->rtcp) {
rtp->rtcp->them.sin_port = htons(ntohs(them->sin_port) + 1);
rtp->rtcp->them.sin_addr = them->sin_addr;
}
Mark Spencer
committed
rtp->rxseqno = 0;
int ast_rtp_get_peer(struct ast_rtp *rtp, struct sockaddr_in *them)
if ((them->sin_family != AF_INET) ||
(them->sin_port != rtp->them.sin_port) ||
(them->sin_addr.s_addr != rtp->them.sin_addr.s_addr)) {
them->sin_family = AF_INET;
them->sin_port = rtp->them.sin_port;
them->sin_addr = rtp->them.sin_addr;
return 1;
}
return 0;
void ast_rtp_get_us(struct ast_rtp *rtp, struct sockaddr_in *us)
{
void ast_rtp_stop(struct ast_rtp *rtp)
{
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->rtcp->them.sin_addr));
memset(&rtp->rtcp->them.sin_port, 0, sizeof(rtp->rtcp->them.sin_port));
void ast_rtp_reset(struct ast_rtp *rtp)
{
memset(&rtp->rxcore, 0, sizeof(rtp->rxcore));
memset(&rtp->txcore, 0, sizeof(rtp->txcore));
memset(&rtp->dtmfmute, 0, sizeof(rtp->dtmfmute));
rtp->lastts = 0;
rtp->lastdigitts = 0;
rtp->lastrxts = 0;
rtp->lastividtimestamp = 0;
rtp->lastovidtimestamp = 0;
rtp->lasteventseqn = 0;
rtp->lasteventendseqn = 0;
rtp->lasttxformat = 0;
rtp->lastrxformat = 0;
rtp->dtmfcount = 0;
rtp->dtmfduration = 0;
rtp->seqno = 0;
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);
}
ast_sched_del(rtp->sched, rtp->rtcp->schedid);
rtp->rtcp->schedid = -1;
}
if (rtp->smoother)
ast_smoother_free(rtp->smoother);
if (rtp->ioid)
ast_io_remove(rtp->io, rtp->ioid);
if (rtp->s > -1)
close(rtp->s);
if (rtp->rtcp) {
close(rtp->rtcp->s);
free(rtp->rtcp);
rtp->rtcp=NULL;
static unsigned int calc_txstamp(struct ast_rtp *rtp, struct timeval *delivery)
Kevin P. Fleming
committed
struct timeval t;
long ms;
if (ast_tvzero(rtp->txcore)) {
rtp->txcore = ast_tvnow();
/* Round to 20ms for nice, pretty timestamps */
rtp->txcore.tv_usec -= rtp->txcore.tv_usec % 20000;
Kevin P. Fleming
committed
/* Use previous txcore if available */
t = (delivery && !ast_tvzero(*delivery)) ? *delivery : ast_tvnow();
ms = ast_tvdiff_ms(t, rtp->txcore);
Kevin P. Fleming
committed
/* Use what we just got for next time */
rtp->txcore = t;
return (unsigned int) ms;
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;
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->lastdigitts);
rtpheader[2] = htonl(rtp->ssrc);
rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
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));
if (res < 0)
ast_log(LOG_ERROR, "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 DTMF packet to %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr),
ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
/* Sequence number of last two end packets does not get incremented */
if (x < 3)
rtp->seqno++;
/* Clear marker bit and set seqno */
rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno));
/* For the last three packets, set the duration and the end bit */
if (x == 2) {
#if 0
/* No, this is wrong... Do not increment lastdigitts, that's not according
to the RFC, as best we can determine */
rtp->lastdigitts++; /* or else the SPA3000 will click instead of beeping... */
rtpheader[1] = htonl(rtp->lastdigitts);
#endif
/* Make duration 800 (100ms) */
rtpheader[3] |= htonl((800));
/* Set the End bit */
rtpheader[3] |= htonl((1 << 23));
/*! \note Increment the digit timestamp by 120ms, to ensure that digits
sent sequentially with no intervening non-digit packets do not
Kevin P. Fleming
committed
get sent with the same timestamp, and that sequential digits
have some 'dead air' in between them
*/
rtp->lastdigitts += 960;
/* Increment the sequence number to reflect the last packet
that was sent
*/
rtp->seqno++;
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
/* \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 */
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
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;