From f61680257a63d31f0abcf41b5c29f4670552af2f Mon Sep 17 00:00:00 2001 From: matteo Date: Wed, 12 Mar 2003 06:00:18 +0000 Subject: [PATCH] Wed Mar 12 07:00:01 CET 2003 git-svn-id: http://svn.digium.com/svn/asterisk/trunk@641 f38db490-d61c-443f-a65b-d21fe96a405b --- CHANGES | 1 + CREDITS | 2 + apps/app_dial.c | 4 + apps/app_macro.c | 19 ++- channel.c | 16 +- channels/chan_iax.c | 11 +- channels/chan_iax2.c | 153 +++++++++--------- channels/chan_mgcp.c | 125 +++++++++++---- channels/chan_sip.c | 236 +++++++++++++++++++++------- channels/chan_zap.c | 4 +- cli.c | 63 +++++++- configs/extensions.conf.sample | 3 +- frame.c | 156 +++++++++++++++++++ include/asterisk/frame.h | 2 + include/asterisk/rtp.h | 30 +++- manager.c | 2 +- pbx.c | 29 +--- rtp.c | 274 ++++++++++++++++++++++----------- 18 files changed, 820 insertions(+), 310 deletions(-) diff --git a/CHANGES b/CHANGES index 4ddbb1199..3fc4dcc4f 100755 --- a/CHANGES +++ b/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 diff --git a/CREDITS b/CREDITS index 3cdbd607f..1339267ba 100755 --- a/CREDITS +++ b/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 diff --git a/apps/app_dial.c b/apps/app_dial.c index 8743e0baa..ac9953bc3 100755 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -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) { diff --git a/apps/app_macro.c b/apps/app_macro.c index c06fa117f..0b4a11fc4 100755 --- a/apps/app_macro.c +++ b/apps/app_macro.c @@ -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; + } } } } diff --git a/channel.c b/channel.c index 6a32fd3fd..9a4d2de1e 100755 --- a/channel.c +++ b/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; } diff --git a/channels/chan_iax.c b/channels/chan_iax.c index 0c3b905b5..3cf6813dd 100755 --- a/channels/chan_iax.c +++ b/channels/chan_iax.c @@ -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; diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index ada9fea1a..7ddcf01d2 100755 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -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) && (xretrans = -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; diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index b81a670db..e2a779577 100755 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -40,6 +40,7 @@ #include #include #include +#include #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;xlines;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; xlines; 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); } } diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 15e1e0f76..d665d64e5 100755 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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;xlines;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; xlines; 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), diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 560755069..91a1ac533 100755 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -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; } diff --git a/cli.c b/cli.c index aaed2d305..b9cb021d1 100755 --- a/cli.c +++ b/cli.c @@ -217,6 +217,14 @@ static char showchan_help[] = "Usage: show channel \n" " Shows lots of information about the specified channel.\n"; +static char debugchan_help[] = +"Usage: debug channel \n" +" Enables debugging on a specific channel.\n"; + +static char nodebugchan_help[] = +"Usage: no debug channel \n" +" Disables debugging on a specific channel.\n"; + static char commandcomplete_help[] = "Usage: _command complete \"\" 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 }, diff --git a/configs/extensions.conf.sample b/configs/extensions.conf.sample index 76e024fff..0499a3351 100755 --- a/configs/extensions.conf.sample +++ b/configs/extensions.conf.sample @@ -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 diff --git a/frame.c b/frame.c index fb255d83b..34ec99502 100755 --- a/frame.c +++ b/frame.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -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[]) { diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 1916a714b..e971a6d03 100755 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -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 diff --git a/include/asterisk/rtp.h b/include/asterisk/rtp.h index d9530a7db..7a00d27c4 100755 --- a/include/asterisk/rtp.h +++ b/include/asterisk/rtp.h @@ -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); diff --git a/manager.c b/manager.c index 528828683..be1bb28fb 100755 --- a/manager.c +++ b/manager.c @@ -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(); } diff --git a/pbx.c b/pbx.c index a78a09d5d..63f251ed2 100755 --- a/pbx.c +++ b/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' */ diff --git a/rtp.c b/rtp.c index fb3ea671f..b7078a5bd 100755 --- a/rtp.c +++ b/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;xcurrent_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 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 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 {