From ecc015889cfa204942e23bb118e28c78012b8884 Mon Sep 17 00:00:00 2001 From: Jeremy McNamara Date: Tue, 23 Dec 2003 23:01:24 +0000 Subject: [PATCH] Apply massive patch from PCadach. If things are broken blame him. Bug#469 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1877 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_h323.c | 414 +++++++++++++++++++++++----- channels/h323/ast_h323.cpp | 489 ++++++++++++++++++++++++++------- channels/h323/ast_h323.h | 67 ++++- channels/h323/chan_h323.h | 80 ++++-- channels/h323/h323.conf.sample | 7 + 5 files changed, 849 insertions(+), 208 deletions(-) diff --git a/channels/chan_h323.c b/channels/chan_h323.c index 15e4b5b228..34fcb0ee58 100755 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,19 @@ #include "h323/chan_h323.h" +#define TRUE 1 +#define FALSE 0 + +/* from rtp.c to translate RTP's payload type to Asterisk's frame subcode */ +struct rtpPayloadType { + int isAstFormat; // whether the following code is an AST_FORMAT + int code; +}; + +call_options_t global_options; + +static struct sockaddr_in bindaddr; + /** String variables required by ASTERISK */ static char *type = "H323"; static char *desc = "The NuFone Network's Open H.323 Channel Driver"; @@ -106,6 +120,8 @@ struct oh323_pvt { int bridge; /* Determine of we should native bridge or not*/ char exten[AST_MAX_EXTENSION]; /* Requested extension */ char context[AST_MAX_EXTENSION]; /* Context where to start */ + char dnid[AST_MAX_EXTENSION]; /* Called number */ + char rdnis[AST_MAX_EXTENSION]; /* Redirecting number */ char username[81]; /* H.323 alias using this channel */ char accountcode[256]; /* Account code */ int amaflags; /* AMA Flags */ @@ -245,17 +261,37 @@ static struct oh323_user *build_user(char *name, struct ast_variable *v) } else if (!strcasecmp(v->name, "nat")) { user->nat = ast_true(v->value); } else if (!strcasecmp(v->name, "noFastStart")) { - user->noFastStart = ast_true(v->value); + user->call_options.noFastStart = ast_true(v->value); } else if (!strcasecmp(v->name, "noH245Tunneling")) { - user->noH245Tunneling = ast_true(v->value); + user->call_options.noH245Tunnelling = ast_true(v->value); } else if (!strcasecmp(v->name, "noSilenceSuppression")) { - user->noSilenceSuppression = ast_true(v->value); + user->call_options.noSilenceSuppression = ast_true(v->value); } else if (!strcasecmp(v->name, "secret")) { strncpy(user->secret, v->value, sizeof(user->secret)-1); } else if (!strcasecmp(v->name, "callerid")) { strncpy(user->callerid, v->value, sizeof(user->callerid)-1); } else if (!strcasecmp(v->name, "accountcode")) { strncpy(user->accountcode, v->value, sizeof(user->accountcode)-1); + } else if (!strcasecmp(v->name, "progress_setup")) { + int progress_setup = atoi(v->value); + if((progress_setup != 0) && + (progress_setup != 1) && + (progress_setup != 3) && + (progress_setup != 8)) { + ast_log(LOG_WARNING, "Invalid value %d for progress_setup at line %d, assuming 0\n", progress_setup, v->lineno); + progress_setup = 0; + } + user->call_options.progress_setup = progress_setup; + } else if (!strcasecmp(v->name, "progress_alert")) { + int progress_alert = atoi(v->value); + if((progress_alert != 0) && + (progress_alert != 8)) { + ast_log(LOG_WARNING, "Invalid value %d for progress_alert at line %d, assuming 0\n", progress_alert, v->lineno); + progress_alert = 0; + } + user->call_options.progress_alert = progress_alert; + } else if (!strcasecmp(v->name, "progress_audio")) { + user->call_options.progress_audio = ast_true(v->value); } else if (!strcasecmp(v->name, "incominglimit")) { user->incominglimit = atoi(v->value); if (user->incominglimit < 0) @@ -332,11 +368,31 @@ static struct oh323_peer *build_peer(char *name, struct ast_variable *v) } else if (!strcasecmp(v->name, "bridge")) { peer->bridge = ast_true(v->value); } else if (!strcasecmp(v->name, "noFastStart")) { - peer->noFastStart = ast_true(v->value); + peer->call_options.noFastStart = ast_true(v->value); } else if (!strcasecmp(v->name, "noH245Tunneling")) { - peer->noH245Tunneling = ast_true(v->value); + peer->call_options.noH245Tunnelling = ast_true(v->value); } else if (!strcasecmp(v->name, "noSilenceSuppression")) { - peer->noSilenceSuppression = ast_true(v->value); + peer->call_options.noSilenceSuppression = ast_true(v->value); + } else if (!strcasecmp(v->name, "progress_setup")) { + int progress_setup = atoi(v->value); + if((progress_setup != 0) && + (progress_setup != 1) && + (progress_setup != 3) && + (progress_setup != 8)) { + ast_log(LOG_WARNING, "Invalid value %d for progress_setup at line %d, assuming 0\n", progress_setup, v->lineno); + progress_setup = 0; + } + peer->call_options.progress_setup = progress_setup; + } else if (!strcasecmp(v->name, "progress_alert")) { + int progress_alert = atoi(v->value); + if((progress_alert != 0) && + (progress_alert != 8)) { + ast_log(LOG_WARNING, "Invalid value %d for progress_alert at line %d, assuming 0\n", progress_alert, v->lineno); + progress_alert = 0; + } + peer->call_options.progress_alert = progress_alert; + } else if (!strcasecmp(v->name, "progress_audio")) { + peer->call_options.progress_audio = ast_true(v->value); } else if (!strcasecmp(v->name, "outgoinglimit")) { peer->outgoinglimit = atoi(v->value); if (peer->outgoinglimit > 0) @@ -427,16 +483,16 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout) } else { p->calloptions.callerid = strdup(c->callerid); } - } + } - res = h323_make_call(called_addr, &(p->cd), p->calloptions); + res = h323_make_call(called_addr, &(p->cd), &p->calloptions); if (res) { ast_log(LOG_NOTICE, "h323_make_call failed(%s)\n", c->name); return -1; } - ast_setstate(c, AST_STATE_RINGING); + ast_setstate(c, AST_STATE_RING); return 0; } @@ -504,20 +560,31 @@ static int oh323_hangup(struct ast_channel *c) return 0; } -static struct ast_frame *oh323_rtp_read(struct oh323_pvt *p) +/* Pass channel struct too to allow RTCP handling */ +static struct ast_frame *oh323_rtp_read(struct ast_channel *c, struct oh323_pvt *p) { /* Retrieve audio/etc from channel. Assumes p->lock is already held. */ struct ast_frame *f; static struct ast_frame null_frame = { AST_FRAME_NULL, }; - /* Only apply it for the first packet, we just need the correct ip/port */ - if(p->nat) - { - ast_rtp_setnat(p->rtp,p->nat); - p->nat = 0; - } + /* Only apply it for the first packet, we just need the correct ip/port */ + if(p->nat) + { + ast_rtp_setnat(p->rtp,p->nat); + p->nat = 0; + } + + switch(c->fdno) { + case 0: /* RTP stream */ + f = ast_rtp_read(p->rtp); + break; + case 1: /* RTCP stream */ + f = ast_rtcp_read(p->rtp); + break; + default: + f = &null_frame; + } - f = ast_rtp_read(p->rtp); /* Don't send RFC2833 if we're not supposed to */ if (f && (f->frametype == AST_FRAME_DTMF) && !(p->dtmfmode & H323_DTMF_RFC2833)) return &null_frame; @@ -525,10 +592,12 @@ static struct ast_frame *oh323_rtp_read(struct oh323_pvt *p) /* We already hold the channel lock */ if (f->frametype == AST_FRAME_VOICE) { if (f->subclass != p->owner->nativeformats) { + /* Must be handled on opening logical channel */ ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass); p->owner->nativeformats = f->subclass; ast_set_read_format(p->owner, p->owner->readformat); - ast_set_write_format(p->owner, p->owner->writeformat); + /* Don't set write format because it will be set up when channel started */ +// ast_set_write_format(p->owner, p->owner->writeformat); } /* Do in-band DTMF detection */ @@ -550,7 +619,8 @@ static struct ast_frame *oh323_read(struct ast_channel *c) struct ast_frame *fr; struct oh323_pvt *p = c->pvt->pvt; ast_mutex_lock(&p->lock); - fr = oh323_rtp_read(p); + /* Pass channel structure to handle other streams than just RTP */ + fr = oh323_rtp_read(c, p); ast_mutex_unlock(&p->lock); return fr; } @@ -559,6 +629,7 @@ static int oh323_write(struct ast_channel *c, struct ast_frame *frame) { struct oh323_pvt *p = c->pvt->pvt; int res = 0; + int need_frfree = 0; /* Does ast_frfree() call required? */ if (frame->frametype != AST_FRAME_VOICE) { if (frame->frametype == AST_FRAME_IMAGE) return 0; @@ -568,9 +639,47 @@ static int oh323_write(struct ast_channel *c, struct ast_frame *frame) } } else { if (!(frame->subclass & c->nativeformats)) { - ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n", - frame->subclass, c->nativeformats, c->readformat, c->writeformat); - return -1; + if(!(frame->subclass & c->writeformat)) { /* Someone sent frame with old format */ + ast_log(LOG_WARNING, "Asked to transmit frame type %s from %s by '%s', while native formats is %s (read/write = %s/%s)\n", + ast_getformatname(frame->subclass), frame->src, c->name, ast_getformatname(c->nativeformats), ast_getformatname(c->readformat), ast_getformatname(c->writeformat)); + return (c->nativeformats ? 0 : -1); + } else { + /* Frame goes from RTP is not in our native + * format - try to translate it... Or we must + * just drop it? + */ + + /* Sometimes translation table isn't set + * correctly but writeformat is invalid, + * so force required translation allocation + */ + ast_set_write_format(c, c->nativeformats); + ast_set_write_format(c, frame->subclass); + + /* Translate it on-the-fly */ + if (c->pvt->writetrans) { + struct ast_frame *frame1; + ast_log(LOG_WARNING, "Asked to transmit frame type %s from %s by '%s', while native formats is %s (read/write = %s/%s) - 2 TRANSLATE\n", + ast_getformatname(frame->subclass), frame->src, c->name, ast_getformatname(c->nativeformats), ast_getformatname(c->readformat), ast_getformatname(c->writeformat)); + /* Allocate new frame with translated context. + * Don't free frame because it will be freed on + * upper layer (RTP). + */ + frame1 = ast_translate(c->pvt->writetrans, frame, 0); + if(frame1) { + /* Substitute passed frame with translated and + mark it for freeing before return */ + frame = frame1; + need_frfree = 1; + } + else + ast_log(LOG_WARNING, "Unable to translate frame type %s to %s\n", ast_getformatname(frame->subclass), ast_getformatname(c->nativeformats)); + } else { + ast_log(LOG_WARNING, "Asked to transmit frame type %s from %s by '%s', while native formats is %s (read/write = %s/%s)\n", + ast_getformatname(frame->subclass), frame->src, c->name, ast_getformatname(c->nativeformats), ast_getformatname(c->readformat), ast_getformatname(c->writeformat)); + return -1; + } + } } } if (p) { @@ -580,6 +689,9 @@ static int oh323_write(struct ast_channel *c, struct ast_frame *frame) } ast_mutex_unlock(&p->lock); } + /* Free translated frame */ + if(need_frfree) + ast_frfree(frame); return res; } @@ -613,7 +725,7 @@ static int oh323_indicate(struct ast_channel *c, int condition) } return 0; case -1: - return -1; + return 0; default: ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", condition); return -1; @@ -644,13 +756,20 @@ static struct ast_channel *oh323_new(struct oh323_pvt *i, int state, const char if (ch) { +// snprintf(ch->name, sizeof(ch->name)-1, "H323/%s-%04x", host, rand() & 0xffff); snprintf(ch->name, sizeof(ch->name)-1, "H323/%s", host); ch->nativeformats = i->capability; if (!ch->nativeformats) ch->nativeformats = capability; fmt = ast_best_codec(ch->nativeformats); ch->type = type; + + /* RTP stream */ ch->fds[0] = ast_rtp_fd(i->rtp); + + /* RTCP stream */ + ch->fds[1] = ast_rtcp_fd(i->rtp); + ast_setstate(ch, state); if (state == AST_STATE_RING) @@ -691,6 +810,10 @@ static struct ast_channel *oh323_new(struct oh323_pvt *i, int state, const char ch->priority = 1; if (strlen(i->callerid)) ch->callerid = strdup(i->callerid); + if (strlen(i->dnid)) + ch->dnid = strdup(i->dnid); + if (strlen(i->rdnis)) + ch->rdnis = strdup(i->rdnis); if (strlen(i->accountcode)) strncpy(ch->accountcode, i->accountcode, sizeof(ch->accountcode)-1); if (i->amaflags) @@ -731,6 +854,7 @@ static struct oh323_pvt *oh323_alloc(int callid) p->cd.call_reference = callid; p->bridge = bridge_default; + memcpy(&p->calloptions, &global_options, sizeof(global_options)); p->dtmfmode = dtmfmode; if (p->dtmfmode & H323_DTMF_RFC2833) @@ -748,25 +872,24 @@ static struct oh323_pvt *find_call(int call_reference) { struct oh323_pvt *p; - ast_mutex_lock(&iflock); + ast_mutex_lock(&iflock); p = iflist; while(p) { if (p->cd.call_reference == call_reference) { /* Found the call */ - ast_mutex_unlock(&iflock); - return p; + ast_mutex_unlock(&iflock); + return p; } p = p->next; } ast_mutex_unlock(&iflock); - return NULL; - + + return NULL; } static struct ast_channel *oh323_request(char *type, int format, void *data) { - int oldformat; struct oh323_pvt *p; struct ast_channel *tmpc = NULL; @@ -835,20 +958,45 @@ static struct ast_channel *oh323_request(char *type, int format, void *data) return tmpc; } -struct oh323_alias *find_alias(const char *source_aliases) +struct oh323_alias *find_alias(call_details_t cd) { - struct oh323_alias *a; + struct oh323_alias *a, *a_e164 = NULL, *a_pfx = NULL; + char *s, *p; + int a_pfxlen, numlen; a = aliasl.aliases; + a_pfxlen = 0; + numlen = strlen(cd.call_dest_e164); while(a) { - if (!strcasecmp(a->name, source_aliases)) { + if (!strcasecmp(a->name, cd.call_dest_alias)) { break; } + /* Check for match of E164 number */ + if (!strcasecmp(a->e164, cd.call_dest_e164)) + a_e164 = a; + else { /* Check for match called number with prefixes */ + for(s = a->prefix; *s; ) { + for(; *s == ' '; ++s); + if(!(p = strchr(s, ','))) + p = s + strlen(s); + if((p - s > a_pfxlen) && (numlen >= p - s) && (strncasecmp(s, cd.call_dest_e164, p - s) == 0)) { + a_pfxlen = p - s; + a_pfx = a; + } + s = p; + if(*s == ',') + ++s; + } + } a = a->next; } - return a; + if(a) + return a; + if(a_e164) + return a_e164; + return a_pfx; } struct oh323_user *find_user(const call_details_t cd) @@ -894,6 +1042,27 @@ struct oh323_peer *find_peer(char *dest_peer) } +static int progress(unsigned call_reference, int inband) +{ + struct oh323_pvt *p; + + ast_log(LOG_DEBUG, "Received ALERT/PROGRESS message for %s tones\n", (inband ? "inband" : "self-generated")); + p = find_call(call_reference); + + if (!p) { + ast_log(LOG_ERROR, "Private structure not found in send_digit.\n"); + return -1; + } + if (!p->owner) { + ast_log(LOG_ERROR, "No asterisk's channel associated with private structure.\n"); + return -1; + } + + ast_queue_control(p->owner, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING), 0); + + return 0; +} + /** * Callback for sending digits from H.323 up to asterisk * @@ -912,13 +1081,13 @@ int send_digit(unsigned call_reference, char digit) } memset(&f, 0, sizeof(f)); f.frametype = AST_FRAME_DTMF; - f.subclass = digit; - f.datalen = 0; - f.samples = 300; + f.subclass = digit; + f.datalen = 0; + f.samples = 300; f.offset = 0; f.data = NULL; - f.mallocd = 0; - f.src = "SEND_DIGIT"; + f.mallocd = 0; + f.src = "SEND_DIGIT"; return ast_queue_frame(p->owner, &f, 1); } @@ -962,20 +1131,21 @@ struct rtp_info *create_connection(unsigned call_reference) * Returns 1 on success */ -int setup_incoming_call(call_details_t cd) +call_options_t *setup_incoming_call(call_details_t cd) { struct oh323_pvt *p = NULL; struct ast_channel *c = NULL; struct oh323_user *user = NULL; struct oh323_alias *alias = NULL; + call_options_t *call_options = NULL; /* allocate the call*/ p = oh323_alloc(cd.call_reference); if (!p) { ast_log(LOG_ERROR, "Unable to allocate private structure, this is bad.\n"); - return 0; + return NULL; } /* Populate the call details in the private structure */ @@ -986,21 +1156,28 @@ int setup_incoming_call(call_details_t cd) p->cd.call_dest_e164 = cd.call_dest_e164; if (h323debug) { - ast_verbose(VERBOSE_PREFIX_3 "Setting up Call\n"); - ast_verbose(VERBOSE_PREFIX_3 " Calling party name: [%s]\n", p->cd.call_source_aliases); - ast_verbose(VERBOSE_PREFIX_3 " Calling party number: [%s]\n", p->cd.call_source_e164); - ast_verbose(VERBOSE_PREFIX_3 " Called party name: [%s]\n", p->cd.call_dest_alias); - ast_verbose(VERBOSE_PREFIX_3 " Called party number: [%s]\n", p->cd.call_dest_e164); + ast_verbose(VERBOSE_PREFIX_2 "Setting up Call\n"); + ast_verbose(VERBOSE_PREFIX_3 "Calling party name: [%s]\n", p->cd.call_source_aliases); + ast_verbose(VERBOSE_PREFIX_3 "Calling party number: [%s]\n", p->cd.call_source_e164); + ast_verbose(VERBOSE_PREFIX_3 "Called party name: [%s]\n", p->cd.call_dest_alias); + ast_verbose(VERBOSE_PREFIX_3 "Called party number: [%s]\n", p->cd.call_dest_e164); + ast_verbose(VERBOSE_PREFIX_3 "Redirecting party number: [%s]\n", p->cd.call_redir_e164); } /* Decide if we are allowing Gatekeeper routed calls*/ if ((!strcasecmp(cd.sourceIp, gatekeeper)) && (gkroute == -1) && (usingGk == 1)) { if (strlen(cd.call_dest_e164)) { - strncpy(p->exten, cd.call_dest_e164, sizeof(p->exten)-1); - strncpy(p->context, default_context, sizeof(p->context)-1); + char *ctx; + + alias = find_alias(cd); + ctx = alias ? alias->context : default_context; + + strncpy(p->dnid, cd.call_dest_e164, sizeof(p->dnid)-1); + strncpy(p->exten, cd.call_dest_e164, sizeof(p->exten)-1); + strncpy(p->context, ctx, sizeof(p->context)-1); } else { - alias = find_alias(cd.call_dest_alias); + alias = find_alias(cd); if (!alias) { ast_log(LOG_ERROR, "Call for %s rejected, alias not found\n", cd.call_dest_alias); @@ -1010,8 +1187,8 @@ int setup_incoming_call(call_details_t cd) strncpy(p->context, alias->context, sizeof(p->context)-1); } - - sprintf(p->callerid, "%s <%s>", p->cd.call_source_aliases, p->cd.call_source_e164); + /* Asterisk prefers user name to be quoted */ + sprintf(p->callerid, "\"%s\" <%s>", p->cd.call_source_aliases, p->cd.call_source_e164); } else { /* Either this call is not from the Gatekeeper @@ -1022,11 +1199,13 @@ int setup_incoming_call(call_details_t cd) if (!user) { - sprintf(p->callerid, "%s <%s>", p->cd.call_source_aliases, p->cd.call_source_e164); + /* Asterisk prefers user name to be quoted */ + sprintf(p->callerid, "\"%s\" <%s>", p->cd.call_source_aliases, p->cd.call_source_e164); if (strlen(p->cd.call_dest_e164)) { + strncpy(p->dnid, cd.call_dest_e164, sizeof(p->dnid)-1); strncpy(p->exten, cd.call_dest_e164, sizeof(p->exten)-1); } else { - strncpy(p->exten, cd.call_dest_alias, sizeof(p->exten)-1); + strncpy(p->exten, cd.call_dest_alias, sizeof(p->exten)-1); } if (!strlen(default_context)) { ast_log(LOG_ERROR, "Call from user '%s' rejected due to no default context\n", p->cd.call_source_aliases); @@ -1034,13 +1213,14 @@ int setup_incoming_call(call_details_t cd) } strncpy(p->context, default_context, sizeof(p->context)-1); ast_log(LOG_DEBUG, "Sending %s to context [%s]\n", cd.call_source_aliases, p->context); - } else { + } else { + call_options = &user->call_options; if (user->host) { if (strcasecmp(cd.sourceIp, inet_ntoa(user->addr.sin_addr))){ if(!strlen(default_context)) { ast_log(LOG_ERROR, "Call from user '%s' rejected due to non-matching IP address of '%s'\n", user->name, cd.sourceIp); - return 0; + return NULL; } strncpy(p->context, default_context, sizeof(p->context)-1); @@ -1052,12 +1232,12 @@ int setup_incoming_call(call_details_t cd) if (user->incominglimit > 0) { if (user->inUse >= user->incominglimit) { ast_log(LOG_ERROR, "Call from user '%s' rejected due to usage limit of %d\n", user->name, user->incominglimit); - return 0; + return NULL; } } strncpy(p->context, user->context, sizeof(p->context)-1); p->bridge = user->bridge; - p->nat = user->nat; + p->nat = user->nat; if (strlen(user->callerid)) strncpy(p->callerid, user->callerid, sizeof(p->callerid) - 1); @@ -1080,14 +1260,21 @@ int setup_incoming_call(call_details_t cd) /* I know this is horrid, don't kill me saddam */ exit: + if(strlen(p->cd.call_redir_e164)) + strncpy(p->rdnis, cd.call_redir_e164, sizeof(p->rdnis)-1); /* allocate a channel and tell asterisk about it */ c = oh323_new(p, AST_STATE_RINGING, cd.call_token); if (!c) { ast_log(LOG_ERROR, "Couldn't create channel. This is bad\n"); - return 0; + return NULL; } - return 1; + ast_queue_control(c, AST_CONTROL_RINGING, 0); + + if(!call_options) + return &global_options; + + return call_options; } /** @@ -1117,7 +1304,56 @@ if (!p) { * * Returns nothing */ -void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort) +void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort, int direction, int payloadType) +{ + struct oh323_pvt *p = NULL; + struct sockaddr_in them; + struct rtpPayloadType payload; + struct ast_channel *chan; + + /* Find the call or allocate a private structure if call not found */ + p = find_call(call_reference); + + if (!p) { + ast_log(LOG_ERROR, "Something is wrong: rtp\n"); + return; + } + + them.sin_family = AF_INET; + them.sin_addr.s_addr = inet_addr(remoteIp); // only works for IPv4 + them.sin_port = htons(remotePort); + + /* Find RTP payload <=> asterisk's subcode association */ + payload = ast_rtp_lookup_pt(p->rtp, payloadType); + + ast_log(LOG_DEBUG, "Setting up %sbound RTP connection for %s:%d with payload %s (RTP code %d)\n", (direction ? "out" : "in"), inet_ntoa(them.sin_addr), remotePort, ast_getformatname(payload.code), payloadType); + + /* Set channel's native codec and prepare translation table + * for given direction and currently used format + */ + if ((chan = p->owner)) { + if (payload.isAstFormat) { + /* Don't allow any transmission until codec is changed */ +// ast_mutex_lock(&chan->lock); + chan->nativeformats = payload.code; + if(direction) + ast_set_write_format(chan, chan->writeformat); + else + ast_set_read_format(chan, chan->readformat); +// ast_mutex_unlock(&chan->lock); + } + } + + ast_rtp_set_peer(p->rtp, &them); + + if(p->calloptions.progress_audio) + progress(call_reference, TRUE); + + return; +} + +/* Not used for now - set RTP peer's address */ +void setup_rtp_peer(unsigned call_reference, const char *remoteIp, int remotePort) { struct oh323_pvt *p = NULL; struct sockaddr_in them; @@ -1134,8 +1370,6 @@ void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int rem them.sin_addr.s_addr = inet_addr(remoteIp); // only works for IPv4 them.sin_port = htons(remotePort); ast_rtp_set_peer(p->rtp, &them); - - return; } /** @@ -1236,13 +1470,15 @@ restartsearch: } ast_mutex_unlock(&iflock); - pthread_testcancel(); - /* Wait for sched or io */ res = ast_sched_wait(sched); if ((res < 0) || (res > 1000)) res = 1000; res = ast_io_wait(io, res); + + /* Check for thread cancellation */ + pthread_testcancel(); + ast_mutex_lock(&monlock); if (res >= 0) ast_sched_runq(sched); @@ -1392,7 +1628,7 @@ int reload_config(void) struct oh323_alias *alias = NULL; struct hostent *hp; char *cat; - char *utype; + char *utype; cfg = ast_load(config); @@ -1408,6 +1644,8 @@ int reload_config(void) } h323debug=0; dtmfmode = H323_DTMF_RFC2833; + /* Fill global variables with pre-determined values */ + memset(&global_options, 0, sizeof(global_options)); memset(&bindaddr, 0, sizeof(bindaddr)); @@ -1478,6 +1716,33 @@ int reload_config(void) ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value); dtmfmode = H323_DTMF_RFC2833; } + /* Setup global parameters */ + } else if (!strcasecmp(v->name, "noFastStart")) { + global_options.noFastStart = ast_true(v->value); + } else if (!strcasecmp(v->name, "noH245Tunneling")) { + global_options.noH245Tunnelling = ast_true(v->value); + } else if (!strcasecmp(v->name, "noSilenceSuppression")) { + global_options.noSilenceSuppression = ast_true(v->value); + } else if (!strcasecmp(v->name, "progress_setup")) { + int progress_setup = atoi(v->value); + if((progress_setup != 0) && + (progress_setup != 1) && + (progress_setup != 3) && + (progress_setup != 8)) { + ast_log(LOG_WARNING, "Invalid value %d for progress_setup at line %d, assuming 0\n", progress_setup, v->lineno); + progress_setup = 0; + } + global_options.progress_setup = progress_setup; + } else if (!strcasecmp(v->name, "progress_alert")) { + int progress_alert = atoi(v->value); + if((progress_alert != 0) && + (progress_alert != 8)) { + ast_log(LOG_WARNING, "Invalid value %d for progress_alert at line %d, assuming 0\n", progress_alert, v->lineno); + progress_alert = 0; + } + global_options.progress_alert = progress_alert; + } else if (!strcasecmp(v->name, "progress_audio")) { + global_options.progress_audio = ast_true(v->value); } else if (!strcasecmp(v->name, "UserByAlias")) { userbyalias = ast_true(v->value); } else if (!strcasecmp(v->name, "bridge")) { @@ -1608,15 +1873,20 @@ int reload(void) delete_aliases(); prune_peers(); + reload_config(); + + +#if 0 + +This code causes seg on -r + if (strlen(gatekeeper)) { h323_gk_urq(); } - reload_config(); -#if 0 /* Possibly register with a GK */ - if (gatekeeper_disable == 0) { + if (!gatekeeper_disable) { if (h323_set_gk(gatekeeper_discover, gatekeeper, secret)) { ast_log(LOG_ERROR, "Gatekeeper registration failed.\n"); h323_end_process(); @@ -1624,6 +1894,7 @@ int reload(void) } } #endif + restart_monitor(); return 0; } @@ -1747,7 +2018,9 @@ int load_module() create_connection, setup_rtp_connection, cleanup_connection, - connection_made, send_digit); + connection_made, + send_digit, + progress); /* start the h.323 listener */ @@ -1805,6 +2078,7 @@ int unload_module() return -1; } h323_gk_urq(); + h323_debug(0,0); h323_end_process(); /* unregister rtp */ @@ -1843,7 +2117,3 @@ char *key() { return ASTERISK_GPL_KEY; } - - - - diff --git a/channels/h323/ast_h323.cpp b/channels/h323/ast_h323.cpp index 3a822c806c..dfdef12f9c 100755 --- a/channels/h323/ast_h323.cpp +++ b/channels/h323/ast_h323.cpp @@ -41,10 +41,11 @@ int channelsOpen; /* DTMF Mode */ int mode = H323_DTMF_RFC2833; +/* Make those variables accessible from chan_h323.c */ +extern "C" { /** Options for connections creation */ -BOOL noFastStart; -BOOL noH245Tunnelling; -BOOL noSilenceSuppression; +call_options_t global_options; +} /** * We assume that only one endPoint should exist. @@ -59,6 +60,27 @@ MyProcess *localProcess = NULL; /** H.323 listener */ H323ListenerTCP *tcpListener; +/* Provide common methods to split out non-user parts of OpenH323 aliases */ +static void FormatAliases(PString & aliases) +{ + /* Convert complex strings */ + // FIXME: deal more than one source alias + char *s; + const char *p = (const char *)aliases; + if ((s = strchr(p, '(')) != NULL) + *s = '\0'; + else if ((s = strchr(p, ',')) != NULL) + *s = '\0'; + else if ((s = strchr(p, '[')) != NULL) + *s = '\0'; + else if ((s = strchr(p, ' ')) != NULL) + *s = '\0'; + else if ((s = strchr(p, '\t')) != NULL) + *s = '\0'; + /* Strip trailing spaces */ + for(s = (char *)(p + strlen(p)); (s > p) && (*--s == ' '); *s = '\0'); +} + MyProcess::MyProcess(): PProcess("The NuFone Network's", "H.323 Channel Driver for Asterisk", MAJOR_VERSION, MINOR_VERSION, BUILD_TYPE, BUILD_NUMBER) { @@ -76,6 +98,7 @@ void MyProcess::Main() { cout << " == Creating H.323 Endpoint" << endl; endPoint = new MyH323EndPoint(); + endPoint->DisableDetectInBandDTMF(TRUE); PTrace::Initialise(0, NULL, PTrace::Timestamp | PTrace::Thread | PTrace::FileAndLine); } @@ -111,6 +134,7 @@ H323_G7231Capability::H323_G7231Capability(BOOL annexA_) : H323AudioCapability(7, 4) { annexA = annexA_; + rtpPayloadType = RTP_DataFrame::G7231; } PObject::Comparison H323_G7231Capability::Compare(const PObject & obj) const @@ -248,7 +272,8 @@ H323Codec * AST_G729ACapability::CreateCodec(H323Codec::Direction direction) con * port = 1720. */ int MyH323EndPoint::MakeCall(const PString & dest, PString & token, - unsigned int *callReference, unsigned int port, char *callerid) + unsigned int *callReference, + call_options_t *call_options) { PString fullAddress; MyH323Connection * connection; @@ -264,7 +289,7 @@ int MyH323EndPoint::MakeCall(const PString & dest, PString & token, cout << " -- Making call to " << fullAddress << "." << endl; } - if (!(connection = (MyH323Connection *)H323EndPoint::MakeCallLocked(fullAddress, token))) { + if (!(connection = (MyH323Connection *)H323EndPoint::MakeCallLocked(fullAddress, token, call_options))) { if (h323debug) cout << "Error making call to \"" << fullAddress << '"' << endl; return 1; @@ -272,8 +297,8 @@ int MyH323EndPoint::MakeCall(const PString & dest, PString & token, *callReference = connection->GetCallReference(); - if (callerid) - connection->SetLocalPartyName(PString(callerid)); + if (call_options->callerid) + connection->SetCID(call_options->callerid); // Use our local function to setup H.323 caller ID correctly connection->Unlock(); @@ -287,7 +312,16 @@ int MyH323EndPoint::MakeCall(const PString & dest, PString & token, void MyH323EndPoint::SetEndpointTypeInfo( H225_EndpointType & info ) const { +// cout << " **** Terminal type: " << terminalType << endl; H323EndPoint::SetEndpointTypeInfo(info); +// cout << " **** INFO: " << info << endl; + /* Because H323EndPoint::SetEndpointTypeInfo() don't set correctly + endpoint type, force manual setting it */ + if(terminalType == e_GatewayOnly) + { + info.RemoveOptionalField(H225_EndpointType::e_terminal); + info.IncludeOptionalField(H225_EndpointType::e_gateway); + } info.m_gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol); info.m_gateway.m_protocol.SetSize(1); H225_SupportedProtocols &protocol=info.m_gateway.m_protocol[0]; @@ -336,17 +370,17 @@ void MyH323EndPoint::OnClosedLogicalChannel(H323Connection & connection, const H } BOOL MyH323EndPoint::OnConnectionForwarded(H323Connection & connection, - const PString & forwardParty, - const H323SignalPDU & pdu) - { + const PString & forwardParty, + const H323SignalPDU & pdu) +{ if (h323debug) cout << " -- Call Forwarded to " << forwardParty << endl; return FALSE; - } - +} + BOOL MyH323EndPoint::ForwardConnection(H323Connection & connection, - const PString & forwardParty, - const H323SignalPDU & pdu) + const PString & forwardParty, + const H323SignalPDU & pdu) { if (h323debug) cout << " -- Forwarding call to " << forwardParty << endl; @@ -369,14 +403,12 @@ void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PStr call_details_t cd; + /* Use common alias formatting routine */ + FormatAliases(remoteName); + cd.call_reference = connection.GetCallReference(); cd.call_token = (const char *)connection.GetCallToken(); - cd.call_source_aliases = (const char *)connection.GetRemotePartyName(); - - /* Convert complex strings */ - char *s; - if ((s = strchr(cd.call_source_aliases, ' ')) != NULL) - *s = '\0'; + cd.call_source_aliases = (const char *)remoteName; /* Invoke the PBX application registered callback */ on_connection_cleared(cd); @@ -452,7 +484,7 @@ void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PStr break; default : if (h323debug) - cout << " -- Call with " << remoteName << " completed" << endl; + cout << " -- Call with " << remoteName << " completed (" << connection.GetCallEndReason() << ")" << endl; } if(connection.IsEstablished()) if (h323debug) @@ -463,26 +495,146 @@ void MyH323EndPoint::OnConnectionCleared(H323Connection & connection, const PStr H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference, void *outbound) { unsigned options = 0; + call_options_t *call_options = (call_options_t *)outbound; - if (noFastStart) + if (!call_options) + call_options = &global_options; + + if (call_options->noFastStart) options |= H323Connection::FastStartOptionDisable; - if (noH245Tunnelling) + if (call_options->noH245Tunnelling) options |= H323Connection::H245TunnelingOptionDisable; - return new MyH323Connection(*this, callReference, options); + /* Set silence detection mode - won't work for Asterisk's RTP but can be used in the negotiation process */ + SetSilenceDetectionMode(call_options->noSilenceSuppression ? H323AudioCodec::NoSilenceDetection : H323AudioCodec::AdaptiveSilenceDetection); + + return new MyH323Connection(*this, callReference, options, call_options); +} + +/* MyH323_ExternalRTPChannel */ +MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel( + H323Connection & connection, /// Connection to endpoint for channel + const H323Capability & capability, /// Capability channel is using + Directions direction, /// Direction of channel + unsigned sessionID /// Session ID for channel + ): H323_ExternalRTPChannel(connection,capability,direction,sessionID) +{ +} + +MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel( + H323Connection & connection, /// Connection to endpoint for channel + const H323Capability & capability, /// Capability channel is using + Directions direction, /// Direction of channel + unsigned sessionID, /// Session ID for channel + const H323TransportAddress & data, /// Data address + const H323TransportAddress & control/// Control address + ): H323_ExternalRTPChannel(connection, capability, direction, sessionID, data, control) +{ +} + +MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel( + H323Connection & connection, /// Connection to endpoint for channel + const H323Capability & capability, /// Capability channel is using + Directions direction, /// Direction of channel + unsigned sessionID, /// Session ID for channel + const PIPSocket::Address & ip, /// IP address of media server + WORD dataPort /// Data port (control is dataPort+1) + ): H323_ExternalRTPChannel(connection, capability, direction, sessionID, ip, dataPort) +{ +} + +BOOL MyH323_ExternalRTPChannel::Start() +{ + BOOL res; + PIPSocket::Address remoteIpAddress; // IP Address of remote endpoint + WORD remotePort; // remote endpoint Data port (control is dataPort+1) + PIPSocket::Address externalIpAddress; // IP address of media server + WORD externalPort; // local media server Data port (control is dataPort+1) + + res = H323_ExternalRTPChannel::Start(); + if (!res) + return res; + + if (h323debug) { + /* Show H.323 channel number to make debugging more comfortable */ + cout << " -- Started RTP media for channel " << GetNumber() << ": "; + cout << ((GetDirection()==H323Channel::IsTransmitter)?"sending ":((GetDirection()==H323Channel::IsReceiver)?"receiving ":" ")); + cout << (const char *)(GetCapability()).GetFormatName() << endl; + } + + if(!GetRemoteAddress(remoteIpAddress, remotePort) && h323debug) + cout << " ** Unable to get remote IP address" << endl; + externalMediaAddress.GetIpAndPort(externalIpAddress, externalPort); + + if (h323debug) { + cout << " -- remoteIpAddress: " << remoteIpAddress << endl; + cout << " -- remotePort: " << remotePort << endl; + cout << " -- ExternalIpAddress: " << externalIpAddress << endl; + cout << " -- ExternalPort: " << externalPort << endl; + } + + const OpalMediaFormat & mediaFormat = codec->GetMediaFormat(); + if (rtpPayloadType == RTP_DataFrame::IllegalPayloadType) { + rtpPayloadType = capability->GetPayloadType(); + if (rtpPayloadType == RTP_DataFrame::IllegalPayloadType) + rtpPayloadType = mediaFormat.GetPayloadType(); + } + + /* Deduce direction of starting channel */ + int direction; + if (GetDirection()==H323Channel::IsTransmitter) + direction = 1; + else if (GetDirection()==H323Channel::IsReceiver) + direction = 0; + else + direction = -1; + + /* Notify Asterisk of remote RTP information */ + /* direction and payload arguments needs to + * correctly setup RTP transport + */ + on_start_logical_channel(connection.GetCallReference(), (const char *)remoteIpAddress.AsString(), remotePort, direction, (int)rtpPayloadType); + + return TRUE; } /* MyH323Connection */ MyH323Connection::MyH323Connection(MyH323EndPoint & ep, - unsigned callReference, - unsigned options) - : H323Connection(ep, - callReference, - options) + unsigned callReference, + unsigned options) + : H323Connection(ep, + callReference, + options) { - remoteIpAddress = 0; // IP Address of remote endpoint - remotePort = 0; // remote endpoint Data port (control is dataPort+1) + remoteIpAddress = 0; // IP Address of remote endpoint + remotePort = 0; // remote endpoint Data port (control is dataPort+1) + + progressSetup = global_options.progress_setup; + progressAlert = global_options.progress_alert; + + if (h323debug) + cout << " == New H.323 Connection created." << endl; + return; +} + +/* MyH323Connection */ +MyH323Connection::MyH323Connection(MyH323EndPoint & ep, + unsigned callReference, + unsigned options, + call_options_t *call_options) + : H323Connection(ep, + callReference, + options) +{ + remoteIpAddress = 0; // IP Address of remote endpoint + remotePort = 0; // remote endpoint Data port (control is dataPort+1) + + if (!call_options) + call_options = &global_options; + + progressSetup = call_options->progress_setup; + progressAlert = call_options->progress_alert; if (h323debug) cout << " == New H.323 Connection created." << endl; @@ -496,20 +648,118 @@ MyH323Connection::~MyH323Connection() return; } +/* Declare reference to standard Asterisk's callerid parser */ +extern "C" { + void ast_callerid_parse(const char *, char **, char **); +} + +/* + * Setup H.323 caller ID to allow OpenH323 to set up Q.931's + * IE:DisplayName and IE:DisplayNumber fields correctly + */ +void MyH323Connection::SetCID(const char *callerid) +{ + char *name; + char *num; + + ast_callerid_parse(callerid, &name, &num); + + if (h323debug) + cout << "name=" << name << ", num=" << num << endl; + + if ((name && *name) || (num && *num)) + { + localAliasNames.RemoveAll(); + if(name && *name) { + SetLocalPartyName(PString(name)); +// localAliasNames.AppendString(name); + } + if(num && *num) + localAliasNames.AppendString(PString(num)); + } +} + +BOOL MyH323Connection::OnReceivedProgress(const H323SignalPDU & pdu) +{ + BOOL res; + + res = H323Connection::OnReceivedProgress(pdu); + + if(res && on_progress) { + BOOL inband; + unsigned ProgressPI; + + if(!pdu.GetQ931().GetProgressIndicator(ProgressPI)) + ProgressPI = 0; + if(h323debug) + cout << "Progress Indicator is " << ProgressPI << endl; + + /* XXX Is this correct? XXX */ + switch(ProgressPI) { + case Q931::ProgressNotEndToEndISDN: + case Q931::ProgressInbandInformationAvailable: + inband = TRUE; + break; + default: + inband = FALSE; + } + on_progress(GetCallReference(), inband); + } + + return res; +} + H323Connection::AnswerCallResponse MyH323Connection::OnAnswerCall(const PString & caller, - const H323SignalPDU & /*setupPDU*/, + const H323SignalPDU & setupPDU, H323SignalPDU & /*connectPDU*/) { + unsigned ProgressInd; + /* The call will be answered later with "AnsweringCall()" function. */ + if(!setupPDU.GetQ931().GetProgressIndicator(ProgressInd)) + ProgressInd = 0; + if(h323debug) + cout << "PI in SETUP was " << ProgressInd << endl; + + /* Progress indicator must be always set to 8 if Setup Have Progress indicator equal to 3 */ + if(progressAlert) + ProgressInd = progressAlert; + else if(ProgressInd == Q931::ProgressOriginNotISDN) + ProgressInd = Q931::ProgressInbandInformationAvailable; + if(ProgressInd) + alertingPDU->GetQ931().SetProgressIndicator(ProgressInd); + if(h323debug) + cout << "Adding PI=" << ProgressInd << " to ALERT message" << endl; + return H323Connection::AnswerCallAlertWithMedia; } -BOOL MyH323Connection::OnAlerting(const H323SignalPDU & /*alertingPDU*/, const PString & username) +BOOL MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PString & username) { - if (h323debug) cout << " -- Ringing phone for \"" << username << "\"" << endl; + + if (on_progress) { + BOOL inband; + unsigned alertingPI; + + if(!alertingPDU.GetQ931().GetProgressIndicator(alertingPI)) + alertingPI = 0; + if(h323debug) + cout << "Progress Indicator is " << alertingPI << endl; + + /* XXX Is this correct? XXX */ + switch(alertingPI) { + case Q931::ProgressNotEndToEndISDN: + case Q931::ProgressInbandInformationAvailable: + inband = TRUE; + break; + default: + inband = FALSE; + } + on_progress(GetCallReference(), inband); + } return TRUE; } @@ -523,6 +773,7 @@ BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU) PString sourceE164; PString destE164; + PString redirE164; PString sourceAliases; PString destAliases; PString sourceIp; @@ -537,19 +788,12 @@ BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU) setupPDU.GetSourceE164(sourceE164); destE164 = ""; setupPDU.GetDestinationE164(destE164); + if(!setupPDU.GetQ931().GetRedirectingNumber(redirE164)) + redirE164 = ""; - /* Convert complex strings */ - // FIXME: deal more than one source alias - char *s; - if ((s = strchr(sourceAliases, ' ')) != NULL) - *s = '\0'; - if ((s = strchr(sourceAliases, '\t')) != NULL) - *s = '\0'; - char *s1; - if ((s1 = strchr(destAliases, ' ')) != NULL) - *s1 = '\0'; - if ((s1 = strchr(destAliases, '\t')) != NULL) - *s1 = '\0'; + /* Use common alias formatting routine */ + FormatAliases(sourceAliases); + FormatAliases(destAliases); GetSignallingChannel()->GetRemoteAddress().GetIpAndPort(Ip, sourcePort); @@ -557,20 +801,24 @@ BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU) cd.call_reference = GetCallReference(); cd.call_token = (const char *)GetCallToken(); - cd.call_source_aliases = (const char *)sourceAliases; + cd.call_source_aliases = (const char *)sourceAliases; cd.call_dest_alias = (const char *)destAliases; cd.call_source_e164 = (const char *)sourceE164; cd.call_dest_e164 = (const char *)destE164; - cd.sourceIp = (const char *)sourceIp; + cd.call_redir_e164 = (const char *)redirE164; + cd.sourceIp = (const char *)sourceIp; /* Notify Asterisk of the request */ - int res = on_incoming_call(cd); + call_options_t *res = on_incoming_call(cd); if (!res) { if (h323debug) cout << " -- Call Failed" << endl; return FALSE; } + + progressSetup = res->progress_setup; + progressAlert = res->progress_alert; return H323Connection::OnReceivedSignalSetup(setupPDU); } @@ -590,22 +838,13 @@ BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU) destE164 = ""; setupPDU.GetDestinationE164(destE164); - /* Convert complex strings */ - // FIXME: deal more than one source alias - char *s; - if ((s = strchr(sourceAliases, ' ')) != NULL) - *s = '\0'; - if ((s = strchr(sourceAliases, '\t')) != NULL) - *s = '\0'; - char *s1; - if ((s1 = strchr(destAliases, ' ')) != NULL) - *s1 = '\0'; - if ((s1 = strchr(destAliases, '\t')) != NULL) - *s1 = '\0'; + /* Use common alias formatting routine */ + FormatAliases(sourceAliases); + FormatAliases(destAliases); cd.call_reference = GetCallReference(); cd.call_token = (const char *)GetCallToken(); - cd.call_source_aliases = (const char *)sourceAliases; + cd.call_source_aliases = (const char *)sourceAliases; cd.call_dest_alias = (const char *)destAliases; cd.call_source_e164 = (const char *)sourceE164; cd.call_dest_e164 = (const char *)destE164; @@ -618,6 +857,10 @@ BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU) return FALSE; } + if(progressSetup) + setupPDU.GetQ931().SetProgressIndicator(progressSetup); +// setupPDU.GetQ931().SetProgressIndicator(Q931::ProgressInbandInformationAvailable); +// setupPDU.GetQ931().SetProgressIndicator(Q931::ProgressOriginNotISDN); return H323Connection::OnSendSignalSetup(setupPDU); } @@ -708,7 +951,7 @@ H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capabilit cout << " -- SessionID: " << sessionID << endl; cout << " -- Direction: " << dir << endl; } - return new H323_ExternalRTPChannel(*this, capability, dir, sessionID, externalIpAddress, externalPort); + return new MyH323_ExternalRTPChannel(*this, capability, dir, sessionID, externalIpAddress, externalPort); } /** This callback function is invoked once upon creation of each @@ -717,7 +960,8 @@ H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capabilit BOOL MyH323Connection::OnStartLogicalChannel(H323Channel & channel) { if (h323debug) { - cout << " -- Started logical channel: "; + /* Show H.323 channel number to make debugging more comfortable */ + cout << " -- Started logical channel " << channel.GetNumber() << ": "; cout << ((channel.GetDirection()==H323Channel::IsTransmitter)?"sending ":((channel.GetDirection()==H323Channel::IsReceiver)?"receiving ":" ")); cout << (const char *)(channel.GetCapability()).GetFormatName() << endl; } @@ -726,8 +970,10 @@ BOOL MyH323Connection::OnStartLogicalChannel(H323Channel & channel) if (h323debug) cout << " -- channelsOpen = " << channelsOpen << endl; +#if 0 H323_ExternalRTPChannel & external = (H323_ExternalRTPChannel &)channel; - external.GetRemoteAddress(remoteIpAddress, remotePort); + if(!external.GetRemoteAddress(remoteIpAddress, remotePort) && h323debug) + cout << " ** Unable to get remote IP address" << endl; if (h323debug) { cout << " -- remoteIpAddress: " << remoteIpAddress << endl; @@ -735,8 +981,49 @@ BOOL MyH323Connection::OnStartLogicalChannel(H323Channel & channel) cout << " -- ExternalIpAddress: " << externalIpAddress << endl; cout << " -- ExternalPort: " << externalPort << endl; } + + /* Try to determine negotiated RTP payload format to configure + * RTP stack more quickly (not to wait at least one packet with + * filled RTP payload + */ + RTP_DataFrame::PayloadTypes payloadType = channel.GetCapability().GetPayloadType(); + cout << " *** channel's payload is " << payloadType << endl; + if (payloadType == RTP_DataFrame::IllegalPayloadType) { + payloadType = channel.GetCodec()->GetMediaFormat().GetPayloadType(); + cout << " *** channel's codec payload is " << payloadType << endl; + } + if ((payloadType == RTP_DataFrame::IllegalPayloadType) || (payloadType >= RTP_DataFrame::DynamicBase)) { + OpalMediaFormat mediaFormat = channel.GetCodec()->GetMediaFormat(); +// if (mediaFormat.GetPayloadType() < RTP_DataFrame::DynamicBase) + { + payloadType = mediaFormat.GetPayloadType(); + cout << " *** channel's Opal media payload is " << payloadType << endl; + } + } +// if ((payloadType == RTP_DataFrame::IllegalPayloadType)) { +// OpalMediaFormat OMF((const char *)(channel.GetCapability()).GetFormatName(), 1); +// if (OMF.IsValid()) +// { +// payloadType = OMF.GetPayloadType(); +// cout << " *** channel's OMF payload is " << payloadType << endl; +// } +// } + + /* Deduce direction of starting channel */ + int direction; + if (channel.GetDirection()==H323Channel::IsTransmitter) + direction = 1; + else if (channel.GetDirection()==H323Channel::IsReceiver) + direction = 0; + else + direction = -1; + /* Notify Asterisk of remote RTP information */ - on_start_logical_channel(GetCallReference(), (const char *)remoteIpAddress.AsString(), remotePort); + /* direction and payload arguments needs to + * correctly setup RTP transport + */ + on_start_logical_channel(GetCallReference(), (const char *)remoteIpAddress.AsString(), remotePort, direction, (int)payloadType); +#endif return TRUE; } @@ -799,7 +1086,6 @@ void h323_gk_urq(void) cout << " ERROR: [h323_gk_urq] No Endpoint, this is bad" << endl; return; } - endPoint->RemoveGatekeeper(); } @@ -823,7 +1109,8 @@ void h323_callback_register(setup_incoming_cb ifunc, start_logchan_cb lfunc, clear_con_cb clfunc, con_established_cb efunc, - send_digit_cb dfunc) + send_digit_cb dfunc, + progress_cb pgfunc) { on_incoming_call = ifunc; on_outgoing_call = sfunc; @@ -832,6 +1119,7 @@ void h323_callback_register(setup_incoming_cb ifunc, on_connection_cleared = clfunc; on_connection_established = efunc; on_send_digit = dfunc; + on_progress = pgfunc; } /** @@ -840,7 +1128,8 @@ void h323_callback_register(setup_incoming_cb ifunc, int h323_set_capability(int cap, int dtmfMode) { int g711Frames = 30; - int gsmFrames = 4; + int gsmFrames = 4; + PINDEX last_cap = -1; /* last common capability block index */ if (!h323_end_point_exist()) { @@ -848,61 +1137,74 @@ int h323_set_capability(int cap, int dtmfMode) return 1; } - mode = dtmfMode; - if (dtmfMode == H323_DTMF_INBAND) - endPoint->SetSendUserInputMode(H323Connection::SendUserInputAsTone); - else - endPoint->SetSendUserInputMode(H323Connection::SendUserInputAsInlineRFC2833); - + /* User input mode moved to the end of procedure */ /* Hardcode this for now (Someone tell me if T.38 works now or provide me with some debug so we can make this work */ -// endPoint->SetCapability(0, 0, new H323_T38Capability(H323_T38Capability::e_UDP)); +// last_cap = endPoint->SetCapability(0, 0, new H323_T38Capability(H323_T38Capability::e_UDP)); if (cap & AST_FORMAT_SPEEX) { /* Not real sure if Asterisk acutally supports all of the various different bit rates so add them all and figure it out later*/ - endPoint->SetCapability(0, 0, new SpeexNarrow2AudioCapability()); - endPoint->SetCapability(0, 0, new SpeexNarrow3AudioCapability()); - endPoint->SetCapability(0, 0, new SpeexNarrow4AudioCapability()); - endPoint->SetCapability(0, 0, new SpeexNarrow5AudioCapability()); - endPoint->SetCapability(0, 0, new SpeexNarrow6AudioCapability()); + last_cap = endPoint->SetCapability(0, 0, new SpeexNarrow2AudioCapability()); + last_cap = endPoint->SetCapability(0, 0, new SpeexNarrow3AudioCapability()); + last_cap = endPoint->SetCapability(0, 0, new SpeexNarrow4AudioCapability()); + last_cap = endPoint->SetCapability(0, 0, new SpeexNarrow5AudioCapability()); + last_cap = endPoint->SetCapability(0, 0, new SpeexNarrow6AudioCapability()); } if (cap & AST_FORMAT_G729A) { AST_G729ACapability *g729aCap; AST_G729Capability *g729Cap; - endPoint->SetCapability(0, 0, g729aCap = new AST_G729ACapability); - endPoint->SetCapability(0, 0, g729Cap = new AST_G729Capability); + last_cap = endPoint->SetCapability(0, 0, g729aCap = new AST_G729ACapability); + last_cap = endPoint->SetCapability(0, 0, g729Cap = new AST_G729Capability); } if (cap & AST_FORMAT_G723_1) { - H323_G7231Capability *g7231Cap; - endPoint->SetCapability(0, 0, g7231Cap = new H323_G7231Capability); + H323_G7231Capability *g7231Cap, *g7231Cap1; + last_cap = endPoint->SetCapability(0, 0, g7231Cap = new H323_G7231Capability); + last_cap = endPoint->SetCapability(0, 0, g7231Cap1 = new H323_G7231Capability(FALSE)); } if (cap & AST_FORMAT_GSM) { H323_GSM0610Capability *gsmCap; - endPoint->SetCapability(0, 0, gsmCap = new H323_GSM0610Capability); - gsmCap->SetTxFramesInPacket(gsmFrames); + last_cap = endPoint->SetCapability(0, 0, gsmCap = new H323_GSM0610Capability); + gsmCap->SetTxFramesInPacket(gsmFrames); } if (cap & AST_FORMAT_ULAW) { - H323_G711Capability *g711uCap; - endPoint->SetCapability(0, 0, g711uCap = new H323_G711Capability(H323_G711Capability::muLaw)); + last_cap = endPoint->SetCapability(0, 0, g711uCap = new H323_G711Capability(H323_G711Capability::muLaw)); g711uCap->SetTxFramesInPacket(g711Frames); } if (cap & AST_FORMAT_ALAW) { H323_G711Capability *g711aCap; - endPoint->SetCapability(0, 0, g711aCap = new H323_G711Capability(H323_G711Capability::ALaw)); + last_cap = endPoint->SetCapability(0, 0, g711aCap = new H323_G711Capability(H323_G711Capability::ALaw)); g711aCap->SetTxFramesInPacket(g711Frames); } + /* Add HookFlash capability - not used yet now */ + last_cap++; + last_cap = endPoint->SetCapability(0, last_cap, new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245)); + + /* Add correct UserInputMode capability + * This allows remote party to send UserIput + * correctly embedded into protocol + */ + last_cap++; + mode = dtmfMode; + if (dtmfMode == H323_DTMF_INBAND) { + endPoint->SetCapability(0, last_cap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245)); + endPoint->SetSendUserInputMode(H323Connection::SendUserInputAsTone); + } else { + endPoint->SetCapability(0, last_cap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833)); + endPoint->SetSendUserInputMode(H323Connection::SendUserInputAsInlineRFC2833); + } + return 0; } @@ -1054,7 +1356,7 @@ void h323_send_tone(const char *call_token, char tone) /** Make a call to the remote endpoint. */ -int h323_make_call(char *host, call_details_t *cd, call_options_t call_options) +int h323_make_call(char *host, call_details_t *cd, call_options_t *call_options) { int res; PString token; @@ -1065,7 +1367,7 @@ int h323_make_call(char *host, call_details_t *cd, call_options_t call_options) PString dest(host); - res = endPoint->MakeCall(dest, token, &cd->call_reference, call_options.port, call_options.callerid); + res = endPoint->MakeCall(dest, token, &cd->call_reference, call_options); memcpy((char *)(cd->call_token), (const unsigned char *)token, token.GetLength()); return res; @@ -1142,6 +1444,3 @@ void h323_native_bridge(const char *token, char *them, char *capability) } } /* extern "C" */ - - - diff --git a/channels/h323/ast_h323.h b/channels/h323/ast_h323.h index 5c0c2b4a91..6b05a9fd82 100755 --- a/channels/h323/ast_h323.h +++ b/channels/h323/ast_h323.h @@ -88,7 +88,7 @@ class H323_G7231Capability : public H323AudioCapability H245_AudioCapability & pdu, /// PDU to set information on unsigned packetSize /// Packet size to use in capability ) const; - + BOOL OnReceivedPDU( const H245_AudioCapability & pdu, /// PDU to get information from unsigned & packetSize /// Packet size to use in capability @@ -198,7 +198,7 @@ class MyH323EndPoint : public H323EndPoint { public: - int MakeCall(const PString &, PString &, unsigned int *, unsigned int, char *); + int MakeCall(const PString &, PString &, unsigned int *, call_options_t *); BOOL ClearCall(const PString &); void OnClosedLogicalChannel(H323Connection &, const H323Channel &); @@ -213,9 +213,8 @@ class MyH323EndPoint : public H323EndPoint { PStringArray SupportedPrefixes; - void SetEndpointTypeInfo( H225_EndpointType & info ) const; - void SetGateway(void); - + void SetEndpointTypeInfo( H225_EndpointType & info ) const; + void SetGateway(void); }; @@ -225,6 +224,7 @@ class MyH323Connection : public H323Connection { public: MyH323Connection(MyH323EndPoint &, unsigned, unsigned); + MyH323Connection(MyH323EndPoint &, unsigned, unsigned, call_options_t *); ~MyH323Connection(); H323Channel * CreateRealTimeLogicalChannel(const H323Capability &, H323Channel::Directions, unsigned, @@ -241,6 +241,9 @@ class MyH323Connection : public H323Connection { void SendUserInputTone(char, unsigned); void OnUserInputTone(char, unsigned, unsigned, unsigned); void OnUserInputString(const PString &value); + BOOL OnReceivedProgress(const H323SignalPDU &); + /* Set up H.323 caller id */ + void SetCID(const char *callerid); PString sourceAliases; PString destAliases; @@ -248,11 +251,53 @@ class MyH323Connection : public H323Connection { PString destE164; PIPSocket::Address externalIpAddress; // IP address of media server - PIPSocket::Address remoteIpAddress; // IP Address of remote endpoint - WORD externalPort; // local media server Data port (control is dataPort+1) - WORD remotePort; // remote endpoint Data port (control is dataPort+1) - WORD sessionId; - BOOL bridging; // Used to help determine which IP to use + PIPSocket::Address remoteIpAddress; // IP Address of remote endpoint + WORD externalPort; // local media server Data port (control is dataPort+1) + WORD remotePort; // remote endpoint Data port (control is dataPort+1) + WORD sessionId; + BOOL bridging; // Used to help determine which IP to use + unsigned progressSetup; // ProgressIndicator IE value for SETUP message + unsigned progressAlert; // ProgressIndicator IE value for ALERT message +}; + +class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel +{ + PCLASSINFO(MyH323_ExternalRTPChannel, H323_ExternalRTPChannel); + +public: + /**@name Construction */ + //@{ + /**Create a new channel. + */ + MyH323_ExternalRTPChannel( + H323Connection & connection, /// Connection to endpoint for channel + const H323Capability & capability, /// Capability channel is using + Directions direction, /// Direction of channel + unsigned sessionID /// Session ID for channel + ); + /**Create a new channel. + */ + MyH323_ExternalRTPChannel( + H323Connection & connection, /// Connection to endpoint for channel + const H323Capability & capability, /// Capability channel is using + Directions direction, /// Direction of channel + unsigned sessionID, /// Session ID for channel + const H323TransportAddress & data, /// Data address + const H323TransportAddress & control/// Control address + ); + /**Create a new channel. + */ + MyH323_ExternalRTPChannel( + H323Connection & connection, /// Connection to endpoint for channel + const H323Capability & capability, /// Capability channel is using + Directions direction, /// Direction of channel + unsigned sessionID, /// Session ID for channel + const PIPSocket::Address & ip, /// IP address of media server + WORD dataPort /// Data port (control is dataPort+1) + ); + //@} +// BOOL OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param); + BOOL Start(void); }; @@ -348,5 +393,3 @@ class ClearCallThread : public PThread { protected: PString token; }; - - diff --git a/channels/h323/chan_h323.h b/channels/h323/chan_h323.h index c330dd883a..912b081520 100755 --- a/channels/h323/chan_h323.h +++ b/channels/h323/chan_h323.h @@ -28,7 +28,23 @@ #include -static struct sockaddr_in bindaddr; +//static struct sockaddr_in bindaddr; + +/** call_option struct is filled from the + PBX application and passed through make_call + function*/ +typedef struct call_options { + char *callerid; + int noFastStart; + int noH245Tunnelling; + int noSilenceSuppression; + int progress_setup; + int progress_alert; + int progress_audio; + unsigned int port; +} call_options_t; + +extern call_options_t global_options; /* structure to hold the valid asterisk users */ struct oh323_user { @@ -38,15 +54,13 @@ struct oh323_user { char callerid[80]; char accountcode[20]; int amaflags; - int noFastStart; - int noH245Tunneling; - int noSilenceSuppression; int inUse; int incominglimit; int bridge; int nat; int dtmfmode; int host; + call_options_t call_options; struct ast_ha *ha; struct sockaddr_in addr; struct oh323_user *next; @@ -57,9 +71,6 @@ struct oh323_user { struct oh323_peer { char name[80]; char context[80]; - int noFastStart; - int noH245Tunneling; - int noSilenceSuppression; int inUse; int outgoinglimit; int bridge; @@ -67,6 +78,7 @@ struct oh323_peer { int dtmfmode; struct sockaddr_in addr; int delme; + call_options_t call_options; struct oh323_peer *next; }; @@ -81,17 +93,6 @@ struct oh323_alias { struct oh323_alias *next; }; -/** call_option struct is filled from the - PBX application and passed through make_call - function*/ -typedef struct call_options { - char *callerid; - int noFastStart; - int noH245Tunnelling; - int noSilenceSuppression; - unsigned int port; -} call_options_t; - /** call_details struct call detail records to asterisk for processing and used for matching up asterisk channels to acutal h.323 connections */ @@ -103,6 +104,7 @@ typedef struct call_details { const char *call_dest_alias; const char *call_source_e164; const char *call_dest_e164; + const char *call_redir_e164; const char *sourceIp; } call_details_t; @@ -123,7 +125,7 @@ on_connection_cb on_create_connection; /* This is a callback prototype function, called upon an incoming call happens. */ -typedef int (*setup_incoming_cb)(call_details_t); +typedef call_options_t *(*setup_incoming_cb)(call_details_t); setup_incoming_cb on_incoming_call; /* This is a callback prototype function, called upon @@ -132,8 +134,10 @@ typedef int (*setup_outbound_cb)(call_details_t); setup_outbound_cb on_outgoing_call; /* This is a callback prototype function, called when the openh323 - OnStartLogicalChannel is invoked. */ -typedef void (*start_logchan_cb)(unsigned int, const char *, int); + OnStartLogicalChannel is invoked. + 2 more arguments - direction and payload type. + */ +typedef void (*start_logchan_cb)(unsigned int, const char *, int, int, int); start_logchan_cb on_start_logical_channel; /* This is a callback protoype function, called when the openh323 @@ -146,15 +150,33 @@ con_established_cb on_connection_established; typedef void (*clear_con_cb)(call_details_t); clear_con_cb on_connection_cleared; +/* This is a callback prototype function, called when the openh323 + OnReceivedAckPDU is invoked. */ +typedef void (*setup_rtp_cb)(unsigned int, const char *, int); +setup_rtp_cb on_setup_rtp_peer; + +typedef int (*progress_cb)(unsigned, int); +progress_cb on_progress; + /* debug flag */ int h323debug; #define H323_DTMF_RFC2833 (1 << 0) #define H323_DTMF_INBAND (1 << 1) +/* Required to declare global variables from chan_h323.c */ +#ifndef BOOL +#define BOOL int +#endif + #ifdef __cplusplus extern "C" { #endif + + /* chan_h323 global parameters */ + extern BOOL noFastStart; + extern BOOL noH245Tunnelling; + extern BOOL noSilenceSuppression; void h323_gk_urq(void); void h323_end_point_create(void); @@ -165,13 +187,13 @@ extern "C" { /* callback function handler*/ void h323_callback_register(setup_incoming_cb, - setup_outbound_cb, - on_connection_cb, - start_logchan_cb, - clear_con_cb, - con_established_cb, - send_digit_cb); - + setup_outbound_cb, + on_connection_cb, + start_logchan_cb, + clear_con_cb, + con_established_cb, + send_digit_cb, + progress_cb); int h323_set_capability(int, int); int h323_set_alias(struct oh323_alias *); @@ -188,7 +210,7 @@ extern "C" { void h323_send_tone(const char *call_token, char tone); /* H323 create and destroy sessions */ - int h323_make_call(char *host, call_details_t *cd, call_options_t); + int h323_make_call(char *host, call_details_t *cd, call_options_t *call_options); int h323_clear_call(const char *); int h323_answering_call(const char *token, int); diff --git a/channels/h323/h323.conf.sample b/channels/h323/h323.conf.sample index 811647a08f..8ddf73dae1 100755 --- a/channels/h323/h323.conf.sample +++ b/channels/h323/h323.conf.sample @@ -52,6 +52,13 @@ allow=gsm ; Always allow GSM, it's cool :) ; use user authentication at all. ; ;context=default +;noFastStart = no +;noH245Tunneling = no +;noSilenceSuppression = yes +;progress_setup = 3 +;progress_alert = 8 +;progress_audio = yes + ; ; H.323 Alias definitions ;