diff --git a/channels/chan_h323.c b/channels/chan_h323.c index 5b92834c58..a3a22e8c7a 100755 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -81,6 +81,8 @@ chan_ringing_cb on_chan_ringing; con_established_cb on_connection_established; clear_con_cb on_connection_cleared; answer_call_cb on_answer_call; +progress_cb on_progress; +rfc2833_cb on_set_rfc2833_payload; /* global debug flag */ int h323debug; @@ -91,6 +93,7 @@ static char *desc = "The NuFone Network's Open H.323 Channel Driver"; static char *tdesc = "The NuFone Network's Open H.323 Channel Driver"; static char *config = "h323.conf"; static char default_context[AST_MAX_EXTENSION] = "default"; +static struct sockaddr_in bindaddr; /** H.323 configuration values */ static int h323_signalling_port = 1720; @@ -99,9 +102,6 @@ static int gatekeeper_disable = 1; static int gatekeeper_discover = 0; static int usingGk = 0; static int gkroute = 0; -static int noFastStart = 0; -static int noH245Tunneling = 0; -static int noSilenceSuppression = 0; /* Assume we can native bridge by default */ static int bridging = 1; /* Find user by alias (h.323 id) is default, alternative is the incomming call's source IP address*/ @@ -111,6 +111,8 @@ static int tos = 0; static int dtmfmode = H323_DTMF_RFC2833; static char secret[50]; +static call_options_t global_options; + /** Private structure of a OpenH323 channel */ struct oh323_pvt { ast_mutex_t lock; /* Channel private lock */ @@ -261,7 +263,7 @@ static struct oh323_user *build_user(char *name, struct ast_variable *v) if (user) { memset(user, 0, sizeof(struct oh323_user)); strncpy(user->name, name, sizeof(user->name) - 1); - + user->options.dtmfcodec = 101; /* set a native brigding default value */ user->bridge = bridging; /* and default context */ @@ -274,17 +276,39 @@ 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->options.noFastStart = ast_true(v->value); } else if (!strcasecmp(v->name, "noH245Tunneling")) { - user->noH245Tunneling = ast_true(v->value); + user->options.noH245Tunneling = ast_true(v->value); } else if (!strcasecmp(v->name, "noSilenceSuppression")) { - user->noSilenceSuppression = ast_true(v->value); + user->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->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, "Invalud value %d for progress_alert at line %d, assuming 0\n", progress_alert, v->lineno); + progress_alert = 0; + } + user->options.progress_alert = progress_alert; + } else if (!strcasecmp(v->name, "progress_audio")) { + user->options.progress_audio = ast_true(v->value); + } else if (!strcasecmp(v->name, "dtmfcodec")) { + user->options.dtmfcodec = atoi(v->value); } else if (!strcasecmp(v->name, "host")) { if (!strcasecmp(v->value, "dynamic")) { ast_log(LOG_ERROR, "A dynamic host on a type=user does not make any sense\n"); @@ -354,6 +378,8 @@ static struct oh323_peer *build_peer(char *name, struct ast_variable *v) peer->ha = NULL; peer->addr.sin_family = AF_INET; peer->capability = capability; + peer->options.dtmfcodec = 101; + peer->dtmfmode = H323_DTMF_RFC2833; while(v) { if (!strcasecmp(v->name, "bridge")) { @@ -361,11 +387,33 @@ static struct oh323_peer *build_peer(char *name, struct ast_variable *v) } else if (!strcasecmp(v->name, "nat")) { peer->nat = ast_true(v->value); } else if (!strcasecmp(v->name, "noFastStart")) { - peer->noFastStart = ast_true(v->value); + peer->options.noFastStart = ast_true(v->value); } else if (!strcasecmp(v->name, "noH245Tunneling")) { - peer->noH245Tunneling = ast_true(v->value); + peer->options.noH245Tunneling = ast_true(v->value); } else if (!strcasecmp(v->name, "noSilenceSuppression")) { - peer->noSilenceSuppression = ast_true(v->value); + peer->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->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->options.progress_alert = progress_alert; + } else if (!strcasecmp(v->name, "progress_audio")) { + peer->options.progress_audio = ast_true(v->value); + } else if (!strcasecmp(v->name, "dtmfcodec")) { + peer->options.dtmfcodec = atoi(v->value); } else if (!strcasecmp(v->name, "dtmfmode")) { if (!strcasecmp(v->value, "inband")) { peer->dtmfmode = H323_DTMF_INBAND; @@ -415,6 +463,7 @@ static struct oh323_peer *build_peer(char *name, struct ast_variable *v) */ static int oh323_digit(struct ast_channel *c, char digit) { + ast_log(LOG_DEBUG, "Sending %c...\n", digit); struct oh323_pvt *p = (struct oh323_pvt *) c->pvt->pvt; if (p && p->rtp && (p->dtmfmode & H323_DTMF_RFC2833)) { ast_rtp_senddigit(p->rtp, digit); @@ -438,8 +487,6 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout) char addr[INET_ADDRSTRLEN]; char called_addr[INET_ADDRSTRLEN]; - ast_log(LOG_DEBUG, "Dest is %s\n", dest); - if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) { ast_log(LOG_WARNING, "Line is already in use (%s)\n", c->name); return -1; @@ -448,9 +495,6 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout) memset(addr, 0, sizeof(addr)); if (usingGk) { memcpy(addr, dest, strlen(addr)); - pvt->options.noFastStart = noFastStart; - pvt->options.noH245Tunneling = noH245Tunneling; - pvt->options.noSilenceSuppression = noSilenceSuppression; pvt->options.port = h323_signalling_port; } else { ast_inet_ntoa(addr, sizeof(addr), pvt->sa.sin_addr); @@ -464,8 +508,8 @@ static int oh323_call(struct ast_channel *c, char *dest, int timeout) } else { sprintf(called_addr, "%s:%d",addr, pvt->options.port); } - ast_log(LOG_DEBUG, "Placing outgoing call to %s\n", dest); - res = h323_make_call(dest, &(pvt->cd), pvt->options); + ast_log(LOG_DEBUG, "Placing outgoing call to %s, %d\n", called_addr, pvt->options.dtmfcodec); + res = h323_make_call(called_addr, &(pvt->cd), &pvt->options); if (res) { ast_log(LOG_NOTICE, "h323_make_call failed(%s)\n", c->name); return -1; @@ -518,7 +562,7 @@ static int oh323_hangup(struct ast_channel *c) /* Start the process if it's not already started */ if (!pvt->alreadygone) { - if (h323_clear_call((pvt->cd).call_token)) { + if (h323_clear_call((pvt->cd).call_token, c->hangupcause)) { ast_log(LOG_DEBUG, "ClearCall failed.\n"); } pvt->needdestroy = 1; @@ -617,13 +661,15 @@ static int oh323_indicate(struct ast_channel *c, int condition) { struct oh323_pvt *pvt = (struct oh323_pvt *) c->pvt->pvt; - + + ast_log(LOG_DEBUG, "OH323: Indicating %d on %s\n", condition, pvt->cd.call_token); + switch(condition) { case AST_CONTROL_RINGING: if (c->_state == AST_STATE_RING || c->_state == AST_STATE_RINGING) { h323_send_alerting(pvt->cd.call_token); break; - } + } return -1; case AST_CONTROL_PROGRESS: if (c->_state != AST_STATE_UP) { @@ -656,7 +702,7 @@ static int oh323_indicate(struct ast_channel *c, int condition) return -1; ast_mutex_unlock(&pvt->lock); } - return 0; + return -1; } static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) @@ -681,6 +727,11 @@ static struct ast_channel *oh323_new(struct oh323_pvt *pvt, int state, const cha /* Don't hold a oh323_pvt lock while we allocate a chanel */ ast_mutex_unlock(&pvt->lock); ch = ast_channel_alloc(1); + /* Update usage counter */ + ast_mutex_lock(&usecnt_lock); + usecnt++; + ast_mutex_unlock(&usecnt_lock); + ast_update_use_count(); ast_mutex_lock(&pvt->lock); if (ch) { snprintf(ch->name, sizeof(ch->name), "H323/%s", host); @@ -720,12 +771,6 @@ static struct ast_channel *oh323_new(struct oh323_pvt *pvt, int state, const cha /* Set the owner of this channel */ pvt->owner = ch; - /* Update usage counter */ - ast_mutex_lock(&usecnt_lock); - usecnt++; - ast_mutex_unlock(&usecnt_lock); - ast_update_use_count(); - strncpy(ch->context, pvt->context, sizeof(ch->context) - 1); strncpy(ch->exten, pvt->exten, sizeof(ch->exten) - 1); ch->priority = 1; @@ -758,6 +803,7 @@ static struct ast_channel *oh323_new(struct oh323_pvt *pvt, int state, const cha } else { ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); } + ast_mutex_unlock(&pvt->lock); return ch; } @@ -911,10 +957,8 @@ static int create_addr(struct oh323_pvt *pvt, char *opeer) ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->nat); ast_rtp_setnat(pvt->rtp, pvt->nat); } - pvt->options.noFastStart = p->noFastStart; - pvt->options.noH245Tunneling = p->noH245Tunneling; - pvt->options.noSilenceSuppression = p->noSilenceSuppression; - if (pvt->dtmfmode) { + memcpy(&pvt->options, &p->options, sizeof(pvt->options)); + if (p->dtmfmode) { pvt->dtmfmode = p->dtmfmode; if (pvt->dtmfmode & H323_DTMF_RFC2833) { pvt->nonCodecCapability |= AST_RTP_DTMF; @@ -937,6 +981,7 @@ static int create_addr(struct oh323_pvt *pvt, char *opeer) } hp = ast_gethostbyname(hostn, &ahp); if (hp) { + memcpy(&pvt->options, &global_options, sizeof(pvt->options)); memcpy(&pvt->sa.sin_addr, hp->h_addr, sizeof(pvt->sa.sin_addr)); pvt->sa.sin_port = htons(portno); return 0; @@ -950,7 +995,7 @@ static int create_addr(struct oh323_pvt *pvt, char *opeer) return 0; } } -static struct ast_channel *oh323_request(const char *type, int format, void *data) +static struct ast_channel *oh323_request(const char *type, int format, void *data, int *cause) { int oldformat; struct oh323_pvt *pvt; @@ -1000,6 +1045,7 @@ static struct ast_channel *oh323_request(const char *type, int format, void *dat return NULL; } } + /* pass on our capabilites to the H.323 stack */ ast_mutex_lock(&caplock); h323_set_capability(pvt->capability, pvt->dtmfmode); @@ -1089,6 +1135,8 @@ struct rtp_info *external_rtp_create(unsigned call_reference, const char * token return info; } +int progress(unsigned call_reference, const char *token, int inband); + /** * Call-back function passing remote ip/port information from H.323 to asterisk * @@ -1110,6 +1158,10 @@ void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int rem them.sin_addr.s_addr = inet_addr(remoteIp); them.sin_port = htons(remotePort); ast_rtp_set_peer(pvt->rtp, &them); + + if (pvt->options.progress_audio) { + progress(call_reference, token, 1); + } return; } @@ -1139,16 +1191,38 @@ void connection_made(unsigned call_reference, const char *token) return; } +int progress(unsigned call_reference, const char *token, 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, token); + + if (!p) { + ast_log(LOG_ERROR, "Private structure not found in progress.\n"); + return -1; + } + if (!p->owner) { + ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n"); + return -1; + } + + ast_queue_control(p->owner, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING)); + + return 0; +} + /** * Call-back function for incoming calls * * 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 *pvt = NULL; struct oh323_user *user = NULL; struct oh323_alias *alias = NULL; + call_options_t *call_options = NULL; char iabuf[INET_ADDRSTRLEN]; /* allocate the call*/ @@ -1156,7 +1230,7 @@ int setup_incoming_call(call_details_t cd) if (!pvt) { 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 */ @@ -1185,7 +1259,7 @@ int setup_incoming_call(call_details_t cd) alias = find_alias(cd.call_dest_alias); if (!alias) { ast_log(LOG_ERROR, "Call for %s rejected, alias not found\n", cd.call_dest_alias); - return 0; + return NULL; } strncpy(pvt->exten, alias->name, sizeof(pvt->exten) - 1); strncpy(pvt->context, alias->context, sizeof(pvt->context) - 1); @@ -1202,17 +1276,18 @@ int setup_incoming_call(call_details_t cd) } if (ast_strlen_zero(default_context)) { ast_log(LOG_ERROR, "Call from '%s' rejected due to no default context\n", pvt->cd.call_source_aliases); - return 0; + return NULL; } strncpy(pvt->context, default_context, sizeof(pvt->context) - 1); ast_log(LOG_DEBUG, "Sending %s to context [%s]\n", cd.call_source_aliases, pvt->context); + memset(&pvt->options, 0, sizeof(pvt->options)); } else { if (user->host) { if (strcasecmp(cd.sourceIp, ast_inet_ntoa(iabuf, sizeof(iabuf), user->addr.sin_addr))){ if (ast_strlen_zero(user->context)) { if (ast_strlen_zero(default_context)) { ast_log(LOG_ERROR, "Call from '%s' rejected due to non-matching IP address (%s) and no default context\n", user->name, cd.sourceIp); - return 0; + return NULL; } strncpy(pvt->context, default_context, sizeof(pvt->context) - 1); } else { @@ -1238,10 +1313,11 @@ int setup_incoming_call(call_details_t cd) if (user->amaflags) { pvt->amaflags = user->amaflags; } + call_options = &user->options; } } exit: - return 1; + return call_options; } /** @@ -1357,6 +1433,21 @@ void cleanup_connection(call_details_t cd) return; } +void set_dtmf_payload(unsigned call_reference, const char *token, int payload) +{ + struct oh323_pvt *pvt = NULL; + + pvt = find_call(call_reference, token); + if (!pvt) { + return; + } + ast_mutex_lock(&pvt->lock); + if (pvt->rtp) { + ast_rtp_set_rtpmap_type(pvt->rtp, payload, "audio", "telephone-event"); + } + ast_mutex_unlock(&pvt->lock); +} + static void *do_monitor(void *data) { int res; @@ -1599,6 +1690,8 @@ int reload_config(void) h323debug = 0; dtmfmode = H323_DTMF_RFC2833; memset(&bindaddr, 0, sizeof(bindaddr)); + memset(&global_options, 0, sizeof(global_options)); + global_options.dtmfcodec = 101; v = ast_variable_browse(cfg, "general"); while(v) { /* Create the interface list */ @@ -1667,14 +1760,18 @@ int reload_config(void) ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value); dtmfmode = H323_DTMF_RFC2833; } + } else if (!strcasecmp(v->name, "dtmfcodec")) { + global_options.dtmfcodec = atoi(v->value); } else if (!strcasecmp(v->name, "UserByAlias")) { userbyalias = ast_true(v->value); } else if (!strcasecmp(v->name, "bridge")) { bridging = ast_true(v->value); } else if (!strcasecmp(v->name, "noFastStart")) { - noFastStart = ast_true(v->value); + global_options.noFastStart = ast_true(v->value); } else if (!strcasecmp(v->name, "noH245Tunneling")) { - noH245Tunneling = ast_true(v->value); + global_options.noH245Tunneling = ast_true(v->value); + } else if (!strcasecmp(v->name, "noSilenceSuppression")) { + global_options.noSilenceSuppression = ast_true(v->value); } v = v->next; } @@ -1948,7 +2045,9 @@ int load_module() chan_ringing, connection_made, send_digit, - answer_call); + answer_call, + progress, + set_dtmf_payload); /* start the h.323 listener */ if (h323_start_listener(h323_signalling_port, bindaddr)) { ast_log(LOG_ERROR, "Unable to create H323 listener.\n"); diff --git a/channels/h323/ast_h323.cpp b/channels/h323/ast_h323.cpp index 6abfff9324..616b7381b6 100755 --- a/channels/h323/ast_h323.cpp +++ b/channels/h323/ast_h323.cpp @@ -156,7 +156,7 @@ H323Codec * H323_G7231Capability::CreateCodec(H323Codec::Direction direction) co } AST_G729Capability::AST_G729Capability() - : H323AudioCapability(24, 6) + : H323AudioCapability(24, 2) { } @@ -213,7 +213,7 @@ H323Codec * AST_G729ACapability::CreateCodec(H323Codec::Direction direction) con * transport = ip. * port = 1720. */ -int MyH323EndPoint::MakeCall(const PString & dest, PString & token, unsigned int *callReference, char *cid_name, char *cid_num) +int MyH323EndPoint::MakeCall(const PString & dest, PString & token, unsigned int *callReference, call_options_t *opts) { PString fullAddress; MyH323Connection * connection; @@ -237,20 +237,23 @@ int MyH323EndPoint::MakeCall(const PString & dest, PString & token, unsigned int return 1; } *callReference = connection->GetCallReference(); - if (cid_name) { + if (opts->cid_name) { localAliasNames.RemoveAll(); - connection->SetLocalPartyName(PString(cid_name)); - if (cid_num) { - localAliasNames.AppendString(PString(cid_num)); + connection->SetLocalPartyName(PString(opts->cid_name)); + if (opts->cid_num) { + localAliasNames.AppendString(PString(opts->cid_num)); } - } else if (cid_num) { + } else if (opts->cid_num) { localAliasNames.RemoveAll(); - connection->SetLocalPartyName(PString(cid_num)); + connection->SetLocalPartyName(PString(opts->cid_num)); } + connection->dtmfCodec = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec; + if (h323debug) { cout << "\t-- " << GetLocalUserName() << " is calling host " << fullAddress << endl; cout << "\t--" << "Call token is " << (const char *)token << endl; cout << "\t-- Call reference is " << *callReference << endl; + cout << "\t-- DTMF Payload is " << connection->dtmfCodec << endl; } connection->Unlock(); return 0; @@ -259,6 +262,12 @@ int MyH323EndPoint::MakeCall(const PString & dest, PString & token, unsigned int void MyH323EndPoint::SetEndpointTypeInfo( H225_EndpointType & info ) const { H323EndPoint::SetEndpointTypeInfo(info); + + 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]; @@ -280,12 +289,20 @@ H323Capabilities MyH323EndPoint::GetCapabilities(void) return capabilities; } +BOOL MyH323EndPoint::ClearCall(const PString & token, H323Connection::CallEndReason reason) +{ + if (h323debug) { + cout << "\t-- ClearCall: Request to clear call with token " << token << ", cause " << reason << endl; + } + return H323EndPoint::ClearCall(token, reason); +} + BOOL MyH323EndPoint::ClearCall(const PString & token) { if (h323debug) { cout << "\t-- ClearCall: Request to clear call with token " << token << endl; } - return H323EndPoint::ClearCall(token); + return ClearCall(token, H323Connection::EndedByLocalUser); } void MyH323EndPoint::SendUserTone(const PString &token, char tone) @@ -506,29 +523,99 @@ MyH323Connection::~MyH323Connection() return; } +BOOL MyH323Connection::OnReceivedProgress(const H323SignalPDU &pdu) +{ + BOOL isInband; + unsigned pi; + + if (!H323Connection::OnReceivedProgress(pdu)) { + return FALSE; + } + + if (!pdu.GetQ931().GetProgressIndicator(pi)) + pi = 0; + if (h323debug) { + cout << "\t- Progress Indicator: " << pi << endl; + } + + switch(pi) { + case Q931::ProgressNotEndToEndISDN: + case Q931::ProgressInbandInformationAvailable: + isInband = TRUE; + break; + default: + isInband = FALSE; + } + on_progress(GetCallReference(), (const char *)GetCallToken(), isInband); + + return TRUE; +} + H323Connection::AnswerCallResponse MyH323Connection::OnAnswerCall(const PString & caller, - const H323SignalPDU & /*setupPDU*/, + const H323SignalPDU & setupPDU, H323SignalPDU & /*connectPDU*/) { + unsigned pi; - if (h323debug) { + if (h323debug) { cout << "\t=-= In OnAnswerCall for call " << GetCallReference() << endl; } + + if (!setupPDU.GetQ931().GetProgressIndicator(pi)) { + pi = 0; + } + if (h323debug) { + cout << "\t\t- Progress Indicator: " << pi << endl; + } + if (progressAlert) { + pi = progressAlert; + } else if (pi == Q931::ProgressOriginNotISDN) { + pi = Q931::ProgressInbandInformationAvailable; + } + if (pi) { + alertingPDU->GetQ931().SetProgressIndicator(pi); + } + if (h323debug) { + cout << "\t\t- Inserting PI of " << pi << " into ALERTING message" << endl; + } + if (!on_answer_call(GetCallReference(), (const char *)GetCallToken())) { return H323Connection::AnswerCallDenied; } /* The call will be answered later with "AnsweringCall()" function. */ - return H323Connection::AnswerCallDeferred; + return H323Connection::AnswerCallDeferredWithMedia; } -BOOL MyH323Connection::OnAlerting(const H323SignalPDU & /*alertingPDU*/, const PString & username) +BOOL MyH323Connection::OnAlerting(const H323SignalPDU & alertingPDU, const PString & username) { if (h323debug) { cout << "\t=-= In OnAlerting for call " << GetCallReference() << ": sessionId=" << sessionId << endl; cout << "\t-- Ringing phone for \"" << username << "\"" << endl; - } + } + + if (on_progress) { + BOOL isInband; + unsigned alertingPI; + + if (!alertingPDU.GetQ931().GetProgressIndicator(alertingPI)) { + alertingPI = 0; + } + if (h323debug) { + cout << "\t\t- Progress Indicator: " << alertingPI << endl; + } + + switch(alertingPI) { + case Q931::ProgressNotEndToEndISDN: + case Q931::ProgressInbandInformationAvailable: + isInband = TRUE; + break; + default: + isInband = FALSE; + } + on_progress(GetCallReference(), (const char *)GetCallToken(), isInband); + } on_chan_ringing(GetCallReference(), (const char *)GetCallToken() ); return TRUE; } @@ -588,7 +675,7 @@ BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU) cd.sourceIp = strdup((const char *)Ip.AsString()); /* Notify Asterisk of the request */ - int res = on_incoming_call(cd); + call_options_t *res = on_incoming_call(cd); if (!res) { if (h323debug) { @@ -596,6 +683,12 @@ BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU) } return FALSE; } + + progressSetup = res->progress_setup; + progressAlert = res->progress_alert; + dtmfCodec = (RTP_DataFrame::PayloadTypes)res->dtmfcodec; + + return H323Connection::OnReceivedSignalSetup(setupPDU); } @@ -646,6 +739,10 @@ BOOL MyH323Connection::OnSendSignalSetup(H323SignalPDU & setupPDU) } return FALSE; } + + if (progressSetup) { + setupPDU.GetQ931().SetProgressIndicator(progressSetup); + } return H323Connection::OnSendSignalSetup(setupPDU); } @@ -711,6 +808,50 @@ void MyH323Connection::OnUserInputString(const PString &value) } } +void MyH323Connection::OnSendCapabilitySet(H245_TerminalCapabilitySet & pdu) +{ + PINDEX i; + + H323Connection::OnSendCapabilitySet(pdu); + + H245_ArrayOf_CapabilityTableEntry & tables = pdu.m_capabilityTable; + for(i = 0; i < tables.GetSize(); i++) + { + H245_CapabilityTableEntry & entry = tables[i]; + if (entry.HasOptionalField(H245_CapabilityTableEntry::e_capability)) { + H245_Capability & cap = entry.m_capability; + if (cap.GetTag() == H245_Capability::e_receiveRTPAudioTelephonyEventCapability) { + H245_AudioTelephonyEventCapability & atec = cap; + atec.m_dynamicRTPPayloadType = dtmfCodec; + on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec); + if (h323debug) { + cout << "\t-- Transmitting RFC2833 on payload " << + atec.m_dynamicRTPPayloadType << endl; + } + } + } + } +} + +BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps, + const H245_MultiplexCapability * muxCap, + H245_TerminalCapabilitySetReject & reject) +{ + if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) { + return FALSE; + } + + const H323Capability * cap = remoteCaps.FindCapability(H323_UserInputCapability::SubTypeNames[H323_UserInputCapability::SignalToneRFC2833]); + if (cap != NULL) { + RTP_DataFrame::PayloadTypes pt = ((H323_UserInputCapability*)cap)->GetPayloadType(); + on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt); + if (h323debug) { + cout << "\t-- Inbound RFC2833 on payload " << pt << endl; + } + } + return TRUE; +} + H323Channel * MyH323Connection::CreateRealTimeLogicalChannel(const H323Capability & capability, H323Channel::Directions dir, unsigned sessionID, @@ -783,7 +924,7 @@ BOOL MyH323_ExternalRTPChannel::Start(void) } /* Collect the remote information */ - GetRemoteAddress(remoteIpAddr, remotePort); + H323_ExternalRTPChannel::GetRemoteAddress(remoteIpAddr, remotePort); if (h323debug) { cout << "\t\tExternal RTP Session Starting" << endl; @@ -800,6 +941,28 @@ BOOL MyH323_ExternalRTPChannel::Start(void) return TRUE; } +BOOL MyH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param) +{ + PIPSocket::Address remoteIpAddress; + WORD remotePort; + + if (h323debug) { + cout << " MyH323_ExternalRTPChannel::OnReceivedAckPDU" << endl; + } + + if (H323_ExternalRTPChannel::OnReceivedAckPDU(param)) { + GetRemoteAddress(remoteIpAddress, remotePort); + if (h323debug) { + cout << " -- remoteIpAddress: " << remoteIpAddress << endl; + cout << " -- remotePort: " << remotePort << endl; + } + on_start_rtp_channel(connection.GetCallReference(), (const char *)remoteIpAddress.AsString(), + remotePort, (const char *)connection.GetCallToken()); + return TRUE; + } + return FALSE; +} + /** IMPLEMENTATION OF C FUNCTIONS */ /** @@ -859,7 +1022,9 @@ void h323_callback_register(setup_incoming_cb ifunc, chan_ringing_cb rfunc, con_established_cb efunc, send_digit_cb dfunc, - answer_call_cb acfunc) + answer_call_cb acfunc, + progress_cb pgfunc, + rfc2833_cb dtmffunc) { on_incoming_call = ifunc; on_outgoing_call = sfunc; @@ -870,6 +1035,8 @@ void h323_callback_register(setup_incoming_cb ifunc, on_connection_established = efunc; on_send_digit = dfunc; on_answer_call = acfunc; + on_progress = pgfunc; + on_set_rfc2833_payload = dtmffunc; } /** @@ -879,8 +1046,9 @@ int h323_set_capability(int cap, int dtmfMode) { H323Capabilities oldcaps; PStringArray codecs; - int g711Frames = 30; + int g711Frames = 20; // int gsmFrames = 4; + PINDEX lastcap = -1; /* last common capability index */ if (!h323_end_point_exist()) { cout << " ERROR: [h323_set_capablity] No Endpoint, this is bad" << endl; @@ -894,12 +1062,6 @@ int h323_set_capability(int cap, int dtmfMode) } endPoint->RemoveCapabilities(codecs); - mode = dtmfMode; - if (dtmfMode == H323_DTMF_INBAND) { - endPoint->SetSendUserInputMode(H323Connection::SendUserInputAsTone); - } else { - endPoint->SetSendUserInputMode(H323Connection::SendUserInputAsInlineRFC2833); - } #if 0 if (cap & AST_FORMAT_SPEEX) { /* Not real sure if Asterisk acutally supports all @@ -916,32 +1078,45 @@ int h323_set_capability(int cap, int dtmfMode) 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); + lastcap = endPoint->SetCapability(0, 0, g729aCap = new AST_G729ACapability); + lastcap = 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); + lastcap = endPoint->SetCapability(0, 0, g7231Cap = new H323_G7231Capability); } #if 0 if (cap & AST_FORMAT_GSM) { H323_GSM0610Capability *gsmCap; - endPoint->SetCapability(0, 0, gsmCap = new H323_GSM0610Capability); + lastcap = endPoint->SetCapability(0, 0, gsmCap = new H323_GSM0610Capability); gsmCap->SetTxFramesInPacket(gsmFrames); } #endif if (cap & AST_FORMAT_ULAW) { H323_G711Capability *g711uCap; - endPoint->SetCapability(0, 0, g711uCap = new H323_G711Capability(H323_G711Capability::muLaw)); + lastcap = 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)); + lastcap = endPoint->SetCapability(0, 0, g711aCap = new H323_G711Capability(H323_G711Capability::ALaw)); g711aCap->SetTxFramesInPacket(g711Frames); - } + } + + lastcap++; + lastcap = endPoint->SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245)); + + lastcap++; + mode = dtmfMode; + if (dtmfMode == H323_DTMF_INBAND) { + endPoint->SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245)); + endPoint->SetSendUserInputMode(H323Connection::SendUserInputAsTone); + } else { + endPoint->SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833)); + endPoint->SetSendUserInputMode(H323Connection::SendUserInputAsInlineRFC2833); + } if (h323debug) { cout << "Allowed Codecs:\n\t" << setprecision(2) << endPoint->GetCapabilities() << endl; @@ -1086,7 +1261,7 @@ void h323_send_tone(const char *call_token, char tone) /** Make a call to the remote endpoint. */ -int h323_make_call(char *dest, call_details_t *cd, call_options_t call_options) +int h323_make_call(char *dest, call_details_t *cd, call_options_t *call_options) { int res; PString token; @@ -1096,17 +1271,23 @@ int h323_make_call(char *dest, call_details_t *cd, call_options_t call_options) return 1; } - res = endPoint->MakeCall(host, token, &cd->call_reference, call_options.cid_name, call_options.cid_num); + res = endPoint->MakeCall(host, token, &cd->call_reference, call_options); memcpy((char *)(cd->call_token), (const unsigned char *)token, token.GetLength()); return res; }; -int h323_clear_call(const char *call_token) +int h323_clear_call(const char *call_token, int cause) { + H225_ReleaseCompleteReason dummy; + H323Connection::CallEndReason r = H323Connection::NumCallEndReasons; + if (!h323_end_point_exist()) { return 1; } - endPoint->ClearCall(PString(call_token)); + + r = H323TranslateToCallEndReason((Q931::CauseValues)(cause), dummy); + + endPoint->ClearCall(PString(call_token), r); return 0; }; @@ -1184,7 +1365,7 @@ int h323_soft_hangup(const char *data) { PString token(data); BOOL result; - + cout << "Soft hangup" << endl; result = endPoint->ClearCall(token); return result; } diff --git a/channels/h323/ast_h323.h b/channels/h323/ast_h323.h index f9a454b6f5..906acd65d1 100755 --- a/channels/h323/ast_h323.h +++ b/channels/h323/ast_h323.h @@ -128,7 +128,8 @@ class MyH323EndPoint : public H323EndPoint { PCLASSINFO(MyH323EndPoint, H323EndPoint); public: - int MakeCall(const PString &, PString &, unsigned int *, char *, char *); + int MakeCall(const PString &, PString &, unsigned int *, call_options_t *opts); + BOOL ClearCall(const PString &, H323Connection::CallEndReason reason); BOOL ClearCall(const PString &); void OnClosedLogicalChannel(H323Connection &, const H323Channel &); @@ -170,6 +171,10 @@ class MyH323Connection : public H323Connection { void SendUserInputTone(char, unsigned); void OnUserInputTone(char, unsigned, unsigned, unsigned); void OnUserInputString(const PString &value); + BOOL OnReceivedProgress(const H323SignalPDU &); + void OnSendCapabilitySet(H245_TerminalCapabilitySet &); + BOOL OnReceivedCapabilitySet(const H323Capabilities &, const H245_MultiplexCapability *, + H245_TerminalCapabilitySetReject &); PString sourceAliases; PString destAliases; @@ -178,6 +183,11 @@ class MyH323Connection : public H323Connection { WORD sessionId; BOOL bridging; + + unsigned progressSetup; + unsigned progressAlert; + + RTP_DataFrame::PayloadTypes dtmfCodec; }; class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel { @@ -192,9 +202,10 @@ class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel { unsigned sessionID); ~MyH323_ExternalRTPChannel(); - + /* Overrides */ BOOL Start(void); + BOOL OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param); protected: BYTE payloadCode; diff --git a/channels/h323/chan_h323.h b/channels/h323/chan_h323.h index 0005b421ce..995b81896d 100755 --- a/channels/h323/chan_h323.h +++ b/channels/h323/chan_h323.h @@ -28,7 +28,20 @@ #include -static struct sockaddr_in bindaddr; +/** call_option struct holds various bits + * of information for each call */ +typedef struct call_options { + char *cid_num; + char *cid_name; + int noFastStart; + int noH245Tunneling; + int noSilenceSuppression; + unsigned int port; + int progress_setup; + int progress_alert; + int progress_audio; + int dtmfcodec; +} call_options_t; /* structure to hold the valid asterisk users */ struct oh323_user { @@ -38,13 +51,11 @@ struct oh323_user { char callerid[80]; char accountcode[20]; int amaflags; - int noFastStart; - int noH245Tunneling; - int noSilenceSuppression; int bridge; int nat; int dtmfmode; int host; + call_options_t options; struct ast_ha *ha; struct sockaddr_in addr; struct oh323_user *next; @@ -56,15 +67,13 @@ struct oh323_peer { char name[80]; char mailbox[80]; int capability; - int noFastStart; - int noH245Tunneling; - int noSilenceSuppression; int bridge; int nat; int dtmfmode; int delme; struct sockaddr_in addr; struct ast_ha *ha; + call_options_t options; struct oh323_peer *next; }; @@ -79,17 +88,6 @@ struct oh323_alias { struct oh323_alias *next; }; -/** call_option struct holds various bits - of information for each call */ -typedef struct call_options { - char *cid_num; - char *cid_name; - int noFastStart; - int noH245Tunneling; - 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 */ @@ -124,9 +122,14 @@ extern on_rtp_cb on_external_rtp_create; typedef void (*start_rtp_cb)(unsigned int, const char *, int, const char *); extern start_rtp_cb on_start_rtp_channel; +/* This is a callback that happens when call progress is + * made, and handles inband progress */ +typedef int (*progress_cb)(unsigned, const char *, int); +extern progress_cb on_progress; + /* 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); extern setup_incoming_cb on_incoming_call; /* This is a callback prototype function, called upon @@ -154,12 +157,22 @@ extern clear_con_cb on_connection_cleared; typedef int (*answer_call_cb)(unsigned, const char *); extern answer_call_cb on_answer_call; +/* This is a callback prototype function, called when + we know which RTP payload type RFC2833 will be + transmitted */ +typedef void (*rfc2833_cb)(unsigned, const char *, int); +extern rfc2833_cb on_set_rfc2833_payload; + /* debug flag */ extern int h323debug; #define H323_DTMF_RFC2833 (1 << 0) #define H323_DTMF_INBAND (1 << 1) +#ifndef BOOL +#define BOOL int +#endif + #ifdef __cplusplus extern "C" { #endif @@ -180,7 +193,9 @@ extern "C" { chan_ringing_cb, con_established_cb, send_digit_cb, - answer_call_cb); + answer_call_cb, + progress_cb, + rfc2833_cb); int h323_set_capability(int, int); int h323_set_alias(struct oh323_alias *); int h323_set_gk(int, char *, char *); @@ -196,8 +211,8 @@ extern "C" { void h323_send_tone(const char *call_token, char tone); /* H323 create and destroy sessions */ - int h323_make_call(char *dest, call_details_t *cd, call_options_t); - int h323_clear_call(const char *); + int h323_make_call(char *dest, call_details_t *cd, call_options_t *); + int h323_clear_call(const char *, int cause); /* H.323 alerting and progress */ int h323_send_alerting(const char *token);