Wed Mar 12 07:00:01 CET 2003

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@641 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.0
Matteo Brancaleoni 23 years ago
parent 67fad0eab1
commit 66a57e51e3

@ -1,3 +1,4 @@
-- Add experimental "debug channel" command
-- Add 'C' flag to dial command to reset call detail record (handy for calling cards) -- Add 'C' flag to dial command to reset call detail record (handy for calling cards)
-- Add NAT and dynamic support to MGCP -- Add NAT and dynamic support to MGCP
-- Allow selection of in-band, out-of-band, or INFO based DTMF -- Allow selection of in-band, out-of-band, or INFO based DTMF

@ -34,6 +34,8 @@ Steven Critchfield - Seek and Trunc functions for playback and recording
critch@basesys.com critch@basesys.com
Jefferson Noxon - app_lookupcidname, app_db, and various other contributions Jefferson Noxon - app_lookupcidname, app_db, and various other contributions
Klaus-Peter Junghanns - in-band DTMF on SIP and MGCP Klaus-Peter Junghanns - in-band DTMF on SIP and MGCP
Ross Finlayson - Dynamic RTP payload support
=== OTHER SOURCE CODE IN ASTERISK === === OTHER SOURCE CODE IN ASTERISK ===
I did not implement the codecs in asterisk. Here is the copyright on the I did not implement the codecs in asterisk. Here is the copyright on the

@ -557,6 +557,10 @@ static int dial_exec(struct ast_channel *chan, void *data)
/* If appropriate, log that we have a destination channel */ /* If appropriate, log that we have a destination channel */
if (chan->cdr) if (chan->cdr)
ast_cdr_setdestchan(chan->cdr, peer->name); ast_cdr_setdestchan(chan->cdr, peer->name);
if (peer->name)
pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", peer->name);
if (numsubst)
pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", numsubst);
/* Make sure channels are compatible */ /* Make sure channels are compatible */
res = ast_channel_make_compatible(chan, peer); res = ast_channel_make_compatible(chan, peer);
if (res < 0) { if (res < 0) {

@ -184,17 +184,20 @@ out:
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority); pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
if (save_macro_priority) free(save_macro_priority); if (save_macro_priority) free(save_macro_priority);
if (!strcasecmp(chan->context, fullmacro) && !chan->_softhangup) { if (!strcasecmp(chan->context, fullmacro)) {
/* If we're leaving the macro normally, restore original information */ /* If we're leaving the macro normally, restore original information */
chan->priority = oldpriority; chan->priority = oldpriority;
strncpy(chan->exten, oldexten, sizeof(chan->exten) - 1);
strncpy(chan->context, oldcontext, sizeof(chan->context) - 1); strncpy(chan->context, oldcontext, sizeof(chan->context) - 1);
if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) { if (!chan->_softhangup) {
/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue /* Copy the extension, so long as we're not in softhangup, where we could be given an asyncgoto */
normally if there is any problem */ strncpy(chan->exten, oldexten, sizeof(chan->exten) - 1);
if (sscanf(offsets, "%d", &offset) == 1) { if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + offset + 1, chan->callerid)) { /* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
chan->priority += offset; normally if there is any problem */
if (sscanf(offsets, "%d", &offset) == 1) {
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + offset + 1, chan->callerid)) {
chan->priority += offset;
}
} }
} }
} }

@ -1043,7 +1043,12 @@ struct ast_frame *ast_read(struct ast_channel *chan)
ast_deactivate_generator(chan); ast_deactivate_generator(chan);
} }
} }
chan->fin++; if (chan->fin & 0x80000000)
ast_frame_dump(chan->name, f, "<<");
if ((chan->fin & 0x7fffffff) == 0x7fffffff)
chan->fin &= 0x80000000;
else
chan->fin++;
return f; return f;
} }
@ -1197,6 +1202,8 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
else else
return 0; return 0;
} }
if (chan->fout & 0x80000000)
ast_frame_dump(chan->name, fr, ">>");
CHECK_BLOCKING(chan); CHECK_BLOCKING(chan);
switch(fr->frametype) { switch(fr->frametype) {
case AST_FRAME_CONTROL: case AST_FRAME_CONTROL:
@ -1228,8 +1235,13 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
/* Consider a write failure to force a soft hangup */ /* Consider a write failure to force a soft hangup */
if (res < 0) if (res < 0)
chan->_softhangup |= AST_SOFTHANGUP_DEV; chan->_softhangup |= AST_SOFTHANGUP_DEV;
else else {
if ((chan->fout & 0x7fffffff) == 0x7fffffff)
chan->fout &= 0x80000000;
else
chan->fout++;
chan->fout++; chan->fout++;
}
return res; return res;
} }

@ -3409,6 +3409,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
char rel0[256]; char rel0[256];
char rel1[255]; char rel1[255];
char empty[32]=""; /* Safety measure */ char empty[32]=""; /* Safety measure */
fr.ts=0; /* make Valgrind happy */
res = recvfrom(netsocket, buf, sizeof(buf), 0,(struct sockaddr *) &sin, &len); res = recvfrom(netsocket, buf, sizeof(buf), 0,(struct sockaddr *) &sin, &len);
if (res < 0) { if (res < 0) {
if (errno != ECONNREFUSED) if (errno != ECONNREFUSED)
@ -4417,8 +4418,8 @@ static struct iax_peer *build_peer(char *name, struct ast_variable *v)
ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno); ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
peer->maxms = 0; peer->maxms = 0;
} }
} } //else if (strcasecmp(v->name,"type"))
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v=v->next; v=v->next;
} }
if (!strlen(peer->methods)) if (!strlen(peer->methods))
@ -4468,7 +4469,8 @@ static struct iax_user *build_user(char *name, struct ast_variable *v)
} }
} else if (!strcasecmp(v->name, "inkeys")) { } else if (!strcasecmp(v->name, "inkeys")) {
strncpy(user->inkeys, v->value, sizeof(user->inkeys)); strncpy(user->inkeys, v->value, sizeof(user->inkeys));
} } //else if (strcasecmp(v->name,"type"))
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v = v->next; v = v->next;
} }
} }
@ -4647,7 +4649,8 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
} else { } else {
amaflags = format; amaflags = format;
} }
} } //else if (strcasecmp(v->name,"type"))
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v = v->next; v = v->next;
} }
iax_capability = capability; iax_capability = capability;

@ -65,7 +65,7 @@
#define GAMMA (0.01) #define GAMMA (0.01)
static char *desc = "Inter Asterisk eXchange (Ver 2)"; static char *desc = "Inter Asterisk eXchange (Ver 2)";
static char *tdesc = "Inter Asterisk eXchange Drver (Ver 2)"; static char *tdesc = "Inter Asterisk eXchange Driver (Ver 2)";
static char *type = "IAX2"; static char *type = "IAX2";
static char context[80] = "default"; static char context[80] = "default";
@ -345,8 +345,6 @@ struct chan_iax2_pvt {
#define DIRECTION_OUTGRESS 2 #define DIRECTION_OUTGRESS 2
struct ast_iax2_frame { struct ast_iax2_frame {
/* Actual, isolated frame */
struct ast_frame *f;
/* /Our/ call number */ /* /Our/ call number */
unsigned short callno; unsigned short callno;
/* /Their/ call number */ /* /Their/ call number */
@ -377,11 +375,13 @@ struct ast_iax2_frame {
int direction; int direction;
/* Retransmission ID */ /* Retransmission ID */
int retrans; int retrans;
/* Easy linking */ /* Easy linking */
struct ast_iax2_frame *next; struct ast_iax2_frame *next;
struct ast_iax2_frame *prev; struct ast_iax2_frame *prev;
/* Actual, isolated frame header */
struct ast_frame af;
unsigned char unused[AST_FRIENDLY_OFFSET];
unsigned char afdata[0]; /* Data for frame */
}; };
struct iax_ies { struct iax_ies {
@ -612,7 +612,7 @@ void showframe(struct ast_iax2_frame *f, struct ast_iax2_full_hdr *fhi, int rx,
fprintf(stderr, fprintf(stderr,
" Timestamp: %05dms SCall: %5.5d DCall: %5.5d [%s:%d]\n", " Timestamp: %05dms SCall: %5.5d DCall: %5.5d [%s:%d]\n",
ntohl(fh->ts), ntohl(fh->ts),
ntohs(fh->scallno) & ~AST_FLAG_FULL, ntohs(fh->dcallno), ntohs(fh->scallno) & ~AST_FLAG_FULL, ntohs(fh->dcallno) & ~AST_FLAG_RETRANS,
inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
} }
#endif #endif
@ -746,10 +746,24 @@ static int frames = 0;
static int iframes = 0; static int iframes = 0;
static int oframes = 0; static int oframes = 0;
static struct ast_iax2_frame *ast_iax2_frame_new(int direction) static void ast_iax2_frame_wrap(struct ast_iax2_frame *fr, struct ast_frame *f)
{
fr->af.frametype = f->frametype;
fr->af.subclass = f->subclass;
fr->af.mallocd = 0; /* Our frame is static relative to the container */
fr->af.datalen = f->datalen;
fr->af.samples = f->samples;
fr->af.offset = AST_FRIENDLY_OFFSET;
fr->af.src = f->src;
fr->af.data = fr->afdata;
if (fr->af.datalen)
memcpy(fr->af.data, f->data, fr->af.datalen);
}
static struct ast_iax2_frame *ast_iax2_frame_new(int direction, int datalen)
{ {
struct ast_iax2_frame *fr; struct ast_iax2_frame *fr;
fr = malloc(sizeof(struct ast_iax2_frame)); fr = malloc(sizeof(struct ast_iax2_frame) + datalen);
if (fr) { if (fr) {
fr->direction = direction; fr->direction = direction;
fr->retrans = -1; fr->retrans = -1;
@ -780,24 +794,15 @@ static void ast_iax2_frame_free(struct ast_iax2_frame *fr)
frames--; frames--;
} }
static struct ast_iax2_frame *iaxfrdup2(struct ast_iax2_frame *fr, int ch) static struct ast_iax2_frame *iaxfrdup2(struct ast_iax2_frame *fr)
{ {
/* Malloc() a copy of a frame */ /* Malloc() a copy of a frame */
struct ast_iax2_frame *new = ast_iax2_frame_new(DIRECTION_INGRESS); struct ast_iax2_frame *new = ast_iax2_frame_new(DIRECTION_INGRESS, fr->af.datalen);
if (new) { if (new) {
memcpy(new, fr, sizeof(struct ast_iax2_frame)); memcpy(new, fr, sizeof(struct ast_iax2_frame));
new->f = ast_frdup(fr->f); ast_iax2_frame_wrap(new, &fr->af);
/* Copy full header */ new->data = NULL;
if (ch) { new->datalen = 0;
memcpy(new->f->data - sizeof(struct ast_iax2_full_hdr),
fr->f->data - sizeof(struct ast_iax2_full_hdr),
sizeof(struct ast_iax2_full_hdr));
/* Grab new data pointer */
new->data = new->f->data - (fr->f->data - fr->data);
} else {
new->data = NULL;
new->datalen = 0;
}
new->direction = DIRECTION_INGRESS; new->direction = DIRECTION_INGRESS;
new->retrans = -1; new->retrans = -1;
} }
@ -835,7 +840,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
int start; int start;
if (new <= NEW_ALLOW) { if (new <= NEW_ALLOW) {
/* Look for an existing connection first */ /* Look for an existing connection first */
for (x=0;(res < 0) && (x<AST_IAX2_MAX_CALLS);x++) { for (x=0;(res < 1) && (x<AST_IAX2_MAX_CALLS);x++) {
ast_pthread_mutex_lock(&iaxsl[x]); ast_pthread_mutex_lock(&iaxsl[x]);
if (iaxs[x]) { if (iaxs[x]) {
/* Look for an exact match */ /* Look for an exact match */
@ -918,25 +923,23 @@ static int __do_deliver(void *data)
unsigned int ts; unsigned int ts;
fr->retrans = -1; fr->retrans = -1;
if (iaxs[fr->callno] && !iaxs[fr->callno]->alreadygone) { if (iaxs[fr->callno] && !iaxs[fr->callno]->alreadygone) {
if (fr->f->frametype == AST_FRAME_IAX) { if (fr->af.frametype == AST_FRAME_IAX) {
/* We have to treat some of these packets specially because /* We have to treat some of these packets specially because
they're LAG measurement packets */ they're LAG measurement packets */
if (fr->f->subclass == AST_IAX2_COMMAND_LAGRQ) { if (fr->af.subclass == AST_IAX2_COMMAND_LAGRQ) {
/* If we got a queued request, build a reply and send it */ /* If we got a queued request, build a reply and send it */
fr->f->subclass = AST_IAX2_COMMAND_LAGRP; fr->af.subclass = AST_IAX2_COMMAND_LAGRP;
iax2_send(iaxs[fr->callno], fr->f, fr->ts, -1, 0, 0, 0); iax2_send(iaxs[fr->callno], &fr->af, fr->ts, -1, 0, 0, 0);
} else if (fr->f->subclass == AST_IAX2_COMMAND_LAGRP) { } else if (fr->af.subclass == AST_IAX2_COMMAND_LAGRP) {
/* This is a reply we've been given, actually measure the difference */ /* This is a reply we've been given, actually measure the difference */
ts = calc_timestamp(iaxs[fr->callno], 0); ts = calc_timestamp(iaxs[fr->callno], 0);
iaxs[fr->callno]->lag = ts - fr->ts; iaxs[fr->callno]->lag = ts - fr->ts;
} }
} else { } else {
iax2_queue_frame(fr->callno, fr->f); iax2_queue_frame(fr->callno, &fr->af);
} }
} }
/* Free the packet */ /* Free our iax frame */
ast_frfree(fr->f);
/* And our iax frame */
ast_iax2_frame_free(fr); ast_iax2_frame_free(fr);
/* And don't run again */ /* And don't run again */
return 0; return 0;
@ -1187,7 +1190,7 @@ static int attempt_transmit(void *data)
iax2_destroy_nolock(f->callno); iax2_destroy_nolock(f->callno);
} else { } else {
if (iaxs[f->callno]->owner) if (iaxs[f->callno]->owner)
ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %d, ts=%d, seqno=%d)\n", inet_ntoa(iaxs[f->callno]->addr.sin_addr),iaxs[f->callno]->owner->name , f->f->frametype, f->f->subclass, f->ts, f->oseqno); ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %d, ts=%d, seqno=%d)\n", inet_ntoa(iaxs[f->callno]->addr.sin_addr),iaxs[f->callno]->owner->name , f->af.frametype, f->af.subclass, f->ts, f->oseqno);
iaxs[f->callno]->error = ETIMEDOUT; iaxs[f->callno]->error = ETIMEDOUT;
if (iaxs[f->callno]->owner) { if (iaxs[f->callno]->owner) {
struct ast_frame fr = { 0, }; struct ast_frame fr = { 0, };
@ -1243,9 +1246,8 @@ static int attempt_transmit(void *data)
iaxq.tail = f->prev; iaxq.tail = f->prev;
iaxq.count--; iaxq.count--;
ast_pthread_mutex_unlock(&iaxq.lock); ast_pthread_mutex_unlock(&iaxq.lock);
/* Free the frame */
ast_frfree(f->f);
f->retrans = -1; f->retrans = -1;
/* Free the IAX2 frame */
ast_iax2_frame_free(f); ast_iax2_frame_free(f);
} }
return 0; return 0;
@ -1392,7 +1394,7 @@ static int forward_delivery(struct ast_iax2_frame *fr)
fr->ts = calc_fakestamp(p1, p2, fr->ts); fr->ts = calc_fakestamp(p1, p2, fr->ts);
/* Now just send it send on the 2nd one /* Now just send it send on the 2nd one
with adjusted timestamp */ with adjusted timestamp */
return iax2_send(p2, fr->f, fr->ts, -1, 0, 0, 0); return iax2_send(p2, &fr->af, fr->ts, -1, 0, 0, 0);
} }
#endif #endif
@ -1509,14 +1511,12 @@ static int schedule_delivery(struct ast_iax2_frame *fr, int reallydeliver)
if (option_debug) if (option_debug)
ast_log(LOG_DEBUG, "Calculated ms is %d\n", ms); ast_log(LOG_DEBUG, "Calculated ms is %d\n", ms);
/* Don't deliver it more than 4 ms late */ /* Don't deliver it more than 4 ms late */
if ((ms > -4) || (fr->f->frametype != AST_FRAME_VOICE)) { if ((ms > -4) || (fr->af.frametype != AST_FRAME_VOICE)) {
__do_deliver(fr); __do_deliver(fr);
} else { } else {
if (option_debug) if (option_debug)
ast_log(LOG_DEBUG, "Dropping voice packet since %d ms is, too old\n", ms); ast_log(LOG_DEBUG, "Dropping voice packet since %d ms is, too old\n", ms);
/* Free the packet */ /* Free our iax frame */
ast_frfree(fr->f);
/* And our iax frame */
ast_iax2_frame_free(fr); ast_iax2_frame_free(fr);
} }
} else { } else {
@ -2180,7 +2180,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
if (now) if (now)
fr = &fr2; fr = &fr2;
else else
fr = ast_iax2_frame_new(DIRECTION_OUTGRESS); fr = ast_iax2_frame_new(DIRECTION_OUTGRESS, f->datalen);
if (!fr) { if (!fr) {
ast_log(LOG_WARNING, "Out of memory\n"); ast_log(LOG_WARNING, "Out of memory\n");
return -1; return -1;
@ -2191,20 +2191,9 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
ast_iax2_frame_free(fr); ast_iax2_frame_free(fr);
return -1; return -1;
} }
/* Isolate our frame for transmission */ /* Copy our prospective frame into our immediate or retransmitted wrapper */
fr->f = ast_frdup(f); ast_iax2_frame_wrap(fr, f);
if (!fr->f) {
ast_log(LOG_WARNING, "Out of memory\n");
if (!now)
ast_iax2_frame_free(fr);
return -1;
}
if (fr->f->offset < sizeof(struct ast_iax2_full_hdr)) {
ast_log(LOG_WARNING, "Packet from '%s' not friendly\n", fr->f->src);
free(fr);
return -1;
}
lastsent = pvt->lastsent; lastsent = pvt->lastsent;
fr->ts = calc_timestamp(pvt, ts); fr->ts = calc_timestamp(pvt, ts);
if (!fr->ts) { if (!fr->ts) {
@ -2218,9 +2207,9 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
fr->final = final; fr->final = final;
if (((fr->ts & 0xFFFF0000L) != (lastsent & 0xFFFF0000L)) if (((fr->ts & 0xFFFF0000L) != (lastsent & 0xFFFF0000L))
/* High two bits of timestamp differ */ || /* High two bits of timestamp differ */ ||
(fr->f->frametype != AST_FRAME_VOICE) (fr->af.frametype != AST_FRAME_VOICE)
/* or not a voice frame */ || /* or not a voice frame */ ||
(fr->f->subclass != pvt->svoiceformat) (fr->af.subclass != pvt->svoiceformat)
/* or new voice format */ ) { /* or new voice format */ ) {
/* We need a full frame */ /* We need a full frame */
if (seqno > -1) if (seqno > -1)
@ -2228,21 +2217,21 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
else else
fr->oseqno = pvt->oseqno++; fr->oseqno = pvt->oseqno++;
fr->iseqno = pvt->iseqno; fr->iseqno = pvt->iseqno;
fh = (struct ast_iax2_full_hdr *)(fr->f->data - sizeof(struct ast_iax2_full_hdr)); fh = (struct ast_iax2_full_hdr *)(fr->af.data - sizeof(struct ast_iax2_full_hdr));
fh->scallno = htons(fr->callno | AST_FLAG_FULL); fh->scallno = htons(fr->callno | AST_FLAG_FULL);
fh->ts = htonl(fr->ts); fh->ts = htonl(fr->ts);
fh->oseqno = htons(fr->oseqno); fh->oseqno = htons(fr->oseqno);
fh->iseqno = htons(fr->iseqno); fh->iseqno = htons(fr->iseqno);
/* Keep track of the last thing we've acknowledged */ /* Keep track of the last thing we've acknowledged */
pvt->aseqno = fr->iseqno; pvt->aseqno = fr->iseqno;
fh->type = fr->f->frametype & 0xFF; fh->type = fr->af.frametype & 0xFF;
fh->csub = compress_subclass(fr->f->subclass); fh->csub = compress_subclass(fr->af.subclass);
if (transfer) { if (transfer) {
fr->dcallno = pvt->transfercallno; fr->dcallno = pvt->transfercallno;
} else } else
fr->dcallno = pvt->peercallno; fr->dcallno = pvt->peercallno;
fh->dcallno = htons(fr->dcallno); fh->dcallno = htons(fr->dcallno);
fr->datalen = fr->f->datalen + sizeof(struct ast_iax2_full_hdr); fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_full_hdr);
fr->data = fh; fr->data = fh;
fr->retries = 0; fr->retries = 0;
/* Retry after 2x the ping time has passed */ /* Retry after 2x the ping time has passed */
@ -2259,7 +2248,6 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
} }
if (now) { if (now) {
res = send_packet(fr); res = send_packet(fr);
ast_frfree(fr->f);
} else } else
res = iax2_transmit(fr); res = iax2_transmit(fr);
} else { } else {
@ -2267,15 +2255,14 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
fr->oseqno = -1; fr->oseqno = -1;
fr->iseqno = -1; fr->iseqno = -1;
/* Mini frame will do */ /* Mini frame will do */
mh = (struct ast_iax2_mini_hdr *)(fr->f->data - sizeof(struct ast_iax2_mini_hdr)); mh = (struct ast_iax2_mini_hdr *)(fr->af.data - sizeof(struct ast_iax2_mini_hdr));
mh->callno = htons(fr->callno); mh->callno = htons(fr->callno);
mh->ts = htons(fr->ts & 0xFFFF); mh->ts = htons(fr->ts & 0xFFFF);
fr->datalen = fr->f->datalen + sizeof(struct ast_iax2_mini_hdr); fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr);
fr->data = mh; fr->data = mh;
fr->retries = -1; fr->retries = -1;
if (now) { if (now) {
res = send_packet(fr); res = send_packet(fr);
ast_frfree(fr->f);
} else } else
res = iax2_transmit(fr); res = iax2_transmit(fr);
} }
@ -2662,13 +2649,14 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
return res; return res;
} }
static int raw_hangup(struct sockaddr_in *sin, short src, short dst) static int raw_hangup(struct sockaddr_in *sin, unsigned short src, unsigned short dst)
{ {
struct ast_iax2_full_hdr fh; struct ast_iax2_full_hdr fh;
fh.scallno = htons(src | AST_FLAG_FULL); fh.scallno = htons(src | AST_FLAG_FULL);
fh.dcallno = htons(dst); fh.dcallno = htons(dst);
fh.ts = 0; fh.ts = 0;
fh.oseqno = 0; fh.oseqno = 0;
fh.iseqno = 0;
fh.type = AST_FRAME_IAX; fh.type = AST_FRAME_IAX;
fh.csub = compress_subclass(AST_IAX2_COMMAND_INVAL); fh.csub = compress_subclass(AST_IAX2_COMMAND_INVAL);
#if 0 #if 0
@ -3505,7 +3493,6 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
int res; int res;
int new = NEW_PREVENT; int new = NEW_PREVENT;
char buf[4096]; char buf[4096];
char src[80];
int len = sizeof(sin); int len = sizeof(sin);
int dcallno = 0; int dcallno = 0;
struct ast_iax2_full_hdr *fh = (struct ast_iax2_full_hdr *)buf; struct ast_iax2_full_hdr *fh = (struct ast_iax2_full_hdr *)buf;
@ -3538,7 +3525,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
#endif #endif
if (ntohs(mh->callno) & AST_FLAG_FULL) { if (ntohs(mh->callno) & AST_FLAG_FULL) {
/* Get the destination call number */ /* Get the destination call number */
dcallno = ntohs(fh->dcallno); dcallno = ntohs(fh->dcallno) & ~AST_FLAG_RETRANS;
/* Retrieve the type and subclass */ /* Retrieve the type and subclass */
f.frametype = fh->type; f.frametype = fh->type;
f.subclass = uncompress_subclass(fh->csub); f.subclass = uncompress_subclass(fh->csub);
@ -3569,7 +3556,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
(f.subclass != AST_IAX2_COMMAND_TXCNT) && (f.subclass != AST_IAX2_COMMAND_TXCNT) &&
(f.subclass != AST_IAX2_COMMAND_TXACC))|| (f.subclass != AST_IAX2_COMMAND_TXACC))||
(f.frametype != AST_FRAME_IAX)) (f.frametype != AST_FRAME_IAX))
raw_hangup(&sin, ntohs(fh->dcallno), ntohs(mh->callno) & ~AST_FLAG_FULL raw_hangup(&sin, ntohs(fh->dcallno) & ~AST_FLAG_RETRANS, ntohs(mh->callno) & ~AST_FLAG_FULL
); );
} }
if (fr.callno > 0) if (fr.callno > 0)
@ -3951,7 +3938,9 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
peer->lastms = iaxs[fr.callno]->pingtime; peer->lastms = iaxs[fr.callno]->pingtime;
if (peer->pokeexpire > -1) if (peer->pokeexpire > -1)
ast_sched_del(sched, peer->pokeexpire); ast_sched_del(sched, peer->pokeexpire);
send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX2_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
iax2_destroy_nolock(fr.callno); iax2_destroy_nolock(fr.callno);
peer->callno = 0;
/* Try again eventually */ /* Try again eventually */
if ((peer->lastms < 0) || (peer->lastms > peer->maxms)) if ((peer->lastms < 0) || (peer->lastms > peer->maxms))
peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, iax2_poke_peer_s, peer); peer->pokeexpire = ast_sched_add(sched, DEFAULT_FREQ_NOTOK, iax2_poke_peer_s, peer);
@ -3969,13 +3958,12 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
/* A little strange -- We have to actually go through the motions of /* A little strange -- We have to actually go through the motions of
delivering the packet. In the very last step, it will be properly delivering the packet. In the very last step, it will be properly
handled by do_deliver */ handled by do_deliver */
snprintf(src, sizeof(src), "LAGRQ-IAX/%s/%d", inet_ntoa(sin.sin_addr),fr.callno); f.src = "LAGRQ";
f.src = src;
f.mallocd = 0; f.mallocd = 0;
f.offset = 0; f.offset = 0;
fr.f = &f;
f.samples = 0; f.samples = 0;
schedule_delivery(iaxfrdup2(&fr, 0), 1); ast_iax2_frame_wrap(&fr, &f);
schedule_delivery(iaxfrdup2(&fr), 1);
#ifdef BRIDGE_OPTIMIZATION #ifdef BRIDGE_OPTIMIZATION
} }
#endif #endif
@ -4229,14 +4217,14 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
return 1; return 1;
} }
/* Common things */ /* Common things */
snprintf(src, sizeof(src), "IAX2/%s/%d", inet_ntoa(sin.sin_addr),fr.callno); f.src = src; f.src = "IAX2";
f.mallocd = 0; f.mallocd = 0;
f.offset = 0; f.offset = 0;
fr.f = &f;
if (f.datalen && (f.frametype == AST_FRAME_VOICE)) if (f.datalen && (f.frametype == AST_FRAME_VOICE))
f.samples = get_samples(&f); f.samples = get_samples(&f);
else else
f.samples = 0; f.samples = 0;
ast_iax2_frame_wrap(&fr, &f);
/* If this is our most recent packet, use it as our basis for timestamping */ /* If this is our most recent packet, use it as our basis for timestamping */
if (iaxs[fr.callno]->last < fr.ts) { if (iaxs[fr.callno]->last < fr.ts) {
@ -4251,10 +4239,10 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
if (iaxs[fr.callno]->bridgecallno) { if (iaxs[fr.callno]->bridgecallno) {
forward_delivery(&fr); forward_delivery(&fr);
} else { } else {
schedule_delivery(iaxfrdup2(&fr, 0), 1); schedule_delivery(iaxfrdup2(&fr), 1);
} }
#else #else
schedule_delivery(iaxfrdup2(&fr, 0), 1); schedule_delivery(iaxfrdup2(&fr), 1);
#endif #endif
/* Always run again */ /* Always run again */
ast_pthread_mutex_unlock(&iaxsl[fr.callno]); ast_pthread_mutex_unlock(&iaxsl[fr.callno]);
@ -4435,9 +4423,6 @@ static void *network_thread(void *ignore)
else else
iaxq.tail = f->prev; iaxq.tail = f->prev;
iaxq.count--; iaxq.count--;
/* Free the frame */
ast_frfree(f->f);
f->f = NULL;
/* Free the iax frame */ /* Free the iax frame */
freeme = f; freeme = f;
} else { } else {
@ -4612,8 +4597,8 @@ static struct iax2_peer *build_peer(char *name, struct ast_variable *v)
ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno); ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
peer->maxms = 0; peer->maxms = 0;
} }
} }// else if (strcasecmp(v->name,"type"))
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v=v->next; v=v->next;
} }
if (!peer->authmethods) if (!peer->authmethods)
@ -4663,7 +4648,8 @@ static struct iax2_user *build_user(char *name, struct ast_variable *v)
} }
} else if (!strcasecmp(v->name, "inkeys")) { } else if (!strcasecmp(v->name, "inkeys")) {
strncpy(user->inkeys, v->value, sizeof(user->inkeys)); strncpy(user->inkeys, v->value, sizeof(user->inkeys));
} }// else if (strcasecmp(v->name,"type"))
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v = v->next; v = v->next;
} }
} }
@ -4846,7 +4832,8 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
} else { } else {
amaflags = format; amaflags = format;
} }
} } //else if (strcasecmp(v->name,"type"))
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v = v->next; v = v->next;
} }
iax2_capability = capability; iax2_capability = capability;

@ -40,6 +40,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/signal.h> #include <sys/signal.h>
#include <asterisk/dsp.h> #include <asterisk/dsp.h>
#include <ctype.h>
#define MGCPDUMPER #define MGCPDUMPER
#define DEFAULT_EXPIREY 120 #define DEFAULT_EXPIREY 120
@ -71,6 +72,7 @@ static int restart_monitor(void);
/* Just about everybody seems to support ulaw, so make it a nice default */ /* Just about everybody seems to support ulaw, so make it a nice default */
static int capability = AST_FORMAT_ULAW; static int capability = AST_FORMAT_ULAW;
static int nonCodecCapability = AST_RTP_DTMF;
static char ourhost[256]; static char ourhost[256];
static struct in_addr __ourip; static struct in_addr __ourip;
@ -133,6 +135,7 @@ struct mgcp_endpoint {
int alreadygone; int alreadygone;
int needdestroy; int needdestroy;
int capability; int capability;
int nonCodecCapability;
int outgoing; int outgoing;
struct ast_dsp *vad; struct ast_dsp *vad;
struct ast_channel *owner; struct ast_channel *owner;
@ -568,21 +571,41 @@ static struct ast_channel *mgcp_new(struct mgcp_endpoint *i, int state)
return tmp; return tmp;
} }
static char *get_sdp(struct mgcp_request *req, char *name) static char* get_sdp_by_line(char* line, char *name, int nameLen) {
{ if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
int x; char* r = line + nameLen + 1;
int len = strlen(name); while (*r && (*r < 33)) ++r;
char *r; return r;
for (x=0;x<req->lines;x++) { }
if (!strncasecmp(req->line[x], name, len) &&
(req->line[x][len] == '=')) { return "";
r = req->line[x] + len + 1; }
while(*r && (*r < 33))
r++; static char *get_sdp(struct mgcp_request *req, char *name) {
return r; int x;
} int len = strlen(name);
} char *r;
return "";
for (x=0; x<req->lines; x++) {
r = get_sdp_by_line(req->line[x], name, len);
if (r[0] != '\0') return r;
}
return "";
}
static void sdpLineNum_iterator_init(int* iterator) {
*iterator = 0;
}
static char* get_sdp_iterate(int* iterator,
struct mgcp_request *req, char *name) {
int len = strlen(name);
char *r;
while (*iterator < req->lines) {
r = get_sdp_by_line(req->line[(*iterator)++], name, len);
if (r[0] != '\0') return r;
}
return "";
} }
static char *__get_header(struct mgcp_request *req, char *name, int *start) static char *__get_header(struct mgcp_request *req, char *name, int *start)
@ -803,14 +826,17 @@ static int process_sdp(struct mgcp_endpoint *p, struct mgcp_request *req)
{ {
char *m; char *m;
char *c; char *c;
char *a;
char host[258]; char host[258];
int len; int len;
int portno; int portno;
int peercapability; int peercapability, peerNonCodecCapability;
struct sockaddr_in sin; struct sockaddr_in sin;
char *codecs; char *codecs;
struct hostent *hp; struct hostent *hp;
int codec; int codec;
int iterator;
/* Get codec and RTP info from SDP */ /* Get codec and RTP info from SDP */
m = get_sdp(req, "m"); m = get_sdp(req, "m");
c = get_sdp(req, "c"); c = get_sdp(req, "c");
@ -840,25 +866,46 @@ static int process_sdp(struct mgcp_endpoint *p, struct mgcp_request *req)
#if 0 #if 0
printf("Peer RTP is at port %s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); printf("Peer RTP is at port %s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
#endif #endif
peercapability = 0; // Scan through the RTP payload types specified in a "m=" line:
rtp_pt_init(p->rtp);
codecs = m + len; codecs = m + len;
while(strlen(codecs)) { while(strlen(codecs)) {
if (sscanf(codecs, "%d %n", &codec, &len) != 1) { if (sscanf(codecs, "%d %n", &codec, &len) != 1) {
ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs); ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
return -1; return -1;
} }
#if 0 rtp_set_m_type(p->rtp, codec);
printf("Codec: %d\n", codec);
#endif
codec = rtp2ast(codec);
if (codec > -1)
peercapability |= codec;
codecs += len; codecs += len;
} }
// Next, scan through each "a=rtpmap:" line, noting each
// specified RTP payload type (with corresponding MIME subtype):
sdpLineNum_iterator_init(&iterator);
while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
char* mimeSubtype = strdup(a); // ensures we have enough space
int subtypeLen, i;
if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue;
// Note: should really look at the 'freq' and '#chans' params too
subtypeLen = strlen(mimeSubtype);
// Convert the MIME subtype to upper case, for ease of searching:
for (i = 0; i < subtypeLen; ++i) {
mimeSubtype[i] = toupper(mimeSubtype[i]);
}
rtp_set_rtpmap_type(p->rtp, codec, "audio", mimeSubtype);
free(mimeSubtype);
}
// Now gather all of the codecs that were asked for:
rtp_get_current_formats(p->rtp,
&peercapability, &peerNonCodecCapability);
p->capability = capability & peercapability; p->capability = capability & peercapability;
if (mgcpdebug) if (mgcpdebug) {
ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n", ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n",
capability, peercapability, p->capability); capability, peercapability, p->capability);
ast_verbose("Non-codec capabilities: us - %d, them - %d, combined - %d\n",
nonCodecCapability, peerNonCodecCapability,
p->nonCodecCapability);
}
if (!p->capability) { if (!p->capability) {
ast_log(LOG_WARNING, "No compatible codecs!\n"); ast_log(LOG_WARNING, "No compatible codecs!\n");
return -1; return -1;
@ -1014,18 +1061,38 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_endpoint *p, struct as
snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", inet_ntoa(dest.sin_addr)); snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", inet_ntoa(dest.sin_addr));
snprintf(t, sizeof(t), "t=0 0\r\n"); snprintf(t, sizeof(t), "t=0 0\r\n");
snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port)); snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) { for (x = 1; x <= AST_FORMAT_MAX_AUDIO; x <<= 1) {
if (p->capability & x) { if (p->capability & x) {
if (mgcpdebug) if (mgcpdebug)
ast_verbose("Answering with capability %d\n", x); ast_verbose("Answering with capability %d\n", x);
if ((codec = ast2rtp(x)) > -1) { codec = rtp_lookup_code(p->rtp, 1, x);
if (codec > -1) {
snprintf(costr, sizeof(costr), " %d", codec); snprintf(costr, sizeof(costr), " %d", codec);
strcat(m, costr); strcat(m, costr);
snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast2rtpn(x)); snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, rtp_lookup_mime_subtype(1, x));
strcat(a, costr); strcat(a, costr);
} }
} }
} }
for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
if (p->nonCodecCapability & x) {
if (mgcpdebug)
ast_verbose("Answering with non-codec capability %d\n", x);
codec = rtp_lookup_code(p->rtp, 0, x);
if (codec > -1) {
snprintf(costr, sizeof(costr), " %d", codec);
strcat(m, costr);
snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, rtp_lookup_mime_subtype(0, x));
strcat(a, costr);
if (x == AST_RTP_DTMF) {
/* Indicate we support DTMF... Not sure about 16, but MSN supports it so dang it, we will too... */
snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n",
codec);
strcat(a, costr);
}
}
}
}
strcat(m, "\r\n"); strcat(m, "\r\n");
len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a); len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
snprintf(costr, sizeof(costr), "%d", len); snprintf(costr, sizeof(costr), "%d", len);
@ -1054,7 +1121,7 @@ static int transmit_modify_with_sdp(struct mgcp_endpoint *p, struct ast_rtp *rtp
snprintf(local, sizeof(local), "p:20"); snprintf(local, sizeof(local), "p:20");
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) { for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
if (p->capability & x) { if (p->capability & x) {
snprintf(tmp, sizeof(tmp), ", a:%s", ast2rtpn(x)); snprintf(tmp, sizeof(tmp), ", a:%s", rtp_lookup_mime_subtype(1, x));
strcat(local, tmp); strcat(local, tmp);
} }
} }
@ -1079,7 +1146,7 @@ static int transmit_connect_with_sdp(struct mgcp_endpoint *p, struct ast_rtp *rt
snprintf(local, sizeof(local), "p:20"); snprintf(local, sizeof(local), "p:20");
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) { for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
if (p->capability & x) { if (p->capability & x) {
snprintf(tmp, sizeof(tmp), ", a:%s", ast2rtpn(x)); snprintf(tmp, sizeof(tmp), ", a:%s", rtp_lookup_mime_subtype(1, x));
strcat(local, tmp); strcat(local, tmp);
} }
} }

@ -95,8 +95,9 @@ static pthread_t monitor_thread = 0;
static int restart_monitor(void); static int restart_monitor(void);
/* Just about everybody seems to support ulaw, so make it a nice default */ /* Codecs that we support by default: */
static int capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM; static int capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM;
static int nonCodecCapability = AST_RTP_DTMF;
static char ourhost[256]; static char ourhost[256];
static struct in_addr __ourip; static struct in_addr __ourip;
@ -106,6 +107,8 @@ static int sipdebug = 0;
static int tos = 0; static int tos = 0;
static int globaldtmfmode = SIP_DTMF_RFC2833;
/* Expire slowly */ /* Expire slowly */
static int expirey = 900; static int expirey = 900;
@ -143,6 +146,7 @@ static struct sip_pvt {
int alreadygone; /* Whether or not we've already been destroyed by or peer */ int alreadygone; /* Whether or not we've already been destroyed by or peer */
int needdestroy; /* if we need to be destroyed */ int needdestroy; /* if we need to be destroyed */
int capability; /* Special capability */ int capability; /* Special capability */
int nonCodecCapability;
int outgoing; /* Outgoing or incoming call? */ int outgoing; /* Outgoing or incoming call? */
int insecure; /* Don't check source port/ip */ int insecure; /* Don't check source port/ip */
int expirey; /* How long we take to expire */ int expirey; /* How long we take to expire */
@ -226,6 +230,7 @@ struct sip_peer {
int expire; int expire;
int expirey; int expirey;
int capability; int capability;
int nonCodecCapability;
int insecure; int insecure;
int nat; int nat;
int canreinvite; int canreinvite;
@ -299,6 +304,7 @@ static int transmit_response_with_auth(struct sip_pvt *p, char *msg, struct sip_
static int transmit_request(struct sip_pvt *p, char *msg, int inc); static int transmit_request(struct sip_pvt *p, char *msg, int inc);
static int transmit_invite(struct sip_pvt *p, char *msg, int sendsdp, char *auth, char *vxml_url); static int transmit_invite(struct sip_pvt *p, char *msg, int sendsdp, char *auth, char *vxml_url);
static int transmit_reinvite_with_sdp(struct sip_pvt *p, struct ast_rtp *rtp); static int transmit_reinvite_with_sdp(struct sip_pvt *p, struct ast_rtp *rtp);
static int transmit_info_with_digit(struct sip_pvt *p, char digit);
static int transmit_message_with_text(struct sip_pvt *p, char *text); static int transmit_message_with_text(struct sip_pvt *p, char *text);
static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req); static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req);
@ -388,6 +394,7 @@ static int create_addr(struct sip_pvt *r, char *peer)
if (!strcasecmp(p->name, peer)) { if (!strcasecmp(p->name, peer)) {
found++; found++;
r->capability = p->capability; r->capability = p->capability;
r->nonCodecCapability = p->nonCodecCapability;
r->nat = p->nat; r->nat = p->nat;
if (r->rtp) { if (r->rtp) {
ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", r->nat); ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", r->nat);
@ -399,7 +406,8 @@ static int create_addr(struct sip_pvt *r, char *peer)
r->insecure = p->insecure; r->insecure = p->insecure;
r->canreinvite = p->canreinvite; r->canreinvite = p->canreinvite;
r->maxtime = p->maxms; r->maxtime = p->maxms;
r->dtmfmode = p->dtmfmode; if (p->dtmfmode)
r->dtmfmode = p->dtmfmode;
strncpy(r->context, p->context,sizeof(r->context)-1); strncpy(r->context, p->context,sizeof(r->context)-1);
if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) && if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
(!p->maxms || ((p->lastms > 0) && (p->lastms <= p->maxms)))) { (!p->maxms || ((p->lastms > 0) && (p->lastms <= p->maxms)))) {
@ -722,7 +730,7 @@ static int sip_hangup(struct ast_channel *ast)
transmit_request(p, "CANCEL", 0); transmit_request(p, "CANCEL", 0);
} else { } else {
/* Send a hangup */ /* Send a hangup */
transmit_request(p, "BYE", p->outgoing); transmit_request(p, "BYE", 1);
} }
} }
#if 0 #if 0
@ -820,6 +828,9 @@ static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
static int sip_senddigit(struct ast_channel *ast, char digit) static int sip_senddigit(struct ast_channel *ast, char digit)
{ {
struct sip_pvt *p = ast->pvt->pvt; struct sip_pvt *p = ast->pvt->pvt;
if (p && (p->dtmfmode & SIP_DTMF_INFO)) {
transmit_info_with_digit(p, digit);
}
if (p && p->rtp && (p->dtmfmode & SIP_DTMF_RFC2833)) { if (p && p->rtp && (p->dtmfmode & SIP_DTMF_RFC2833)) {
ast_rtp_senddigit(p->rtp, digit); ast_rtp_senddigit(p->rtp, digit);
} }
@ -1018,21 +1029,41 @@ static struct cfalias {
{ "Via", "v" }, { "Via", "v" },
}; };
static char *get_sdp(struct sip_request *req, char *name) static char* get_sdp_by_line(char* line, char *name, int nameLen) {
{ if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
int x; char* r = line + nameLen + 1;
int len = strlen(name); while (*r && (*r < 33)) ++r;
char *r; return r;
for (x=0;x<req->lines;x++) { }
if (!strncasecmp(req->line[x], name, len) &&
(req->line[x][len] == '=')) { return "";
r = req->line[x] + len + 1; }
while(*r && (*r < 33))
r++; static char *get_sdp(struct sip_request *req, char *name) {
return r; int x;
} int len = strlen(name);
} char *r;
return "";
for (x=0; x<req->lines; x++) {
r = get_sdp_by_line(req->line[x], name, len);
if (r[0] != '\0') return r;
}
return "";
}
static void sdpLineNum_iterator_init(int* iterator) {
*iterator = 0;
}
static char* get_sdp_iterate(int* iterator,
struct sip_request *req, char *name) {
int len = strlen(name);
char *r;
while (*iterator < req->lines) {
r = get_sdp_by_line(req->line[(*iterator)++], name, len);
if (r[0] != '\0') return r;
}
return "";
} }
static char *__get_header(struct sip_request *req, char *name, int *start) static char *__get_header(struct sip_request *req, char *name, int *start)
@ -1161,7 +1192,7 @@ static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useg
strncpy(p->callid, callid, sizeof(p->callid) - 1); strncpy(p->callid, callid, sizeof(p->callid) - 1);
/* Assume reinvite OK */ /* Assume reinvite OK */
p->canreinvite = 1; p->canreinvite = 1;
p->dtmfmode = SIP_DTMF_RFC2833; p->dtmfmode = globaldtmfmode;
/* Add to list */ /* Add to list */
ast_pthread_mutex_lock(&iflock); ast_pthread_mutex_lock(&iflock);
p->next = iflist; p->next = iflist;
@ -1346,14 +1377,17 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
{ {
char *m; char *m;
char *c; char *c;
char *a;
char host[258]; char host[258];
int len = -1; int len = -1;
int portno; int portno;
int peercapability; int peercapability, peerNonCodecCapability;
struct sockaddr_in sin; struct sockaddr_in sin;
char *codecs; char *codecs;
struct hostent *hp; struct hostent *hp;
int codec; int codec;
int iterator;
/* Get codec and RTP info from SDP */ /* Get codec and RTP info from SDP */
if (strcasecmp(get_header(req, "Content-Type"), "application/sdp")) { if (strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
ast_log(LOG_NOTICE, "Content is '%s', not 'application/sdp'\n", get_header(req, "Content-Type")); ast_log(LOG_NOTICE, "Content is '%s', not 'application/sdp'\n", get_header(req, "Content-Type"));
@ -1387,25 +1421,47 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
#if 0 #if 0
printf("Peer RTP is at port %s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); printf("Peer RTP is at port %s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
#endif #endif
peercapability = 0; // Scan through the RTP payload types specified in a "m=" line:
rtp_pt_init(p->rtp);
codecs = m + len; codecs = m + len;
while(strlen(codecs)) { while(strlen(codecs)) {
if (sscanf(codecs, "%d %n", &codec, &len) != 1) { if (sscanf(codecs, "%d %n", &codec, &len) != 1) {
ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs); ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
return -1; return -1;
} }
#if 0 rtp_set_m_type(p->rtp, codec);
printf("Codec: %d\n", codec);
#endif
codec = rtp2ast(codec);
if (codec > -1)
peercapability |= codec;
codecs += len; codecs += len;
} }
// Next, scan through each "a=rtpmap:" line, noting each
// specified RTP payload type (with corresponding MIME subtype):
sdpLineNum_iterator_init(&iterator);
while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
char* mimeSubtype = strdup(a); // ensures we have enough space
int subtypeLen, i;
if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue;
// Note: should really look at the 'freq' and '#chans' params too
subtypeLen = strlen(mimeSubtype);
// Convert the MIME subtype to upper case, for ease of searching:
for (i = 0; i < subtypeLen; ++i) {
mimeSubtype[i] = toupper(mimeSubtype[i]);
}
rtp_set_rtpmap_type(p->rtp, codec, "audio", mimeSubtype);
free(mimeSubtype);
}
// Now gather all of the codecs that were asked for:
rtp_get_current_formats(p->rtp,
&peercapability, &peerNonCodecCapability);
p->capability = capability & peercapability; p->capability = capability & peercapability;
if (sipdebug) p->nonCodecCapability = nonCodecCapability & peerNonCodecCapability;
if (sipdebug) {
ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n", ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n",
capability, peercapability, p->capability); capability, peercapability, p->capability);
ast_verbose("Non-codec capabilities: us - %d, them - %d, combined - %d\n",
nonCodecCapability, peerNonCodecCapability,
p->nonCodecCapability);
}
if (!p->capability) { if (!p->capability) {
ast_log(LOG_WARNING, "No compatible codecs!\n"); ast_log(LOG_WARNING, "No compatible codecs!\n");
return -1; return -1;
@ -1540,7 +1596,7 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, struct s
for (;;) { for (;;) {
tmp = __get_header(orig, field, &start); tmp = __get_header(orig, field, &start);
if (strlen(tmp)) { if (strlen(tmp)) {
if (!copied) { if (!copied && p->nat) {
if (ntohs(p->recv.sin_port) != DEFAULT_SIP_PORT) if (ntohs(p->recv.sin_port) != DEFAULT_SIP_PORT)
snprintf(new, sizeof(new), "%s;received=%s:%d", tmp, inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); snprintf(new, sizeof(new), "%s;received=%s:%d", tmp, inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
else else
@ -1746,6 +1802,20 @@ static int add_text(struct sip_request *req, char *text)
return 0; return 0;
} }
static int add_digit(struct sip_request *req, char digit)
{
char tmp[256];
int len;
char clen[256];
snprintf(tmp, sizeof(tmp), "Signal=%c\r\nDuration=250\r\n", digit);
len = strlen(tmp);
snprintf(clen, sizeof(clen), "%d", len);
add_header(req, "Content-Type", "application/dtmf-relay");
add_header(req, "Content-Length", clen);
add_line(req, tmp);
return 0;
}
static int add_sdp(struct sip_request *resp, struct sip_pvt *p, struct ast_rtp *rtp) static int add_sdp(struct sip_request *resp, struct sip_pvt *p, struct ast_rtp *rtp)
{ {
int len; int len;
@ -1791,33 +1861,51 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p, struct ast_rtp *
if (p->capability & cur->codec) { if (p->capability & cur->codec) {
if (sipdebug) if (sipdebug)
ast_verbose("Answering with preferred capability %d\n", cur->codec); ast_verbose("Answering with preferred capability %d\n", cur->codec);
if ((codec = ast2rtp(cur->codec)) > -1) { codec = rtp_lookup_code(p->rtp, 1, cur->codec);
if (codec > -1) {
snprintf(costr, sizeof(costr), " %d", codec); snprintf(costr, sizeof(costr), " %d", codec);
strcat(m, costr); strcat(m, costr);
snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast2rtpn(rtp2ast(codec))); snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, rtp_lookup_mime_subtype(1, cur->codec));
strcat(a, costr); strcat(a, costr);
} }
} }
alreadysent |= cur->codec; alreadysent |= cur->codec;
cur = cur->next; cur = cur->next;
} }
/* Now send anything else in no particular order */ /* Now send any other common codecs, and non-codec formats: */
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) { for (x = 1; x <= AST_FORMAT_MAX_AUDIO; x <<= 1) {
if ((p->capability & x) && !(alreadysent & x)) { if ((p->capability & x) && !(alreadysent & x)) {
if (sipdebug) if (sipdebug)
ast_verbose("Answering with capability %d\n", x); ast_verbose("Answering with capability %d\n", x);
if ((codec = ast2rtp(x)) > -1) { codec = rtp_lookup_code(p->rtp, 1, x);
if (codec > -1) {
snprintf(costr, sizeof(costr), " %d", codec);
strcat(m, costr);
snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, rtp_lookup_mime_subtype(1, x));
strcat(a, costr);
}
}
}
for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
if (p->nonCodecCapability & x) {
if (sipdebug)
ast_verbose("Answering with non-codec capability %d\n", x);
codec = rtp_lookup_code(p->rtp, 0, x);
if (codec > -1) {
snprintf(costr, sizeof(costr), " %d", codec); snprintf(costr, sizeof(costr), " %d", codec);
strcat(m, costr); strcat(m, costr);
snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast2rtpn(x)); snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, rtp_lookup_mime_subtype(0, x));
strcat(a, costr); strcat(a, costr);
if (x == AST_RTP_DTMF) {
/* Indicate we support DTMF... Not sure about 16, but MSN supports it so dang it, we will too... */
snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n",
codec);
strcat(a, costr);
}
} }
} }
} }
strcat(m, " 101\r\n"); strcat(m, "\r\n");
strcat(a, "a=rtpmap:101 telephone-event/8000\r\n");
/* Indicate we support DTMF only... Not sure about 16, but MSN supports it so dang it, we will too... */
strcat(a, "a=fmtp:101 0-16\r\n");
len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a); len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
snprintf(costr, sizeof(costr), "%d", len); snprintf(costr, sizeof(costr), "%d", len);
add_header(resp, "Content-Type", "application/sdp"); add_header(resp, "Content-Type", "application/sdp");
@ -2079,6 +2167,14 @@ static int transmit_message_with_text(struct sip_pvt *p, char *text)
return send_request(p, &req); return send_request(p, &req);
} }
static int transmit_info_with_digit(struct sip_pvt *p, char digit)
{
struct sip_request req;
reqprep(&req, p, "INFO", 1);
add_digit(&req, digit);
return send_request(p, &req);
}
static int transmit_request(struct sip_pvt *p, char *msg, int inc) static int transmit_request(struct sip_pvt *p, char *msg, int inc)
{ {
struct sip_request resp; struct sip_request resp;
@ -2574,7 +2670,8 @@ static int check_user(struct sip_pvt *p, struct sip_request *req, char *cmd, cha
strncpy(p->accountcode, user->accountcode, sizeof(p->accountcode) -1); strncpy(p->accountcode, user->accountcode, sizeof(p->accountcode) -1);
p->canreinvite = user->canreinvite; p->canreinvite = user->canreinvite;
p->amaflags = user->amaflags; p->amaflags = user->amaflags;
p->dtmfmode = user->dtmfmode; if (user->dtmfmode)
p->dtmfmode = user->dtmfmode;
} }
break; break;
} }
@ -2772,6 +2869,7 @@ static char *complete_sipch(char *line, char *word, int pos, int state)
static int sip_show_channel(int fd, int argc, char *argv[]) static int sip_show_channel(int fd, int argc, char *argv[])
{ {
struct sip_pvt *cur; struct sip_pvt *cur;
char tmp[256];
if (argc != 4) if (argc != 4)
return RESULT_SHOWUSAGE; return RESULT_SHOWUSAGE;
ast_pthread_mutex_lock(&iflock); ast_pthread_mutex_lock(&iflock);
@ -2782,6 +2880,14 @@ static int sip_show_channel(int fd, int argc, char *argv[])
ast_cli(fd, "Theoretical Address: %s:%d\n", inet_ntoa(cur->sa.sin_addr), ntohs(cur->sa.sin_port)); ast_cli(fd, "Theoretical Address: %s:%d\n", inet_ntoa(cur->sa.sin_addr), ntohs(cur->sa.sin_port));
ast_cli(fd, "Received Address: %s:%d\n", inet_ntoa(cur->recv.sin_addr), ntohs(cur->recv.sin_port)); ast_cli(fd, "Received Address: %s:%d\n", inet_ntoa(cur->recv.sin_addr), ntohs(cur->recv.sin_port));
ast_cli(fd, "NAT Support: %s\n", cur->nat ? "Yes" : "No"); ast_cli(fd, "NAT Support: %s\n", cur->nat ? "Yes" : "No");
strcpy(tmp, "");
if (cur->dtmfmode & SIP_DTMF_RFC2833)
strcat(tmp, "rfc2833 ");
if (cur->dtmfmode & SIP_DTMF_INFO)
strcat(tmp, "info ");
if (cur->dtmfmode & SIP_DTMF_INBAND)
strcat(tmp, "inband ");
ast_cli(fd, "DTMF Mode: %s\n", tmp);
break; break;
} }
cur = cur->next; cur = cur->next;
@ -2844,15 +2950,15 @@ static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header
static int do_register_auth(struct sip_pvt *p, struct sip_request *req) { static int do_register_auth(struct sip_pvt *p, struct sip_request *req) {
char digest[256]; char digest[256];
memset(digest,0,sizeof(digest)); memset(digest,0,sizeof(digest));
reply_digest(p,req, "WWW-Authenticate", "REGISTER", (char *)&digest, sizeof(digest) ); reply_digest(p,req, "WWW-Authenticate", "REGISTER", digest, sizeof(digest) );
return transmit_register(p->registry,"REGISTER",(char *)&digest); return transmit_register(p->registry,"REGISTER",digest);
} }
static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req) { static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req) {
char digest[256]; char digest[256];
memset(digest,0,sizeof(digest)); memset(digest,0,sizeof(digest));
reply_digest(p,req, "Proxy-Authenticate", "INVITE", (char *)&digest, sizeof(digest) ); reply_digest(p,req, "Proxy-Authenticate", "INVITE", digest, sizeof(digest) );
return transmit_invite(p,"INVITE",1,(char *)&digest, NULL); return transmit_invite(p,"INVITE",1,digest, NULL);
} }
static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, char *orig_header, char *digest, int digest_len) { static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, char *orig_header, char *digest, int digest_len) {
@ -3083,7 +3189,6 @@ retrylock:
/* char *exp; */ /* char *exp; */
int expires; int expires;
struct sip_registry *r; struct sip_registry *r;
transmit_request(p, "ACK", 0);
r=p->registry; r=p->registry;
r->regstate=REG_STATE_REGISTERED; r->regstate=REG_STATE_REGISTERED;
ast_log(LOG_NOTICE, "Registration successful\n"); ast_log(LOG_NOTICE, "Registration successful\n");
@ -3829,7 +3934,6 @@ static struct sip_user *build_user(char *name, struct ast_variable *v)
user->canreinvite = 1; user->canreinvite = 1;
/* JK02: set default context */ /* JK02: set default context */
strcpy(user->context, context); strcpy(user->context, context);
user->dtmfmode = SIP_DTMF_RFC2833;
while(v) { while(v) {
if (!strcasecmp(v->name, "context")) { if (!strcasecmp(v->name, "context")) {
strncpy(user->context, v->value, sizeof(user->context)); strncpy(user->context, v->value, sizeof(user->context));
@ -3869,7 +3973,8 @@ static struct sip_user *build_user(char *name, struct ast_variable *v)
} }
} else if (!strcasecmp(v->name, "insecure")) { } else if (!strcasecmp(v->name, "insecure")) {
user->insecure = ast_true(v->value); user->insecure = ast_true(v->value);
} } //else if (strcasecmp(v->name,"type"))
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v = v->next; v = v->next;
} }
} }
@ -3924,7 +4029,7 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
peer->capability = capability; peer->capability = capability;
/* Assume can reinvite */ /* Assume can reinvite */
peer->canreinvite = 1; peer->canreinvite = 1;
peer->dtmfmode = SIP_DTMF_RFC2833; peer->dtmfmode = 0;
while(v) { while(v) {
if (!strcasecmp(v->name, "secret")) if (!strcasecmp(v->name, "secret"))
strncpy(peer->secret, v->value, sizeof(peer->secret)-1); strncpy(peer->secret, v->value, sizeof(peer->secret)-1);
@ -4017,8 +4122,8 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno); ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of iax.conf\n", peer->name, v->lineno);
peer->maxms = 0; peer->maxms = 0;
} }
} } //else if (strcasecmp(v->name,"type"))
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v=v->next; v=v->next;
} }
if (!strlen(peer->methods)) if (!strlen(peer->methods))
@ -4039,6 +4144,8 @@ static int reload_config(void)
struct hostent *hp; struct hostent *hp;
int format; int format;
int oldport = ntohs(bindaddr.sin_port); int oldport = ntohs(bindaddr.sin_port);
globaldtmfmode = SIP_DTMF_RFC2833;
if (gethostname(ourhost, sizeof(ourhost))) { if (gethostname(ourhost, sizeof(ourhost))) {
ast_log(LOG_WARNING, "Unable to get hostname, SIP disabled\n"); ast_log(LOG_WARNING, "Unable to get hostname, SIP disabled\n");
@ -4065,6 +4172,17 @@ static int reload_config(void)
/* Create the interface list */ /* Create the interface list */
if (!strcasecmp(v->name, "context")) { if (!strcasecmp(v->name, "context")) {
strncpy(context, v->value, sizeof(context)-1); strncpy(context, v->value, sizeof(context)-1);
} else if (!strcasecmp(v->name, "dtmfmode")) {
if (!strcasecmp(v->value, "inband"))
globaldtmfmode=SIP_DTMF_INBAND;
else if (!strcasecmp(v->value, "rfc2833"))
globaldtmfmode = SIP_DTMF_RFC2833;
else if (!strcasecmp(v->value, "info"))
globaldtmfmode = SIP_DTMF_INFO;
else {
ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value);
globaldtmfmode = SIP_DTMF_RFC2833;
}
} else if (!strcasecmp(v->name, "language")) { } else if (!strcasecmp(v->name, "language")) {
strncpy(language, v->value, sizeof(language)-1); strncpy(language, v->value, sizeof(language)-1);
} else if (!strcasecmp(v->name, "nat")) { } else if (!strcasecmp(v->name, "nat")) {
@ -4122,9 +4240,9 @@ static int reload_config(void)
} else { } else {
ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config); ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
} }
} else } //else if (strcasecmp(v->name,"type"))
ast_log(LOG_NOTICE, "Ignoring unknown SIP general keyword '%s'\n", v->name); // ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v = v->next; v = v->next;
} }
cat = ast_category_browse(cfg, NULL); cat = ast_category_browse(cfg, NULL);
@ -4181,6 +4299,12 @@ static int reload_config(void)
if (sipsock < 0) { if (sipsock < 0) {
ast_log(LOG_WARNING, "Unable to create SIP socket: %s\n", strerror(errno)); ast_log(LOG_WARNING, "Unable to create SIP socket: %s\n", strerror(errno));
} else { } else {
// Allow SIP clients on the same host to access us:
const int reuseFlag = 1;
setsockopt(sipsock, SOL_SOCKET, SO_REUSEADDR,
(const char*)&reuseFlag,
sizeof reuseFlag);
if (bind(sipsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) { if (bind(sipsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n", ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port), inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),

@ -6285,7 +6285,7 @@ int load_module()
strncpy(idledial, v->value, sizeof(idledial) - 1); strncpy(idledial, v->value, sizeof(idledial) - 1);
#endif #endif
} else } else
ast_log(LOG_DEBUG, "Ignoring %s\n", v->name); ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v = v->next; v = v->next;
} }
ast_pthread_mutex_unlock(&iflock); ast_pthread_mutex_unlock(&iflock);
@ -6638,7 +6638,7 @@ static int reload_zt(void)
strncpy(idledial, v->value, sizeof(idledial) - 1); strncpy(idledial, v->value, sizeof(idledial) - 1);
#endif #endif
} else } else
ast_log(LOG_DEBUG, "Ignoring %s\n", v->name); ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
v = v->next; v = v->next;
} }

63
cli.c

@ -217,6 +217,14 @@ static char showchan_help[] =
"Usage: show channel <channel>\n" "Usage: show channel <channel>\n"
" Shows lots of information about the specified channel.\n"; " Shows lots of information about the specified channel.\n";
static char debugchan_help[] =
"Usage: debug channel <channel>\n"
" Enables debugging on a specific channel.\n";
static char nodebugchan_help[] =
"Usage: no debug channel <channel>\n"
" Disables debugging on a specific channel.\n";
static char commandcomplete_help[] = static char commandcomplete_help[] =
"Usage: _command complete \"<line>\" text state\n" "Usage: _command complete \"<line>\" text state\n"
" This function is used internally to help with command completion and should.\n" " This function is used internally to help with command completion and should.\n"
@ -323,6 +331,50 @@ static int handle_commandcomplete(int fd, int argc, char *argv[])
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
static int handle_debugchan(int fd, int argc, char *argv[])
{
struct ast_channel *c=NULL;
if (argc != 3)
return RESULT_SHOWUSAGE;
c = ast_channel_walk(NULL);
while(c) {
if (!strcasecmp(c->name, argv[2])) {
c->fin |= 0x80000000;
c->fout |= 0x80000000;
break;
}
c = ast_channel_walk(c);
}
if (c)
ast_cli(fd, "Debugging enabled on channel %s\n", c->name);
else
ast_cli(fd, "No such channel %s\n", argv[2]);
return RESULT_SUCCESS;
}
static int handle_nodebugchan(int fd, int argc, char *argv[])
{
struct ast_channel *c=NULL;
if (argc != 4)
return RESULT_SHOWUSAGE;
c = ast_channel_walk(NULL);
while(c) {
if (!strcasecmp(c->name, argv[3])) {
c->fin &= 0x7fffffff;
c->fout &= 0x7fffffff;
break;
}
c = ast_channel_walk(c);
}
if (c)
ast_cli(fd, "Debugging disabled on channel %s\n", c->name);
else
ast_cli(fd, "No such channel %s\n", argv[2]);
return RESULT_SUCCESS;
}
static int handle_showchan(int fd, int argc, char *argv[]) static int handle_showchan(int fd, int argc, char *argv[])
{ {
struct ast_channel *c=NULL; struct ast_channel *c=NULL;
@ -343,8 +395,8 @@ static int handle_showchan(int fd, int argc, char *argv[])
" WriteFormat: %d\n" " WriteFormat: %d\n"
" ReadFormat: %d\n" " ReadFormat: %d\n"
"1st File Descriptor: %d\n" "1st File Descriptor: %d\n"
" Frames in: %d\n" " Frames in: %d%s\n"
" Frames out: %d\n" " Frames out: %d%s\n"
" Time to Hangup: %d\n" " Time to Hangup: %d\n"
" -- PBX --\n" " -- PBX --\n"
" Context: %s\n" " Context: %s\n"
@ -357,7 +409,8 @@ static int handle_showchan(int fd, int argc, char *argv[])
c->name, c->type, c->name, c->type,
(c->callerid ? c->callerid : "(N/A)"), (c->callerid ? c->callerid : "(N/A)"),
(c->dnid ? c->dnid : "(N/A)" ), ast_state2str(c->_state), c->_state, c->rings, c->nativeformats, c->writeformat, c->readformat, (c->dnid ? c->dnid : "(N/A)" ), ast_state2str(c->_state), c->_state, c->rings, c->nativeformats, c->writeformat, c->readformat,
c->fds[0], c->fin, c->fout, c->whentohangup, c->fds[0], c->fin & 0x7fffffff, (c->fin & 0x80000000) ? " (DEBUGGED)" : "",
c->fout & 0x7fffffff, (c->fout & 0x80000000) ? " (DEBUGGED)" : "", c->whentohangup,
c->context, c->exten, c->priority, ( c->appl ? c->appl : "(N/A)" ), c->context, c->exten, c->priority, ( c->appl ? c->appl : "(N/A)" ),
( c-> data ? (strlen(c->data) ? c->data : "(Empty)") : "(None)"), ( c-> data ? (strlen(c->data) ? c->data : "(Empty)") : "(None)"),
c->stack, (c->blocking ? c->blockproc : "(Not Blocking)")); c->stack, (c->blocking ? c->blockproc : "(Not Blocking)"));
@ -406,11 +459,13 @@ static int handle_help(int fd, int argc, char *argv[]);
static struct ast_cli_entry builtins[] = { static struct ast_cli_entry builtins[] = {
/* Keep alphabetized */ /* Keep alphabetized */
{ { "help", NULL }, handle_help, "Display help list, or specific help on a command", help_help },
{ { "_command", "complete", NULL }, handle_commandcomplete, "Command complete", commandcomplete_help }, { { "_command", "complete", NULL }, handle_commandcomplete, "Command complete", commandcomplete_help },
{ { "_command", "nummatches", NULL }, handle_commandnummatches, "Returns number of command matches", commandnummatches_help }, { { "_command", "nummatches", NULL }, handle_commandnummatches, "Returns number of command matches", commandnummatches_help },
{ { "_command", "matchesarray", NULL }, handle_commandmatchesarray, "Returns command matches array", commandmatchesarray_help }, { { "_command", "matchesarray", NULL }, handle_commandmatchesarray, "Returns command matches array", commandmatchesarray_help },
{ { "debug", "channel", NULL }, handle_debugchan, "Enable debugging on a channel", debugchan_help, complete_ch },
{ { "help", NULL }, handle_help, "Display help list, or specific help on a command", help_help },
{ { "load", NULL }, handle_load, "Load a dynamic module by name", load_help, complete_fn }, { { "load", NULL }, handle_load, "Load a dynamic module by name", load_help, complete_fn },
{ { "no", "debug", "channel", NULL }, handle_nodebugchan, "Disable debugging on a channel", nodebugchan_help, complete_ch },
{ { "reload", NULL }, handle_reload, "Reload configuration", reload_help }, { { "reload", NULL }, handle_reload, "Reload configuration", reload_help },
{ { "set", "verbose", NULL }, handle_set_verbose, "Set level of verboseness", set_verbose_help }, { { "set", "verbose", NULL }, handle_set_verbose, "Set level of verboseness", set_verbose_help },
{ { "show", "channel", NULL }, handle_showchan, "Display information on a specific channel", showchan_help, complete_ch }, { { "show", "channel", NULL }, handle_showchan, "Display information on a specific channel", showchan_help, complete_ch },

@ -21,7 +21,8 @@ writeprotect=no
; ;
; The "Globals" category contains global variables that can be referenced ; The "Globals" category contains global variables that can be referenced
; in the dialplan with ${VARIABLE} ; in the dialplan with ${VARIABLE} or ${ENV(VARIABLE)} for Environmental variable
; ${${VARIABLE}} or ${text${VARIABLE}} or any hybrid
; ;
[globals] [globals]
CONSOLE=Console/dsp ; Console interface for demo CONSOLE=Console/dsp ; Console interface for demo

@ -16,6 +16,7 @@
#include <asterisk/logger.h> #include <asterisk/logger.h>
#include <asterisk/options.h> #include <asterisk/options.h>
#include <asterisk/cli.h> #include <asterisk/cli.h>
#include <asterisk/term.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
@ -346,6 +347,161 @@ int ast_getformatbyname(char *name)
return 0; return 0;
} }
void ast_frame_dump(char *name, struct ast_frame *f, char *prefix)
{
char *n = "unknown";
char ftype[40] = "Unknown Frametype";
char cft[80];
char subclass[40] = "Unknown Subclass";
char csub[80];
char moreinfo[40] = "";
char cn[40];
char cp[40];
char cmn[40];
if (name)
n = name;
if (!f) {
ast_verbose("%s [ %s (NULL) ] [%s]\n",
term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
return;
}
/* XXX We should probably print one each of voice and video when the format changes XXX */
if (f->frametype == AST_FRAME_VOICE)
return;
if (f->frametype == AST_FRAME_VIDEO)
return;
switch(f->frametype) {
case AST_FRAME_DTMF:
strcpy(ftype, "DTMF");
subclass[0] = f->subclass;
subclass[1] = '\0';
break;
case AST_FRAME_CONTROL:
strcpy(ftype, "Control");
switch(f->subclass) {
case AST_CONTROL_HANGUP:
strcpy(subclass, "Hangup");
break;
case AST_CONTROL_RING:
strcpy(subclass, "Ring");
break;
case AST_CONTROL_RINGING:
strcpy(subclass, "Ringing");
break;
case AST_CONTROL_ANSWER:
strcpy(subclass, "Answer");
break;
case AST_CONTROL_BUSY:
strcpy(subclass, "Busy");
break;
case AST_CONTROL_TAKEOFFHOOK:
strcpy(subclass, "Take Off Hook");
break;
case AST_CONTROL_OFFHOOK:
strcpy(subclass, "Line Off Hook");
break;
case AST_CONTROL_CONGESTION:
strcpy(subclass, "Congestion");
break;
case AST_CONTROL_FLASH:
strcpy(subclass, "Flash");
break;
case AST_CONTROL_WINK:
strcpy(subclass, "Wink");
break;
case AST_CONTROL_OPTION:
strcpy(subclass, "Option");
break;
case AST_CONTROL_RADIO_KEY:
strcpy(subclass, "Key Radio");
break;
case AST_CONTROL_RADIO_UNKEY:
strcpy(subclass, "Unkey Radio");
break;
default:
snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
}
case AST_FRAME_NULL:
strcpy(ftype, "Null Frame");
strcpy(subclass, "N/A");
break;
case AST_FRAME_IAX:
/* Should never happen */
strcpy(ftype, "IAX Specific");
snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
break;
case AST_FRAME_TEXT:
strcpy(ftype, "Text");
strcpy(subclass, "N/A");
strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
break;
case AST_FRAME_IMAGE:
strcpy(ftype, "Image");
snprintf(subclass, sizeof(subclass), "Image format %d\n", f->subclass);
break;
case AST_FRAME_HTML:
strcpy(ftype, "HTML");
switch(f->subclass) {
case AST_HTML_URL:
strcpy(subclass, "URL");
strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
break;
case AST_HTML_DATA:
strcpy(subclass, "Data");
break;
case AST_HTML_BEGIN:
strcpy(subclass, "Begin");
break;
case AST_HTML_END:
strcpy(subclass, "End");
break;
case AST_HTML_LDCOMPLETE:
strcpy(subclass, "Load Complete");
break;
case AST_HTML_NOSUPPORT:
strcpy(subclass, "No Support");
break;
case AST_HTML_LINKURL:
strcpy(subclass, "Link URL");
strncpy(moreinfo, f->data, sizeof(moreinfo) - 1);
break;
case AST_HTML_UNLINK:
strcpy(subclass, "Unlink");
break;
case AST_HTML_LINKREJECT:
strcpy(subclass, "Link Reject");
break;
default:
snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
break;
}
break;
default:
snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
}
if (strlen(moreinfo))
ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",
term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
f->frametype,
term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
f->subclass,
term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
else
ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",
term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
f->frametype,
term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
f->subclass,
term_color(cn, n, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
}
#ifdef TRACE_FRAMES #ifdef TRACE_FRAMES
static int show_frame_stats(int fd, int argc, char *argv[]) static int show_frame_stats(int fd, int argc, char *argv[])
{ {

@ -291,6 +291,8 @@ extern void ast_smoother_reset(struct ast_smoother *s, int bytes);
extern int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f); extern int ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f);
extern struct ast_frame *ast_smoother_read(struct ast_smoother *s); extern struct ast_frame *ast_smoother_read(struct ast_smoother *s);
extern void ast_frame_dump(char *name, struct ast_frame *f, char *prefix);
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} }
#endif #endif

@ -25,6 +25,14 @@
extern "C" { extern "C" {
#endif #endif
/* Codes for RTP-specific data - not defined by our AST_FORMAT codes */
/*! DTMF (RFC2833) */
#define AST_RTP_DTMF (1 << 0)
/*! 'Comfort Noise' (RFC3389) */
#define AST_RTP_CN (1 << 1)
/*! Maximum RTP-specific code */
#define AST_RTP_MAX AST_RTP_CN
struct ast_rtp_protocol { struct ast_rtp_protocol {
struct ast_rtp *(*get_rtp_info)(struct ast_channel *chan); /* Get RTP struct, or NULL if unwilling to transfer */ struct ast_rtp *(*get_rtp_info)(struct ast_channel *chan); /* Get RTP struct, or NULL if unwilling to transfer */
int (*set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer); /* Set RTP peer */ int (*set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer); /* Set RTP peer */
@ -61,13 +69,23 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit);
int ast_rtp_settos(struct ast_rtp *rtp, int tos); int ast_rtp_settos(struct ast_rtp *rtp, int tos);
void ast_rtp_setnat(struct ast_rtp *rtp, int nat); // Setting RTP payload types from lines in a SDP description:
void rtp_pt_init(struct ast_rtp* rtp);
void rtp_set_m_type(struct ast_rtp* rtp, int pt);
void rtp_set_rtpmap_type(struct ast_rtp* rtp, int pt,
char* mimeType, char* mimeSubtype);
int ast2rtp(int id); // Mapping between RTP payload format codes and Asterisk codes:
struct rtpPayloadType rtp_lookup_pt(struct ast_rtp* rtp, int pt);
int rtp_lookup_code(struct ast_rtp* rtp, int isAstFormat, int code);
int rtp2ast(int id); void rtp_get_current_formats(struct ast_rtp* rtp,
int* astFormats, int* nonAstFormats);
char *ast2rtpn(int id); // Mapping an Asterisk code into a MIME subtype (string):
char* rtp_lookup_mime_subtype(int isAstFormat, int code);
void ast_rtp_setnat(struct ast_rtp *rtp, int nat);
int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);

@ -772,6 +772,6 @@ int init_manager(void)
int reload_manager(void) int reload_manager(void)
{ {
manager_event(EVENT_FLAG_SYSTEM, "Reload", NULL); manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
return init_manager(); return init_manager();
} }

29
pbx.c

@ -754,6 +754,14 @@ static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char *
*cp4=ast_var_value(variables); *cp4=ast_var_value(variables);
} }
} }
if (!(*cp4)) {
int len=strlen(cp3);
int len_env=strlen("ENV(");
if (len > (len_env+1) && !strncasecmp(cp3,"ENV(",len_env) && !strcmp(cp3+len-1,")")) {
cp3[len-1]='\0';
*cp4=getenv(cp3+len_env);
}
}
} }
} }
@ -1101,27 +1109,6 @@ int ast_pbx_run(struct ast_channel *c)
c->pbx->rtimeout = 10; c->pbx->rtimeout = 10;
c->pbx->dtimeout = 5; c->pbx->dtimeout = 5;
if (option_debug)
ast_log(LOG_DEBUG, "PBX_THREAD(%s)\n", c->name);
else if (option_verbose > 1) {
struct timeval tv;
struct tm tm;
FILE *LOG;
gettimeofday(&tv,NULL);
localtime_r(&(tv.tv_sec),&tm);
LOG = fopen(AST_SPOOL_DIR "/call.log","a");
if (c->callerid) {
ast_verbose( VERBOSE_PREFIX_2 "Accepting call on '%s' (%s) at %02d-%02d %02d:%02d\n", c->name, c->callerid, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);
fprintf(LOG,"%04d-%02d-%02d %02d:%02d:%02d - %s - %s\n",tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, c->name, c->callerid);
} else {
ast_verbose( VERBOSE_PREFIX_2 "Accepting call on '%s' at %02d-%02d %02d:%02d\n", c->name, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);
fprintf(LOG,"%04d-%02d-%02d %02d:%02d:%02d - %s\n",tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, c->name);
}
fclose(LOG);
}
/* Start by trying whatever the channel is set to */ /* Start by trying whatever the channel is set to */
if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) { if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
/* JK02: If not successfull fall back to 's' */ /* JK02: If not successfull fall back to 's' */

274
rtp.c

@ -39,6 +39,14 @@
static int dtmftimeout = 300; /* 300 samples */ static int dtmftimeout = 300; /* 300 samples */
// The value of each RTP payload format mapping:
struct rtpPayloadType {
int isAstFormat; // whether the following code is an AST_FORMAT
int code;
};
#define MAX_RTP_PT 256
struct ast_rtp { struct ast_rtp {
int s; int s;
char resp; char resp;
@ -62,6 +70,11 @@ struct ast_rtp {
struct io_context *io; struct io_context *io;
void *data; void *data;
ast_rtp_callback callback; ast_rtp_callback callback;
struct rtpPayloadType current_RTP_PT[MAX_RTP_PT];
// a cache for the result of rtp_lookup_code():
int rtp_lookup_code_cache_isAstFormat;
int rtp_lookup_code_cache_code;
int rtp_lookup_code_cache_result;
}; };
static struct ast_rtp_protocol *protos = NULL; static struct ast_rtp_protocol *protos = NULL;
@ -204,41 +217,6 @@ static struct ast_frame *process_rfc3389(struct ast_rtp *rtp, unsigned char *dat
return f; return f;
} }
static struct ast_frame *process_type121(struct ast_rtp *rtp, unsigned char *data, int len)
{
char resp = 0;
struct ast_frame *f = NULL;
unsigned char b0,b1,b2,b3,b4,b5,b6,b7;
b0=*(data+0);b1=*(data+1);b2=*(data+2);b3=*(data+3);
b4=*(data+4);b5=*(data+5);b6=*(data+6);b7=*(data+7);
// printf("%u %u %u %u %u %u %u %u\n",b0,b1,b2,b3,b4,b5,b6,b7);
if (b2==32) {
// printf("Start %d\n",b3);
if (b4==0) {
// printf("Detection point for DTMF %d\n",b3);
if (b3<10) {
resp='0'+b3;
} else if (b3<11) {
resp='*';
} else if (b3<12) {
resp='#';
} else if (b3<16) {
resp='A'+(b3-12);
}
rtp->resp=resp;
f = send_dtmf(rtp);
}
}
if (b2==3) {
// printf("Stop(3) %d\n",b3);
}
if (b2==0) {
// printf("Stop(0) %d\n",b3);
}
return f;
}
static int rtpread(int *id, int fd, short events, void *cbdata) static int rtpread(int *id, int fd, short events, void *cbdata)
{ {
struct ast_rtp *rtp = cbdata; struct ast_rtp *rtp = cbdata;
@ -262,6 +240,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
unsigned int timestamp; unsigned int timestamp;
unsigned int *rtpheader; unsigned int *rtpheader;
static struct ast_frame *f, null_frame = { AST_FRAME_NULL, }; static struct ast_frame *f, null_frame = { AST_FRAME_NULL, };
struct rtpPayloadType rtpPT;
len = sizeof(sin); len = sizeof(sin);
@ -297,29 +276,24 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
printf("Got RTP packet from %s:%d (type %d, seq %d, ts %d, len = %d)\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp,res - hdrlen); printf("Got RTP packet from %s:%d (type %d, seq %d, ts %d, len = %d)\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp,res - hdrlen);
#endif #endif
rtp->f.frametype = AST_FRAME_VOICE; rtp->f.frametype = AST_FRAME_VOICE;
rtp->f.subclass = rtp2ast(payloadtype); rtpPT = rtp_lookup_pt(rtp, payloadtype);
if (rtp->f.subclass < 0) { if (!rtpPT.isAstFormat) {
f = NULL; // This is special in-band data that's not one of our codecs
if (payloadtype == 101) { if (rtpPT.code == AST_RTP_DTMF) {
/* It's special -- rfc2833 process it */ /* It's special -- rfc2833 process it */
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen); f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
} else if (payloadtype == 121) { if (f) return f; else return &null_frame;
/* CISCO proprietary DTMF bridge */ } else if (rtpPT.code == AST_RTP_CN) {
f = process_type121(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen); /* Comfort Noise */
} else if (payloadtype == 100) { f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
/* CISCO's notso proprietary DTMF bridge */ if (f) return f; else return &null_frame;
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen); } else {
} else if (payloadtype == 13) { ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype);
f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen); return &null_frame;
} else { }
ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype); }
} rtp->f.subclass = rtpPT.code;
if (f) rtp->lastrxformat = rtp->f.subclass;
return f;
else
return &null_frame;
} else
rtp->lastrxformat = rtp->f.subclass;
if (!rtp->lastrxts) if (!rtp->lastrxts)
rtp->lastrxts = timestamp; rtp->lastrxts = timestamp;
@ -367,6 +341,10 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
case AST_FORMAT_G723_1: case AST_FORMAT_G723_1:
rtp->f.samples = g723_samples(rtp->f.data, rtp->f.datalen); rtp->f.samples = g723_samples(rtp->f.data, rtp->f.datalen);
break; break;
case AST_FORMAT_SPEEX:
rtp->f.samples = 160;
// assumes that the RTP packet contained one Speex frame
break;
default: default:
ast_log(LOG_NOTICE, "Unable to calculate samples for format %d\n", rtp->f.subclass); ast_log(LOG_NOTICE, "Unable to calculate samples for format %d\n", rtp->f.subclass);
break; break;
@ -375,48 +353,151 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
return &rtp->f; return &rtp->f;
} }
// The following array defines the MIME type (and subtype) for each
// of our codecs, or RTP-specific data type.
static struct { static struct {
int rtp; struct rtpPayloadType payloadType;
int ast; char* type;
char *label; char* subtype;
} cmap[] = { } mimeTypes[] = {
{ 0, AST_FORMAT_ULAW, "PCMU" }, {{1, AST_FORMAT_G723_1}, "audio", "G723"},
{ 3, AST_FORMAT_GSM, "GSM" }, {{1, AST_FORMAT_GSM}, "audio", "GSM"},
{ 4, AST_FORMAT_G723_1, "G723" }, {{1, AST_FORMAT_ULAW}, "audio", "PCMU"},
{ 5, AST_FORMAT_ADPCM, "ADPCM" }, {{1, AST_FORMAT_ALAW}, "audio", "PCMA"},
{ 8, AST_FORMAT_ALAW, "PCMA" }, {{1, AST_FORMAT_MP3}, "audio", "MPA"},
{ 18, AST_FORMAT_G729A, "G729" }, {{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"},
{{0, AST_RTP_DTMF}, "audio", "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"},
}; };
int rtp2ast(int id) // Static (i.e., well-known) RTP payload types for our "AST_FORMAT..."s:
{ static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
int x; [0] = {1, AST_FORMAT_ULAW},
for (x=0;x<sizeof(cmap) / sizeof(cmap[0]); x++) { [3] = {1, AST_FORMAT_GSM},
if (cmap[x].rtp == id) [4] = {1, AST_FORMAT_G723_1},
return cmap[x].ast; [5] = {1, AST_FORMAT_ADPCM}, // 8 kHz
} [6] = {1, AST_FORMAT_ADPCM}, // 16 kHz
return -1; [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},
[14] = {1, AST_FORMAT_MP3},
[16] = {1, AST_FORMAT_ADPCM}, // 11.025 kHz
[17] = {1, AST_FORMAT_ADPCM}, // 22.050 kHz
[18] = {1, AST_FORMAT_G729A},
[26] = {1, AST_FORMAT_JPEG},
[31] = {1, AST_FORMAT_H261},
[34] = {1, AST_FORMAT_H263},
};
void rtp_pt_init(struct ast_rtp* rtp) {
int i;
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;
} }
int ast2rtp(int id) // Make a note of a RTP payload type that was seen in a SDP "m=" line.
{ // By default, use the well-known value for this type (although it may
int x; // still be set to a different value by a subsequent "a=rtpmap:" line):
for (x=0;x<sizeof(cmap) / sizeof(cmap[0]); x++) { void rtp_set_m_type(struct ast_rtp* rtp, int pt) {
if (cmap[x].ast == id) if (pt < 0 || pt > MAX_RTP_PT) return; // bogus payload type
return cmap[x].rtp;
} if (static_RTP_PT[pt].code != 0) {
return -1; rtp->current_RTP_PT[pt] = static_RTP_PT[pt];
}
}
// Make a note of a RTP payload type (with MIME type) that was seen in
// a SDP "a=rtpmap:" line.
void rtp_set_rtpmap_type(struct ast_rtp* rtp, int pt,
char* mimeType, char* mimeSubtype) {
int i;
if (pt < 0 || pt > MAX_RTP_PT) return; // bogus payload type
for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
if (strcmp(mimeSubtype, mimeTypes[i].subtype) == 0 &&
strcmp(mimeType, mimeTypes[i].type) == 0) {
rtp->current_RTP_PT[pt] = mimeTypes[i].payloadType;
return;
}
}
}
// 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 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;
}
}
} }
char *ast2rtpn(int id) struct rtpPayloadType rtp_lookup_pt(struct ast_rtp* rtp, int pt) {
{ if (pt < 0 || pt > MAX_RTP_PT) {
int x; struct rtpPayloadType result;
for (x=0;x<sizeof(cmap) / sizeof(cmap[0]); x++) { result.isAstFormat = result.code = 0;
if (cmap[x].ast == id) return result; // bogus payload type
return cmap[x].label; }
} return rtp->current_RTP_PT[pt];
return ""; }
int rtp_lookup_code(struct ast_rtp* rtp, int isAstFormat, int code) {
int pt;
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;
}
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;
}
}
return -1;
} }
char* rtp_lookup_mime_subtype(int isAstFormat, 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;
}
}
return "";
}
struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io) struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io)
{ {
struct ast_rtp *rtp; struct ast_rtp *rtp;
@ -604,6 +685,10 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
case AST_FORMAT_G723_1: case AST_FORMAT_G723_1:
pred = rtp->lastts + g723_samples(f->data, f->datalen); pred = rtp->lastts + g723_samples(f->data, f->datalen);
break; break;
case AST_FORMAT_SPEEX:
pred = rtp->lastts + 160;
// assumes that the RTP packet contains one Speex frame
break;
default: default:
ast_log(LOG_WARNING, "Not sure about timestamp format for codec format %d\n", f->subclass); ast_log(LOG_WARNING, "Not sure about timestamp format for codec format %d\n", f->subclass);
} }
@ -648,7 +733,7 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
return -1; return -1;
} }
codec = ast2rtp(_f->subclass); codec = rtp_lookup_code(rtp, 1, _f->subclass);
if (codec < 0) { if (codec < 0) {
ast_log(LOG_WARNING, "Don't know how to send format %d packets with RTP\n", _f->subclass); ast_log(LOG_WARNING, "Don't know how to send format %d packets with RTP\n", _f->subclass);
return -1; return -1;
@ -706,6 +791,9 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
break; break;
default: default:
ast_log(LOG_WARNING, "Not sure about sending format %d packets\n", _f->subclass); ast_log(LOG_WARNING, "Not sure about sending format %d packets\n", _f->subclass);
// fall through to...
case AST_FORMAT_SPEEX:
// Don't buffer outgoing frames; send them one-per-packet:
if (_f->offset < hdrlen) { if (_f->offset < hdrlen) {
f = ast_frdup(_f); f = ast_frdup(_f);
} else { } else {

Loading…
Cancel
Save