Wed Mar 12 07:00:01 CET 2003
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@641 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
9cfcee5163
commit
f61680257a
1
CHANGES
1
CHANGES
|
@ -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 NAT and dynamic support to MGCP
|
||||
-- Allow selection of in-band, out-of-band, or INFO based DTMF
|
||||
|
|
2
CREDITS
2
CREDITS
|
@ -34,6 +34,8 @@ Steven Critchfield - Seek and Trunc functions for playback and recording
|
|||
critch@basesys.com
|
||||
Jefferson Noxon - app_lookupcidname, app_db, and various other contributions
|
||||
Klaus-Peter Junghanns - in-band DTMF on SIP and MGCP
|
||||
Ross Finlayson - Dynamic RTP payload support
|
||||
|
||||
=== OTHER SOURCE CODE IN ASTERISK ===
|
||||
|
||||
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 (chan->cdr)
|
||||
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 */
|
||||
res = ast_channel_make_compatible(chan, peer);
|
||||
if (res < 0) {
|
||||
|
|
|
@ -184,17 +184,20 @@ out:
|
|||
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", 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 */
|
||||
chan->priority = oldpriority;
|
||||
strncpy(chan->exten, oldexten, sizeof(chan->exten) - 1);
|
||||
strncpy(chan->context, oldcontext, sizeof(chan->context) - 1);
|
||||
if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
|
||||
/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
|
||||
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;
|
||||
if (!chan->_softhangup) {
|
||||
/* Copy the extension, so long as we're not in softhangup, where we could be given an asyncgoto */
|
||||
strncpy(chan->exten, oldexten, sizeof(chan->exten) - 1);
|
||||
if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
|
||||
/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
16
channel.c
16
channel.c
|
@ -1043,7 +1043,12 @@ struct ast_frame *ast_read(struct ast_channel *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;
|
||||
}
|
||||
|
||||
|
@ -1197,6 +1202,8 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
|
|||
else
|
||||
return 0;
|
||||
}
|
||||
if (chan->fout & 0x80000000)
|
||||
ast_frame_dump(chan->name, fr, ">>");
|
||||
CHECK_BLOCKING(chan);
|
||||
switch(fr->frametype) {
|
||||
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 */
|
||||
if (res < 0)
|
||||
chan->_softhangup |= AST_SOFTHANGUP_DEV;
|
||||
else
|
||||
else {
|
||||
if ((chan->fout & 0x7fffffff) == 0x7fffffff)
|
||||
chan->fout &= 0x80000000;
|
||||
else
|
||||
chan->fout++;
|
||||
chan->fout++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -3409,6 +3409,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
|
|||
char rel0[256];
|
||||
char rel1[255];
|
||||
char empty[32]=""; /* Safety measure */
|
||||
fr.ts=0; /* make Valgrind happy */
|
||||
res = recvfrom(netsocket, buf, sizeof(buf), 0,(struct sockaddr *) &sin, &len);
|
||||
if (res < 0) {
|
||||
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);
|
||||
peer->maxms = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} //else if (strcasecmp(v->name,"type"))
|
||||
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
|
||||
v=v->next;
|
||||
}
|
||||
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")) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -4647,7 +4649,8 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
|
|||
} else {
|
||||
amaflags = format;
|
||||
}
|
||||
}
|
||||
} //else if (strcasecmp(v->name,"type"))
|
||||
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
|
||||
v = v->next;
|
||||
}
|
||||
iax_capability = capability;
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
#define GAMMA (0.01)
|
||||
|
||||
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 context[80] = "default";
|
||||
|
@ -345,8 +345,6 @@ struct chan_iax2_pvt {
|
|||
#define DIRECTION_OUTGRESS 2
|
||||
|
||||
struct ast_iax2_frame {
|
||||
/* Actual, isolated frame */
|
||||
struct ast_frame *f;
|
||||
/* /Our/ call number */
|
||||
unsigned short callno;
|
||||
/* /Their/ call number */
|
||||
|
@ -377,11 +375,13 @@ struct ast_iax2_frame {
|
|||
int direction;
|
||||
/* Retransmission ID */
|
||||
int retrans;
|
||||
|
||||
|
||||
/* Easy linking */
|
||||
struct ast_iax2_frame *next;
|
||||
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 {
|
||||
|
@ -612,7 +612,7 @@ void showframe(struct ast_iax2_frame *f, struct ast_iax2_full_hdr *fhi, int rx,
|
|||
fprintf(stderr,
|
||||
" Timestamp: %05dms SCall: %5.5d DCall: %5.5d [%s:%d]\n",
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
|
@ -746,10 +746,24 @@ static int frames = 0;
|
|||
static int iframes = 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;
|
||||
fr = malloc(sizeof(struct ast_iax2_frame));
|
||||
fr = malloc(sizeof(struct ast_iax2_frame) + datalen);
|
||||
if (fr) {
|
||||
fr->direction = direction;
|
||||
fr->retrans = -1;
|
||||
|
@ -780,24 +794,15 @@ static void ast_iax2_frame_free(struct ast_iax2_frame *fr)
|
|||
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 */
|
||||
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) {
|
||||
memcpy(new, fr, sizeof(struct ast_iax2_frame));
|
||||
new->f = ast_frdup(fr->f);
|
||||
/* Copy full header */
|
||||
if (ch) {
|
||||
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;
|
||||
}
|
||||
ast_iax2_frame_wrap(new, &fr->af);
|
||||
new->data = NULL;
|
||||
new->datalen = 0;
|
||||
new->direction = DIRECTION_INGRESS;
|
||||
new->retrans = -1;
|
||||
}
|
||||
|
@ -835,7 +840,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc
|
|||
int start;
|
||||
if (new <= NEW_ALLOW) {
|
||||
/* 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]);
|
||||
if (iaxs[x]) {
|
||||
/* Look for an exact match */
|
||||
|
@ -918,25 +923,23 @@ static int __do_deliver(void *data)
|
|||
unsigned int ts;
|
||||
fr->retrans = -1;
|
||||
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
|
||||
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 */
|
||||
fr->f->subclass = AST_IAX2_COMMAND_LAGRP;
|
||||
iax2_send(iaxs[fr->callno], fr->f, fr->ts, -1, 0, 0, 0);
|
||||
} else if (fr->f->subclass == AST_IAX2_COMMAND_LAGRP) {
|
||||
fr->af.subclass = AST_IAX2_COMMAND_LAGRP;
|
||||
iax2_send(iaxs[fr->callno], &fr->af, fr->ts, -1, 0, 0, 0);
|
||||
} else if (fr->af.subclass == AST_IAX2_COMMAND_LAGRP) {
|
||||
/* This is a reply we've been given, actually measure the difference */
|
||||
ts = calc_timestamp(iaxs[fr->callno], 0);
|
||||
iaxs[fr->callno]->lag = ts - fr->ts;
|
||||
}
|
||||
} else {
|
||||
iax2_queue_frame(fr->callno, fr->f);
|
||||
iax2_queue_frame(fr->callno, &fr->af);
|
||||
}
|
||||
}
|
||||
/* Free the packet */
|
||||
ast_frfree(fr->f);
|
||||
/* And our iax frame */
|
||||
/* Free our iax frame */
|
||||
ast_iax2_frame_free(fr);
|
||||
/* And don't run again */
|
||||
return 0;
|
||||
|
@ -1187,7 +1190,7 @@ static int attempt_transmit(void *data)
|
|||
iax2_destroy_nolock(f->callno);
|
||||
} else {
|
||||
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;
|
||||
if (iaxs[f->callno]->owner) {
|
||||
struct ast_frame fr = { 0, };
|
||||
|
@ -1243,9 +1246,8 @@ static int attempt_transmit(void *data)
|
|||
iaxq.tail = f->prev;
|
||||
iaxq.count--;
|
||||
ast_pthread_mutex_unlock(&iaxq.lock);
|
||||
/* Free the frame */
|
||||
ast_frfree(f->f);
|
||||
f->retrans = -1;
|
||||
/* Free the IAX2 frame */
|
||||
ast_iax2_frame_free(f);
|
||||
}
|
||||
return 0;
|
||||
|
@ -1392,7 +1394,7 @@ static int forward_delivery(struct ast_iax2_frame *fr)
|
|||
fr->ts = calc_fakestamp(p1, p2, fr->ts);
|
||||
/* Now just send it send on the 2nd one
|
||||
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
|
||||
|
||||
|
@ -1509,14 +1511,12 @@ static int schedule_delivery(struct ast_iax2_frame *fr, int reallydeliver)
|
|||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Calculated ms is %d\n", ms);
|
||||
/* 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);
|
||||
} else {
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Dropping voice packet since %d ms is, too old\n", ms);
|
||||
/* Free the packet */
|
||||
ast_frfree(fr->f);
|
||||
/* And our iax frame */
|
||||
/* Free our iax frame */
|
||||
ast_iax2_frame_free(fr);
|
||||
}
|
||||
} else {
|
||||
|
@ -2180,7 +2180,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
|
|||
if (now)
|
||||
fr = &fr2;
|
||||
else
|
||||
fr = ast_iax2_frame_new(DIRECTION_OUTGRESS);
|
||||
fr = ast_iax2_frame_new(DIRECTION_OUTGRESS, f->datalen);
|
||||
if (!fr) {
|
||||
ast_log(LOG_WARNING, "Out of memory\n");
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
/* Isolate our frame for transmission */
|
||||
fr->f = ast_frdup(f);
|
||||
/* Copy our prospective frame into our immediate or retransmitted wrapper */
|
||||
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;
|
||||
fr->ts = calc_timestamp(pvt, 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;
|
||||
if (((fr->ts & 0xFFFF0000L) != (lastsent & 0xFFFF0000L))
|
||||
/* High two bits of timestamp differ */ ||
|
||||
(fr->f->frametype != AST_FRAME_VOICE)
|
||||
(fr->af.frametype != AST_FRAME_VOICE)
|
||||
/* or not a voice frame */ ||
|
||||
(fr->f->subclass != pvt->svoiceformat)
|
||||
(fr->af.subclass != pvt->svoiceformat)
|
||||
/* or new voice format */ ) {
|
||||
/* We need a full frame */
|
||||
if (seqno > -1)
|
||||
|
@ -2228,21 +2217,21 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
|
|||
else
|
||||
fr->oseqno = pvt->oseqno++;
|
||||
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->ts = htonl(fr->ts);
|
||||
fh->oseqno = htons(fr->oseqno);
|
||||
fh->iseqno = htons(fr->iseqno);
|
||||
/* Keep track of the last thing we've acknowledged */
|
||||
pvt->aseqno = fr->iseqno;
|
||||
fh->type = fr->f->frametype & 0xFF;
|
||||
fh->csub = compress_subclass(fr->f->subclass);
|
||||
fh->type = fr->af.frametype & 0xFF;
|
||||
fh->csub = compress_subclass(fr->af.subclass);
|
||||
if (transfer) {
|
||||
fr->dcallno = pvt->transfercallno;
|
||||
} else
|
||||
fr->dcallno = pvt->peercallno;
|
||||
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->retries = 0;
|
||||
/* 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) {
|
||||
res = send_packet(fr);
|
||||
ast_frfree(fr->f);
|
||||
} else
|
||||
res = iax2_transmit(fr);
|
||||
} else {
|
||||
|
@ -2267,15 +2255,14 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
|
|||
fr->oseqno = -1;
|
||||
fr->iseqno = -1;
|
||||
/* 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->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->retries = -1;
|
||||
if (now) {
|
||||
res = send_packet(fr);
|
||||
ast_frfree(fr->f);
|
||||
} else
|
||||
res = iax2_transmit(fr);
|
||||
}
|
||||
|
@ -2662,13 +2649,14 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
|
|||
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;
|
||||
fh.scallno = htons(src | AST_FLAG_FULL);
|
||||
fh.dcallno = htons(dst);
|
||||
fh.ts = 0;
|
||||
fh.oseqno = 0;
|
||||
fh.iseqno = 0;
|
||||
fh.type = AST_FRAME_IAX;
|
||||
fh.csub = compress_subclass(AST_IAX2_COMMAND_INVAL);
|
||||
#if 0
|
||||
|
@ -3505,7 +3493,6 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
|
|||
int res;
|
||||
int new = NEW_PREVENT;
|
||||
char buf[4096];
|
||||
char src[80];
|
||||
int len = sizeof(sin);
|
||||
int dcallno = 0;
|
||||
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
|
||||
if (ntohs(mh->callno) & AST_FLAG_FULL) {
|
||||
/* Get the destination call number */
|
||||
dcallno = ntohs(fh->dcallno);
|
||||
dcallno = ntohs(fh->dcallno) & ~AST_FLAG_RETRANS;
|
||||
/* Retrieve the type and subclass */
|
||||
f.frametype = fh->type;
|
||||
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_TXACC))||
|
||||
(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)
|
||||
|
@ -3951,7 +3938,9 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
|
|||
peer->lastms = iaxs[fr.callno]->pingtime;
|
||||
if (peer->pokeexpire > -1)
|
||||
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);
|
||||
peer->callno = 0;
|
||||
/* Try again eventually */
|
||||
if ((peer->lastms < 0) || (peer->lastms > peer->maxms))
|
||||
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
|
||||
delivering the packet. In the very last step, it will be properly
|
||||
handled by do_deliver */
|
||||
snprintf(src, sizeof(src), "LAGRQ-IAX/%s/%d", inet_ntoa(sin.sin_addr),fr.callno);
|
||||
f.src = src;
|
||||
f.src = "LAGRQ";
|
||||
f.mallocd = 0;
|
||||
f.offset = 0;
|
||||
fr.f = &f;
|
||||
f.samples = 0;
|
||||
schedule_delivery(iaxfrdup2(&fr, 0), 1);
|
||||
ast_iax2_frame_wrap(&fr, &f);
|
||||
schedule_delivery(iaxfrdup2(&fr), 1);
|
||||
#ifdef BRIDGE_OPTIMIZATION
|
||||
}
|
||||
#endif
|
||||
|
@ -4229,14 +4217,14 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
|
|||
return 1;
|
||||
}
|
||||
/* 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.offset = 0;
|
||||
fr.f = &f;
|
||||
if (f.datalen && (f.frametype == AST_FRAME_VOICE))
|
||||
f.samples = get_samples(&f);
|
||||
else
|
||||
f.samples = 0;
|
||||
ast_iax2_frame_wrap(&fr, &f);
|
||||
|
||||
/* If this is our most recent packet, use it as our basis for timestamping */
|
||||
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) {
|
||||
forward_delivery(&fr);
|
||||
} else {
|
||||
schedule_delivery(iaxfrdup2(&fr, 0), 1);
|
||||
schedule_delivery(iaxfrdup2(&fr), 1);
|
||||
}
|
||||
#else
|
||||
schedule_delivery(iaxfrdup2(&fr, 0), 1);
|
||||
schedule_delivery(iaxfrdup2(&fr), 1);
|
||||
#endif
|
||||
/* Always run again */
|
||||
ast_pthread_mutex_unlock(&iaxsl[fr.callno]);
|
||||
|
@ -4435,9 +4423,6 @@ static void *network_thread(void *ignore)
|
|||
else
|
||||
iaxq.tail = f->prev;
|
||||
iaxq.count--;
|
||||
/* Free the frame */
|
||||
ast_frfree(f->f);
|
||||
f->f = NULL;
|
||||
/* Free the iax frame */
|
||||
freeme = f;
|
||||
} 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);
|
||||
peer->maxms = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}// else if (strcasecmp(v->name,"type"))
|
||||
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
|
||||
v=v->next;
|
||||
}
|
||||
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")) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -4846,7 +4832,8 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
|
|||
} else {
|
||||
amaflags = format;
|
||||
}
|
||||
}
|
||||
} //else if (strcasecmp(v->name,"type"))
|
||||
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
|
||||
v = v->next;
|
||||
}
|
||||
iax2_capability = capability;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <sys/signal.h>
|
||||
#include <asterisk/dsp.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define MGCPDUMPER
|
||||
#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 */
|
||||
static int capability = AST_FORMAT_ULAW;
|
||||
static int nonCodecCapability = AST_RTP_DTMF;
|
||||
|
||||
static char ourhost[256];
|
||||
static struct in_addr __ourip;
|
||||
|
@ -133,6 +135,7 @@ struct mgcp_endpoint {
|
|||
int alreadygone;
|
||||
int needdestroy;
|
||||
int capability;
|
||||
int nonCodecCapability;
|
||||
int outgoing;
|
||||
struct ast_dsp *vad;
|
||||
struct ast_channel *owner;
|
||||
|
@ -568,21 +571,41 @@ static struct ast_channel *mgcp_new(struct mgcp_endpoint *i, int state)
|
|||
return tmp;
|
||||
}
|
||||
|
||||
static char *get_sdp(struct mgcp_request *req, char *name)
|
||||
{
|
||||
int x;
|
||||
int len = strlen(name);
|
||||
char *r;
|
||||
for (x=0;x<req->lines;x++) {
|
||||
if (!strncasecmp(req->line[x], name, len) &&
|
||||
(req->line[x][len] == '=')) {
|
||||
r = req->line[x] + len + 1;
|
||||
while(*r && (*r < 33))
|
||||
r++;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
static char* get_sdp_by_line(char* line, char *name, int nameLen) {
|
||||
if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
|
||||
char* r = line + nameLen + 1;
|
||||
while (*r && (*r < 33)) ++r;
|
||||
return r;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static char *get_sdp(struct mgcp_request *req, char *name) {
|
||||
int x;
|
||||
int len = strlen(name);
|
||||
char *r;
|
||||
|
||||
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)
|
||||
|
@ -803,14 +826,17 @@ static int process_sdp(struct mgcp_endpoint *p, struct mgcp_request *req)
|
|||
{
|
||||
char *m;
|
||||
char *c;
|
||||
char *a;
|
||||
char host[258];
|
||||
int len;
|
||||
int portno;
|
||||
int peercapability;
|
||||
int peercapability, peerNonCodecCapability;
|
||||
struct sockaddr_in sin;
|
||||
char *codecs;
|
||||
struct hostent *hp;
|
||||
int codec;
|
||||
int iterator;
|
||||
|
||||
/* Get codec and RTP info from SDP */
|
||||
m = get_sdp(req, "m");
|
||||
c = get_sdp(req, "c");
|
||||
|
@ -840,25 +866,46 @@ static int process_sdp(struct mgcp_endpoint *p, struct mgcp_request *req)
|
|||
#if 0
|
||||
printf("Peer RTP is at port %s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
||||
#endif
|
||||
peercapability = 0;
|
||||
// Scan through the RTP payload types specified in a "m=" line:
|
||||
rtp_pt_init(p->rtp);
|
||||
codecs = m + len;
|
||||
while(strlen(codecs)) {
|
||||
if (sscanf(codecs, "%d %n", &codec, &len) != 1) {
|
||||
ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
|
||||
return -1;
|
||||
}
|
||||
#if 0
|
||||
printf("Codec: %d\n", codec);
|
||||
#endif
|
||||
codec = rtp2ast(codec);
|
||||
if (codec > -1)
|
||||
peercapability |= codec;
|
||||
rtp_set_m_type(p->rtp, codec);
|
||||
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;
|
||||
if (mgcpdebug)
|
||||
if (mgcpdebug) {
|
||||
ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n",
|
||||
capability, peercapability, p->capability);
|
||||
ast_verbose("Non-codec capabilities: us - %d, them - %d, combined - %d\n",
|
||||
nonCodecCapability, peerNonCodecCapability,
|
||||
p->nonCodecCapability);
|
||||
}
|
||||
if (!p->capability) {
|
||||
ast_log(LOG_WARNING, "No compatible codecs!\n");
|
||||
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(t, sizeof(t), "t=0 0\r\n");
|
||||
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 (mgcpdebug)
|
||||
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, ast2rtpn(x));
|
||||
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 (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");
|
||||
len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
|
||||
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");
|
||||
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1079,7 +1146,7 @@ static int transmit_connect_with_sdp(struct mgcp_endpoint *p, struct ast_rtp *rt
|
|||
snprintf(local, sizeof(local), "p:20");
|
||||
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,8 +95,9 @@ static pthread_t monitor_thread = 0;
|
|||
|
||||
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 nonCodecCapability = AST_RTP_DTMF;
|
||||
|
||||
static char ourhost[256];
|
||||
static struct in_addr __ourip;
|
||||
|
@ -106,6 +107,8 @@ static int sipdebug = 0;
|
|||
|
||||
static int tos = 0;
|
||||
|
||||
static int globaldtmfmode = SIP_DTMF_RFC2833;
|
||||
|
||||
/* Expire slowly */
|
||||
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 needdestroy; /* if we need to be destroyed */
|
||||
int capability; /* Special capability */
|
||||
int nonCodecCapability;
|
||||
int outgoing; /* Outgoing or incoming call? */
|
||||
int insecure; /* Don't check source port/ip */
|
||||
int expirey; /* How long we take to expire */
|
||||
|
@ -226,6 +230,7 @@ struct sip_peer {
|
|||
int expire;
|
||||
int expirey;
|
||||
int capability;
|
||||
int nonCodecCapability;
|
||||
int insecure;
|
||||
int nat;
|
||||
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_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_info_with_digit(struct sip_pvt *p, char digit);
|
||||
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);
|
||||
|
||||
|
@ -388,6 +394,7 @@ static int create_addr(struct sip_pvt *r, char *peer)
|
|||
if (!strcasecmp(p->name, peer)) {
|
||||
found++;
|
||||
r->capability = p->capability;
|
||||
r->nonCodecCapability = p->nonCodecCapability;
|
||||
r->nat = p->nat;
|
||||
if (r->rtp) {
|
||||
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->canreinvite = p->canreinvite;
|
||||
r->maxtime = p->maxms;
|
||||
r->dtmfmode = p->dtmfmode;
|
||||
if (p->dtmfmode)
|
||||
r->dtmfmode = p->dtmfmode;
|
||||
strncpy(r->context, p->context,sizeof(r->context)-1);
|
||||
if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
|
||||
(!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);
|
||||
} else {
|
||||
/* Send a hangup */
|
||||
transmit_request(p, "BYE", p->outgoing);
|
||||
transmit_request(p, "BYE", 1);
|
||||
}
|
||||
}
|
||||
#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)
|
||||
{
|
||||
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)) {
|
||||
ast_rtp_senddigit(p->rtp, digit);
|
||||
}
|
||||
|
@ -1018,21 +1029,41 @@ static struct cfalias {
|
|||
{ "Via", "v" },
|
||||
};
|
||||
|
||||
static char *get_sdp(struct sip_request *req, char *name)
|
||||
{
|
||||
int x;
|
||||
int len = strlen(name);
|
||||
char *r;
|
||||
for (x=0;x<req->lines;x++) {
|
||||
if (!strncasecmp(req->line[x], name, len) &&
|
||||
(req->line[x][len] == '=')) {
|
||||
r = req->line[x] + len + 1;
|
||||
while(*r && (*r < 33))
|
||||
r++;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
static char* get_sdp_by_line(char* line, char *name, int nameLen) {
|
||||
if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
|
||||
char* r = line + nameLen + 1;
|
||||
while (*r && (*r < 33)) ++r;
|
||||
return r;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static char *get_sdp(struct sip_request *req, char *name) {
|
||||
int x;
|
||||
int len = strlen(name);
|
||||
char *r;
|
||||
|
||||
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)
|
||||
|
@ -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);
|
||||
/* Assume reinvite OK */
|
||||
p->canreinvite = 1;
|
||||
p->dtmfmode = SIP_DTMF_RFC2833;
|
||||
p->dtmfmode = globaldtmfmode;
|
||||
/* Add to list */
|
||||
ast_pthread_mutex_lock(&iflock);
|
||||
p->next = iflist;
|
||||
|
@ -1346,14 +1377,17 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
|
|||
{
|
||||
char *m;
|
||||
char *c;
|
||||
char *a;
|
||||
char host[258];
|
||||
int len = -1;
|
||||
int portno;
|
||||
int peercapability;
|
||||
int peercapability, peerNonCodecCapability;
|
||||
struct sockaddr_in sin;
|
||||
char *codecs;
|
||||
struct hostent *hp;
|
||||
int codec;
|
||||
int iterator;
|
||||
|
||||
/* Get codec and RTP info from 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"));
|
||||
|
@ -1387,25 +1421,47 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
|
|||
#if 0
|
||||
printf("Peer RTP is at port %s:%d\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
||||
#endif
|
||||
peercapability = 0;
|
||||
// Scan through the RTP payload types specified in a "m=" line:
|
||||
rtp_pt_init(p->rtp);
|
||||
codecs = m + len;
|
||||
while(strlen(codecs)) {
|
||||
if (sscanf(codecs, "%d %n", &codec, &len) != 1) {
|
||||
ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
|
||||
return -1;
|
||||
}
|
||||
#if 0
|
||||
printf("Codec: %d\n", codec);
|
||||
#endif
|
||||
codec = rtp2ast(codec);
|
||||
if (codec > -1)
|
||||
peercapability |= codec;
|
||||
rtp_set_m_type(p->rtp, codec);
|
||||
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;
|
||||
if (sipdebug)
|
||||
p->nonCodecCapability = nonCodecCapability & peerNonCodecCapability;
|
||||
if (sipdebug) {
|
||||
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) {
|
||||
ast_log(LOG_WARNING, "No compatible codecs!\n");
|
||||
return -1;
|
||||
|
@ -1540,7 +1596,7 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, struct s
|
|||
for (;;) {
|
||||
tmp = __get_header(orig, field, &start);
|
||||
if (strlen(tmp)) {
|
||||
if (!copied) {
|
||||
if (!copied && p->nat) {
|
||||
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));
|
||||
else
|
||||
|
@ -1746,6 +1802,20 @@ static int add_text(struct sip_request *req, char *text)
|
|||
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)
|
||||
{
|
||||
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 (sipdebug)
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
alreadysent |= cur->codec;
|
||||
cur = cur->next;
|
||||
}
|
||||
/* Now send anything else in no particular order */
|
||||
for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
|
||||
/* Now send any other common codecs, and non-codec formats: */
|
||||
for (x = 1; x <= AST_FORMAT_MAX_AUDIO; x <<= 1) {
|
||||
if ((p->capability & x) && !(alreadysent & x)) {
|
||||
if (sipdebug)
|
||||
ast_verbose("Answering with capability %d\n", x);
|
||||
if ((codec = ast2rtp(x)) > -1) {
|
||||
snprintf(costr, sizeof(costr), " %d", codec);
|
||||
ast_verbose("Answering with capability %d\n", x);
|
||||
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, ast2rtpn(x));
|
||||
snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, rtp_lookup_mime_subtype(1, x));
|
||||
strcat(a, costr);
|
||||
}
|
||||
}
|
||||
}
|
||||
strcat(m, " 101\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");
|
||||
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);
|
||||
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");
|
||||
len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
|
||||
snprintf(costr, sizeof(costr), "%d", len);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
p->canreinvite = user->canreinvite;
|
||||
p->amaflags = user->amaflags;
|
||||
p->dtmfmode = user->dtmfmode;
|
||||
if (user->dtmfmode)
|
||||
p->dtmfmode = user->dtmfmode;
|
||||
}
|
||||
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[])
|
||||
{
|
||||
struct sip_pvt *cur;
|
||||
char tmp[256];
|
||||
if (argc != 4)
|
||||
return RESULT_SHOWUSAGE;
|
||||
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, "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");
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
char digest[256];
|
||||
memset(digest,0,sizeof(digest));
|
||||
reply_digest(p,req, "WWW-Authenticate", "REGISTER", (char *)&digest, sizeof(digest) );
|
||||
return transmit_register(p->registry,"REGISTER",(char *)&digest);
|
||||
reply_digest(p,req, "WWW-Authenticate", "REGISTER", digest, sizeof(digest) );
|
||||
return transmit_register(p->registry,"REGISTER",digest);
|
||||
}
|
||||
|
||||
static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req) {
|
||||
char digest[256];
|
||||
memset(digest,0,sizeof(digest));
|
||||
reply_digest(p,req, "Proxy-Authenticate", "INVITE", (char *)&digest, sizeof(digest) );
|
||||
return transmit_invite(p,"INVITE",1,(char *)&digest, NULL);
|
||||
reply_digest(p,req, "Proxy-Authenticate", "INVITE", digest, sizeof(digest) );
|
||||
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) {
|
||||
|
@ -3083,7 +3189,6 @@ retrylock:
|
|||
/* char *exp; */
|
||||
int expires;
|
||||
struct sip_registry *r;
|
||||
transmit_request(p, "ACK", 0);
|
||||
r=p->registry;
|
||||
r->regstate=REG_STATE_REGISTERED;
|
||||
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;
|
||||
/* JK02: set default context */
|
||||
strcpy(user->context, context);
|
||||
user->dtmfmode = SIP_DTMF_RFC2833;
|
||||
while(v) {
|
||||
if (!strcasecmp(v->name, "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")) {
|
||||
user->insecure = ast_true(v->value);
|
||||
}
|
||||
} //else if (strcasecmp(v->name,"type"))
|
||||
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
|
||||
v = v->next;
|
||||
}
|
||||
}
|
||||
|
@ -3924,7 +4029,7 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
|
|||
peer->capability = capability;
|
||||
/* Assume can reinvite */
|
||||
peer->canreinvite = 1;
|
||||
peer->dtmfmode = SIP_DTMF_RFC2833;
|
||||
peer->dtmfmode = 0;
|
||||
while(v) {
|
||||
if (!strcasecmp(v->name, "secret"))
|
||||
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);
|
||||
peer->maxms = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} //else if (strcasecmp(v->name,"type"))
|
||||
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
|
||||
v=v->next;
|
||||
}
|
||||
if (!strlen(peer->methods))
|
||||
|
@ -4039,6 +4144,8 @@ static int reload_config(void)
|
|||
struct hostent *hp;
|
||||
int format;
|
||||
int oldport = ntohs(bindaddr.sin_port);
|
||||
|
||||
globaldtmfmode = SIP_DTMF_RFC2833;
|
||||
|
||||
if (gethostname(ourhost, sizeof(ourhost))) {
|
||||
ast_log(LOG_WARNING, "Unable to get hostname, SIP disabled\n");
|
||||
|
@ -4065,6 +4172,17 @@ static int reload_config(void)
|
|||
/* Create the interface list */
|
||||
if (!strcasecmp(v->name, "context")) {
|
||||
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")) {
|
||||
strncpy(language, v->value, sizeof(language)-1);
|
||||
} else if (!strcasecmp(v->name, "nat")) {
|
||||
|
@ -4122,9 +4240,9 @@ static int reload_config(void)
|
|||
} else {
|
||||
ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
|
||||
}
|
||||
} else
|
||||
ast_log(LOG_NOTICE, "Ignoring unknown SIP general keyword '%s'\n", v->name);
|
||||
v = v->next;
|
||||
} //else if (strcasecmp(v->name,"type"))
|
||||
// ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
|
||||
v = v->next;
|
||||
}
|
||||
|
||||
cat = ast_category_browse(cfg, NULL);
|
||||
|
@ -4181,6 +4299,12 @@ static int reload_config(void)
|
|||
if (sipsock < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to create SIP socket: %s\n", strerror(errno));
|
||||
} 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) {
|
||||
ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
|
||||
inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
|
||||
|
|
|
@ -6285,7 +6285,7 @@ int load_module()
|
|||
strncpy(idledial, v->value, sizeof(idledial) - 1);
|
||||
#endif
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Ignoring %s\n", v->name);
|
||||
ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
|
||||
v = v->next;
|
||||
}
|
||||
ast_pthread_mutex_unlock(&iflock);
|
||||
|
@ -6638,7 +6638,7 @@ static int reload_zt(void)
|
|||
strncpy(idledial, v->value, sizeof(idledial) - 1);
|
||||
#endif
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Ignoring %s\n", v->name);
|
||||
ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
|
||||
v = v->next;
|
||||
}
|
||||
|
||||
|
|
63
cli.c
63
cli.c
|
@ -217,6 +217,14 @@ static char showchan_help[] =
|
|||
"Usage: show channel <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[] =
|
||||
"Usage: _command complete \"<line>\" text state\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;
|
||||
}
|
||||
|
||||
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[])
|
||||
{
|
||||
struct ast_channel *c=NULL;
|
||||
|
@ -343,8 +395,8 @@ static int handle_showchan(int fd, int argc, char *argv[])
|
|||
" WriteFormat: %d\n"
|
||||
" ReadFormat: %d\n"
|
||||
"1st File Descriptor: %d\n"
|
||||
" Frames in: %d\n"
|
||||
" Frames out: %d\n"
|
||||
" Frames in: %d%s\n"
|
||||
" Frames out: %d%s\n"
|
||||
" Time to Hangup: %d\n"
|
||||
" -- PBX --\n"
|
||||
" Context: %s\n"
|
||||
|
@ -357,7 +409,8 @@ static int handle_showchan(int fd, int argc, char *argv[])
|
|||
c->name, c->type,
|
||||
(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->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-> data ? (strlen(c->data) ? c->data : "(Empty)") : "(None)"),
|
||||
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[] = {
|
||||
/* 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", "nummatches", NULL }, handle_commandnummatches, "Returns number of command matches", commandnummatches_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 },
|
||||
{ { "no", "debug", "channel", NULL }, handle_nodebugchan, "Disable debugging on a channel", nodebugchan_help, complete_ch },
|
||||
{ { "reload", NULL }, handle_reload, "Reload configuration", reload_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 },
|
||||
|
|
|
@ -21,7 +21,8 @@ writeprotect=no
|
|||
|
||||
;
|
||||
; 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]
|
||||
CONSOLE=Console/dsp ; Console interface for demo
|
||||
|
|
156
frame.c
156
frame.c
|
@ -16,6 +16,7 @@
|
|||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/cli.h>
|
||||
#include <asterisk/term.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
@ -346,6 +347,161 @@ int ast_getformatbyname(char *name)
|
|||
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
|
||||
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 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)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,14 @@
|
|||
extern "C" {
|
||||
#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 *(*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 */
|
||||
|
@ -61,14 +69,24 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit);
|
|||
|
||||
int ast_rtp_settos(struct ast_rtp *rtp, int tos);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
void rtp_get_current_formats(struct ast_rtp* rtp,
|
||||
int* astFormats, int* nonAstFormats);
|
||||
|
||||
// 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 ast2rtp(int id);
|
||||
|
||||
int rtp2ast(int id);
|
||||
|
||||
char *ast2rtpn(int id);
|
||||
|
||||
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_proto_register(struct ast_rtp_protocol *proto);
|
||||
|
|
|
@ -772,6 +772,6 @@ int init_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();
|
||||
}
|
||||
|
|
29
pbx.c
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);
|
||||
}
|
||||
}
|
||||
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->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 */
|
||||
if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
|
||||
/* JK02: If not successfull fall back to 's' */
|
||||
|
|
274
rtp.c
274
rtp.c
|
@ -39,6 +39,14 @@
|
|||
|
||||
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 {
|
||||
int s;
|
||||
char resp;
|
||||
|
@ -62,6 +70,11 @@ struct ast_rtp {
|
|||
struct io_context *io;
|
||||
void *data;
|
||||
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;
|
||||
|
@ -204,41 +217,6 @@ static struct ast_frame *process_rfc3389(struct ast_rtp *rtp, unsigned char *dat
|
|||
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)
|
||||
{
|
||||
struct ast_rtp *rtp = cbdata;
|
||||
|
@ -262,6 +240,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
|||
unsigned int timestamp;
|
||||
unsigned int *rtpheader;
|
||||
static struct ast_frame *f, null_frame = { AST_FRAME_NULL, };
|
||||
struct rtpPayloadType rtpPT;
|
||||
|
||||
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);
|
||||
#endif
|
||||
rtp->f.frametype = AST_FRAME_VOICE;
|
||||
rtp->f.subclass = rtp2ast(payloadtype);
|
||||
if (rtp->f.subclass < 0) {
|
||||
f = NULL;
|
||||
if (payloadtype == 101) {
|
||||
/* It's special -- rfc2833 process it */
|
||||
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
} else if (payloadtype == 121) {
|
||||
/* CISCO proprietary DTMF bridge */
|
||||
f = process_type121(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
} else if (payloadtype == 100) {
|
||||
/* CISCO's notso proprietary DTMF bridge */
|
||||
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
} else if (payloadtype == 13) {
|
||||
f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype);
|
||||
}
|
||||
if (f)
|
||||
return f;
|
||||
else
|
||||
return &null_frame;
|
||||
} else
|
||||
rtp->lastrxformat = rtp->f.subclass;
|
||||
rtpPT = rtp_lookup_pt(rtp, payloadtype);
|
||||
if (!rtpPT.isAstFormat) {
|
||||
// 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 */
|
||||
f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
if (f) return f; else return &null_frame;
|
||||
} else if (rtpPT.code == AST_RTP_CN) {
|
||||
/* Comfort Noise */
|
||||
f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
|
||||
if (f) return f; else return &null_frame;
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype);
|
||||
return &null_frame;
|
||||
}
|
||||
}
|
||||
rtp->f.subclass = rtpPT.code;
|
||||
rtp->lastrxformat = rtp->f.subclass;
|
||||
|
||||
if (!rtp->lastrxts)
|
||||
rtp->lastrxts = timestamp;
|
||||
|
@ -367,6 +341,10 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
|||
case AST_FORMAT_G723_1:
|
||||
rtp->f.samples = g723_samples(rtp->f.data, rtp->f.datalen);
|
||||
break;
|
||||
case AST_FORMAT_SPEEX:
|
||||
rtp->f.samples = 160;
|
||||
// assumes that the RTP packet contained one Speex frame
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_NOTICE, "Unable to calculate samples for format %d\n", rtp->f.subclass);
|
||||
break;
|
||||
|
@ -375,48 +353,151 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
|||
return &rtp->f;
|
||||
}
|
||||
|
||||
// The following array defines the MIME type (and subtype) for each
|
||||
// of our codecs, or RTP-specific data type.
|
||||
static struct {
|
||||
int rtp;
|
||||
int ast;
|
||||
char *label;
|
||||
} cmap[] = {
|
||||
{ 0, AST_FORMAT_ULAW, "PCMU" },
|
||||
{ 3, AST_FORMAT_GSM, "GSM" },
|
||||
{ 4, AST_FORMAT_G723_1, "G723" },
|
||||
{ 5, AST_FORMAT_ADPCM, "ADPCM" },
|
||||
{ 8, AST_FORMAT_ALAW, "PCMA" },
|
||||
{ 18, AST_FORMAT_G729A, "G729" },
|
||||
struct rtpPayloadType payloadType;
|
||||
char* type;
|
||||
char* subtype;
|
||||
} mimeTypes[] = {
|
||||
{{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_MP3}, "audio", "MPA"},
|
||||
{{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)
|
||||
{
|
||||
int x;
|
||||
for (x=0;x<sizeof(cmap) / sizeof(cmap[0]); x++) {
|
||||
if (cmap[x].rtp == id)
|
||||
return cmap[x].ast;
|
||||
}
|
||||
return -1;
|
||||
// Static (i.e., well-known) RTP payload types for our "AST_FORMAT..."s:
|
||||
static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
|
||||
[0] = {1, AST_FORMAT_ULAW},
|
||||
[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},
|
||||
[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)
|
||||
{
|
||||
int x;
|
||||
for (x=0;x<sizeof(cmap) / sizeof(cmap[0]); x++) {
|
||||
if (cmap[x].ast == id)
|
||||
return cmap[x].rtp;
|
||||
}
|
||||
return -1;
|
||||
// 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
|
||||
// still be set to a different value by a subsequent "a=rtpmap:" line):
|
||||
void 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];
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
int x;
|
||||
for (x=0;x<sizeof(cmap) / sizeof(cmap[0]); x++) {
|
||||
if (cmap[x].ast == id)
|
||||
return cmap[x].label;
|
||||
}
|
||||
return "";
|
||||
struct rtpPayloadType rtp_lookup_pt(struct ast_rtp* rtp, int pt) {
|
||||
if (pt < 0 || pt > MAX_RTP_PT) {
|
||||
struct rtpPayloadType result;
|
||||
result.isAstFormat = result.code = 0;
|
||||
return result; // bogus payload type
|
||||
}
|
||||
return rtp->current_RTP_PT[pt];
|
||||
}
|
||||
|
||||
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 *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:
|
||||
pred = rtp->lastts + g723_samples(f->data, f->datalen);
|
||||
break;
|
||||
case AST_FORMAT_SPEEX:
|
||||
pred = rtp->lastts + 160;
|
||||
// assumes that the RTP packet contains one Speex frame
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_WARNING, "Not sure about timestamp format for codec format %d\n", f->subclass);
|
||||
}
|
||||
|
@ -648,7 +733,7 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
|
|||
return -1;
|
||||
}
|
||||
|
||||
codec = ast2rtp(_f->subclass);
|
||||
codec = rtp_lookup_code(rtp, 1, _f->subclass);
|
||||
if (codec < 0) {
|
||||
ast_log(LOG_WARNING, "Don't know how to send format %d packets with RTP\n", _f->subclass);
|
||||
return -1;
|
||||
|
@ -706,6 +791,9 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
|
|||
break;
|
||||
default:
|
||||
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) {
|
||||
f = ast_frdup(_f);
|
||||
} else {
|
||||
|
|
Reference in New Issue