Major fixes: Fixed deadlock issue, added support for inband call progress and correct...
authorJeremy McNamara <jj@nufone.net>
Wed, 15 Dec 2004 23:24:13 +0000 (23:24 +0000)
committerJeremy McNamara <jj@nufone.net>
Wed, 15 Dec 2004 23:24:13 +0000 (23:24 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4466 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_h323.c
channels/h323/ast_h323.cpp
channels/h323/ast_h323.h
channels/h323/chan_h323.h

index 5b92834..a3a22e8 100755 (executable)
@@ -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");
index 6abfff9..616b738 100755 (executable)
@@ -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;
 }
index f9a454b..906acd6 100755 (executable)
@@ -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;
index 0005b42..995b818 100755 (executable)
 
 #include <arpa/inet.h>
 
-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);